First, Add References:
The first step that we must do is add a reference to System.Xml and System.Xml.Linq in both the test project and the F# project.
The C# Tests:
The goal of these tests is to verify that a specific customer can be retrieved from the XML source. Method "CanGetCustomerById" retrieves the customer from the actual XML source (which in this case is hard coded into the GetById member, but could have easily been retrieved from a file or database). Method "CanGetCustomerByIdWithXmlProvided" creates a fake XElement and passes it to the function for test purposes.
[TestMethod] public void CanGetCustomerById() { FSharpMockExample.Data.ICustomerDao customerDao = new FSharpMockExample.Data.CustomerDao(); FSharpMockExample.Entities.ICustomer customer = customerDao.GetById(1); Assert.AreEqual(customer.Id, 1); Assert.AreEqual(customer.Name, "ABC Company"); Assert.AreEqual(customer.Balance, 20); } [TestMethod] public void CanGetCustomerByIdWithXmlProvided() { XElement xElement = new XElement("c", new XElement("Customer", new XAttribute("Id", "1"), new XAttribute("Name", "ABC Company"), new XAttribute("Balance", "20.00")), new XElement("Customer", new XAttribute("Id", "2"), new XAttribute("Name", "AABB, Inc"), new XAttribute("Balance", "30.00"))); FSharpMockExample.Data.ICustomerDao customerDao = new FSharpMockExample.Data.CustomerDao(); FSharpMockExample.Entities.ICustomer customer = customerDao.GetById(xElement, 2); Assert.AreEqual(customer.Id, 2); Assert.AreEqual(customer.Name, "AABB, Inc"); Assert.AreEqual(customer.Balance, 30); }
The F# Signature File:
The signature file looks very similar to that which was created during the last entry. The main difference is a new overloaded GetById function, which contains a tuple (a tuple is common F# data structure used to group data types) of type "XElement * int". Since XElement is used, we must also open System.Xml.Linq.
#light namespace FSharpMockExample.Data open FSharpMockExample.Entities open System.Xml.Linq type ICustomerDao = interface abstract GetById: int -> ICustomer abstract GetById: XElement * int -> ICustomer end type CustomerDao = class new: unit -> CustomerDao interface ICustomerDao end
The F# Source File:
Most of the changes are found in this file. The first thing that an astute reader might notice is the XLinqHelper module. Modules provide a way to group and reuse identifiers and functions. The CustomerDao class encapsulates the majority of the changes. Member GetById xml retrieves, and in this sample actually creates, the source xml. It then casts the current class to the ICustomerDao interface, parses the raw xml into an XElement and calls the overloaded GetById XElement*int member. The overloaded GetById XElement*int member uses the Seq library to find the customer by the specified CustomerId, news up a customer object, casts it to an ICustomer, and finally returns the result.
#light namespace FSharpMockExample.Data open FSharpMockExample.Entities open System.Xml.Linq module XLinqHelper = let GetXName xname = XName.op_Implicit(xname) type ICustomerDao = interface abstract GetById: int -> ICustomer abstract GetById: XElement * int -> ICustomer end type CustomerDao = class new()={} interface ICustomerDao with member this.GetById id = let rawXml = "<Customers> <Customer Id=\"1\" Name=\"ABC Company\" Balance=\"20.00\"/> <Customer Id=\"2\" Name=\"AABB, Inc\" Balance=\"30.00\"/> </Customers>" let thisInterface = (this :> ICustomerDao) let xml = XElement.Parse rawXml thisInterface.GetById (xml, id) member this.GetById (xml, id) = let GetCustomer (customerElement:XElement) = new Customer(int(customerElement.Attribute(XLinqHelper.GetXName "Id").Value), customerElement.Attribute(XLinqHelper.GetXName "Name").Value, decimal(customerElement.Attribute(XLinqHelper.GetXName "Balance").Value)) :> ICustomer xml.Elements() |> Seq.find(fun customer -> (int(customer.Attribute(XLinqHelper.GetXName "Id").Value) = id)) |> GetCustomer end
Conclusion:
As you can see from the example, adding basic data access functionality using Linq to XML is pretty easy. With the help of the Seq library and System.Xml.Linq, the possibilities of XML data manipulation are endless.
A special thanks goes out to Elijah Manor for adding F# support to Syntax Higherlighter. Very cool Elijah!!
No comments:
Post a Comment