Saturday, August 4, 2012

Type Provider Sample to Perform the Design Time Validation

Let us continue from the type provider samples from the previous post.

If you have not noticed the type provider is actually a design-time feature, the sample here is to highlight this feature. The production code requires the XML meet certain criteria. In this sample, the XML's start value <= end value.

There are several ways to prevent this kind of error:

  1. use schema
  2. use test case
  3. or, leave this to run-time crash.. ;-)

In this case, it is not easy to define this requirement in a schema file. The test case can check this kind error in a brute-force way. Even I do not invoke the code, the test case still runs. I want this kind of validation only happens when the method is used. The ideal situation is to let Visual Studio to tell there is something wrong with the  XML file and prevent you from a successful compilation. I want to bring this kind of run-time error to design time. The production code is listed below.

type MyProductionCode() = class
    member this.Work() =
        let xml = XDocument.Load("XmlFile1.xml")
        let start = xml.Descendants(XName.Get("Start")) | > Seq.head
        let end' = xml.Descendants(XName.Get("End")) | > Seq.head
     
        // if start >= end, something bad will happen
        if Convert.ToInt32(start.Value) >= Convert.ToInt32(end'.Value) then
            failwith "report illegal parameter from runtime"
end

The way to get this done is to put code in the InvokeCode property in the ProvidedMethod. The InvokeCode returns an code quotation and this code quotation is something will be executed at run-time, other code which is not embedded in the code quotation will only executed at design time and it is the place where can play the tricks.

let m = ProvidedMethod(
                            methodName = "Work",
                            parameters = [],
                            returnType = typeof,
                            IsStaticMethod = false,
                            InvokeCode = fun args ->
                                test.Test1(xmlFileName)      //executed at design time to validate the XML file                      
                                < @@ (%%args.[0]:MyProductionCode).Work() @@ >                                  
                            )

The Test1 method will check the XML file and throw exception if the XML is invalid. As a result, a red line will be under the function call in the Visual Studio. An interesting thing for the type provider version versus the test case is that the error only happens the method appears in the code. If user does not intend to invoke the code, there will be no error.

If you can combine this sample with the wrapper sample, you can have a more general version. We are working on the new release of our F# sample pack and eventually all type provider samples will be there.

I will be moving to cloud and data analysis stuff from next week where F# shows more muscle. Please stay tuned.. :-)

No comments: