Wednesday, October 10, 2012

Implementing a Rule Based System for First Aid Prescriptions

A rule based system for the calculation of medication to be used in an APLS (Acute Pediatric Life Support) setting follows can be nicely implemented using a functional approach.

F# is a relatively new .net family member is the .net version of a functional programming language. Functional programming languages are particularly suitable to solve data processing and decision support problems. So, I decided to give it a go.

First of all, the problem. As medication in children has to applied to a broad range of age and weight categories, different medication solutions have to be applied. For example, for midazolam we use the following solutions:


Weight Category Solution
< 5.0 kg 50 mg/ 50 mL
5.0 - 15 kg 100 mg/ 50 mL
15 - 23 kg 150 mg/ 50 mL
> 23 kg 200 mg/ 50 mL

In 'normal' C# this would require a lot of if then constructs. In F# the initial solution already looks nicer:

[<Measure>] type kg
[<Measure>] type mg

let selectMidazolamQuantity (weight: float<kg>) :float<mg> =
    match weight with
    | w when w < 0.0<kg> || w > 200.0<kg> -> failwith "Not a valid weight"
    | w when w < 5.0<kg> -> 50.0<mg>
    | w when w >= 5.0<kg> && w < 15.0<kg> -> 100.0<mg>
    | w when w >= 15.0<kg> && w < 23.0<kg> -> 150.0<mg>
    | w when w >= 23.0<kg> -> 200.0<mg>

let qty = selectMidazolamQuantity(23.0<kg>)
qty

In F# instead of if then constructs, pattern matching can be used. The correctness of the pattern is checked at compiler time. So, for example when the pattern is incomplete, this is immediately shown in the editor. Also, primitive values can be decorated with a measure attribute.

When the above code is send to F# interactive this will have the following result:


Script.fsx(40,11): warning FS0025: Incomplete pattern matches on this expression.
val selectMidazolamQuantity : float<kg> -> float<mg>
val qty : float<mg> = 200.0
This code can be further improved by matching against a list of categories:



let milrinoneRules = [| 
    (0.4<kg>, 5.0<kg>, 5.0<mg>); 
    (5.0<kg>, 10.0<kg>, 10.0<mg>);
    (10.0<kg>, 200.0<kg>, 15.0<mg>) 
    |]

let selectQuantity (weight: float<kg>, rules: (float<kg>*float<kg>*float<mg>)[]) : float<mg> =
    match weight with
    | w when w < 0.0<kg> || w > 200.0<kg> -> failwith "Not a valid weight"
    | w ->  
        let rule = Array.find(fun (lower, upper, _) -> w > lower && w <= upper) rules
        let _, _, quantity = rule
        printf "quantity is %s\n" (quantity.ToString())
        quantity

selectQuantity (12.0<kg>, milrinoneRules)

Next step is to annotate the rules set with the medication for wich it is used.

Monday, October 8, 2012

Setting up a SoapClient to use Windows Authentication

Setting up a soap client to use windows authentication is rather tricky as there many configuration options concerning ASP.NET security.

First of all make sure that IIS 7.0 is correctly configured to use Windows authentication instead of default anonymous user login. Therefore, the following has to be applied to the


This effectively forces IIS to use an authenticated windows user. If a user is already windows authenticated, the user does not need to log in. So, this setting is appropriate for use in intranet environments, not in intranet environments.

However, users do not interact with webservices, code interacts with webservices. To consume a web service a service reference has to be added to the project:


Adding a service reference to a project creates an app.config describing the binding of that service including the security settings. Default security settings only enable anonymous user to consume the code. If IIS is configured to use windows security this will result in a HTTP 401 error.

Therefore, the following section has to be modified:


                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
To:

                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>

Note: this section resides in the:

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>

After adjusting the security section the code when run using an authorized windows user should work. But for an application with a web based user interface this is not required! The user will be prompted to log in, if required. So then the code is run with the authenticated user and the webservices can be consumed. I use the above to enable test code to run.