Sunday, 19 January 2014

Mortality Index - WSDL Type Provider

Web Service at SoA Site


I want to include in the Mortality Manager application an ability to import mortality tables from the Society of Actuaries website at http://mort.soa.org/.

For this, an index of these files needs to be created, to provide this as a set of rates that the user can select.

After some investigation, you can identify that a Web Service is hosted on this site. If you use the link http://mort.soa.org/WebService.asmx, you can see that you get access to two commands:




The GetListOfTables command is the one we shall use.

F# WSDL Type Provider


Again F# makes it very easy to use this facility. There is a type provider for WSDL, and this is described on MSDN at http://msdn.microsoft.com/en-us/library/hh362328.aspx.

To get the index information, I use the following function:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
namespace MortMgr

open Microsoft.FSharp.Data.TypeProviders
open System.IO
open System.ServiceModel

module Soa = 
    type SoaWS = WsdlService< "http://mort.soa.org/WebService.asmx?WSDL" >
    
    /// gets list of tables from SoA site
    let getTabList() = 
        let fml = 
            try 
                let soaClient = SoaWS.GetWebServiceSoap()
                let mygets = 
                    [ 1..25 ] |> List.map (fun i -> soaClient.GetListOfTablesAsync(i, 100, "TableIdentity", "asc", "", "-1", "-1", "-1") |> Async.AwaitTask)
                
                let gets = 
                    mygets
                    |> Async.Parallel
                    |> Async.RunSynchronously
                
                let rwsl = 
                    gets
                    |> List.ofArray
                    |> List.map (fun r -> r.Body.GetListOfTablesResult.rows |> List.ofArray)
                
                let rws = rwsl |> List.concat
                rws |> List.map (fun m -> 
                           { ref = m.TableIdentity
                             tabnm = m.TableName
                             usage = m.ContentType
                             nation = m.Nation
                             layout = m.Type })
            with
            | :? ServerTooBusyException as exn -> 
                let innerMessage = 
                    match (exn.InnerException) with
                    | null -> ""
                    | innerExn -> innerExn.Message
                failwith "An exception occurred:\n %s\n %s" exn.Message innerMessage
            | exn -> failwith "An exception occurred: %s" exn.Message
        
        let rec trim iml oml = 
            if iml = [] then List.rev oml
            else 
                let im = iml.Head
                if im.ref = 1 then List.rev oml
                else trim iml.Tail (im :: oml)
        
        trim fml.Tail [ fml.Head ]|>List.toArray

The type is first defined as SoaWS. This gives access to the available commands in a type safe manner.

The function getTabList() first gets the Web Service as soaClient.

mygets  is then created by calling the Asynchronous version of the GetListOfTables command. Parameters are required. The first specifies which page is required. The second specifies the number of entries on each page. The code asks separately for 25 pages with 100 entries on each page. This is turned into an F# Async call.

gets then takes mygets and runs it in parallel to get the returned values.

rwsl then takes gets and extracts the rows in a type-safe manner from the downloaded results.

rws then takes rwsl and concatenates the 25 sets of rows.

Finally these results are converted to a list of F# records as fml.

This will however have some repeated data as the Web Service starts to return mortality tables from the start of its list after it reaches the end of the number it holds. A simple trim function is therefore defined to truncate the set held, when the first identifier (stored as ref) appears for the second time.





No comments:

Post a Comment