Monday, February 20, 2012

Dynamic XPATH in XSLT using C#

Recently I had a task of converting a flat XML to hierarchical XML deserializable to .NET entities. Everything was smooth until I got into a situation where-in I had some elements like shown below


...
<CCY1>GBP</CCY1>
<Value1>1.34</Value1>
<CCY2>EUR</CCY2>


<Value2>1.34</Value2>
...


which needed to be like after conversion as shown below


....
<CCYDetails>
<CCYDetail>
<CCY>GBP</CCY>
<Value>1.34</Value>
....
</CCYDetails>
</CCYDetail>
...
 
After some research in internet, I figured out that it is not straight forward in XSLT. It needs some help of scripting language. Since I am from .NET background, I wasn't able to find much help in this regard. Then I found one code in one of the forum threads and tweaked a bit to get it working.


XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:user="http://tempuri.org/user">
<msxsl:script language="CSharp" implements-prefix="user">
<![CDATA[
public XPathNodeIterator FilterNodes(XPathNodeIterator context,string xpath)
{
context.MoveNext();
return context.Current.Select(xpath);
}
]]>
</msxsl:script>
<xsl:template match="/">
<root>
<CCYDetailss>
<xsl:for-each select="MinPayInAmendment">
<xsl:call-template name="ccy_loop">
</xsl:call-template>
</xsl:for-each>
</CCYDetails>
</root>
</xsl:template>
<xsl:template name="ccy_loop">
<xsl:param name="num">1</xsl:param>
<xsl:if test="not ($num=17)">
<xsl:variable name="ccy" select="concat('CCY',$num)">
</xsl:variable>
<xsl:variable name="new" select="concat('New',$num)">
</xsl:variable>
<CCYDetail>
<CCY>
<xsl:value-of select="user:FilterNodes(.,$ccy)"/>
</CCY>
<New>
<xsl:value-of select="user:FilterNodes(.,$new)"/>
</New>
</CCYDetail>
<xsl:call-template name="ccy_loop">
<xsl:with-param name="num">
<xsl:value-of select="$num+1"></xsl:value-of>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>


C#
XPathDocument xpath = new XPathDocument(@"C:\input_xml.xml");

XPathNavigator navi = xpath.CreateNavigator();
XsltSettings settings = new XsltSettings();
settings.EnableScript = true;
settings.EnableDocumentFunction = true;
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(@"C:\XSLTFile1.xslt",settings,new XmlUrlResolver());
MemoryStream resultStream = new MemoryStream();
XmlWriterSettings writer_settings = new XmlWriterSettings();
writer_settings.Indent = true;
XmlWriter writer = XmlWriter.Create(resultStream,writer_settings);
transform.Transform(xpath, null, writer);
resultStream.Position = 0;
StreamReader stream = new StreamReader(resultStream);
Console.WriteLine(stream.ReadToEnd());
writer.Close();



PDF to XML using iTextsharp

Here is the very simple way of creating the XML from PDF document. I used Form fields in the PDF document. Then using the iTextsharp, I looped through the Acrofields or Form fields and created the flat XML document out of it. You can customize to create more complex structures if need be.

XmlDocument doc = new XmlDocument();
PdfReader reader = new PdfReader(@"C:\Input.pdf");
AcroFields fields = reader.AcroFields;
doc.LoadXml(string.Format("<{0}/>", root));
foreach (string keyName in fields.Fields.Keys)
{
AcroFields.Item item = fields.GetFieldItem(keyName);
XmlElement elt = doc.CreateElement(keyName);
elt.InnerXml = "<![CDATA[" + fields.GetField(keyName) + "]]>"";
doc.DocumentElement.AppendChild(elt);
}

doc.Save(@"C:\output.xml");

Wednesday, February 8, 2012

Generic Error Handling in WCF REST

It is very obvious that we will not have the luxury of throwing the service exceptions when we create web service wrappers to the business processing logic. But it is not end of the world. WCF provides IErrorHandler interface which allows us to handle all the exceptions that are generated from the layers below in generic fashion. For WCF this is OK, but what to do for WCF REST? Don't worry, the same interface can be enhanced to support the error handling functionality for WCF REST services as well. Below is the sample implementation of generic error handling in WCF REST services;

1) Implement the IErrorHandler interface

public class BSErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
//This condition is needed to skip handling the WebFaultException
//since it is already handled in the layers below  (I have used WebFaultException<string>
//In case you use different type, add the condition for that)
if (!(error is System.ServiceModel.Web.WebFaultException))
{
//I have used XML type; so why I am using DataContractSerializer
//If you want to use JSON type, use DataContractJSONSerializer
fault = Message.CreateMessage(version,string.Empty, string.Format("Error: {0}", error.Message), new DataContractSerializer(typeof(string)));
fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Xml));
//Below code sets the response status to OK (200) so that client
//knows this is a valid response and handle it accordingly
HttpResponseMessageProperty hrp = new HttpResponseMessageProperty();
hrp.StatusCode = System.Net.HttpStatusCode.OK;
fault.Properties[HttpResponseMessageProperty.Name] = hrp;
}
}
}

2) Inject this error handler in the Channel Dispatcher as shown below;

public class CustomMessageBehavior : IEndpointBehavior

{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
BSErrorHandler err = new BSErrorHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(err);
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}

3) Configure the dispatcher in the Web.Config

Job done!!

Monday, January 30, 2012

Entity Framework and IBM DB2 Database

Recently I was doing one POC on Entity Framework and IBM DB2 database. Here is how we can make entity framework to consume IBM DB2 database.


IBM DB2 runs mostly on zOS or Linux platform. They do also have express edition which runs on Windows OS. I used the IBM DB2 Express edition which is a free downloadable from IBM site. Also, you will need the IBM DB2 connector VS Add-In to be able to establish connection with DB2 database. Don't worry, here is the link to download both these components


https://www14.software.ibm.com/webapp/iwm/web/download.do?source=swg-db2expressc&S_PKG=dlwin32&S_TACT=100KG25W&lang=en_US&dlmethod=http


Once you install and setup the IBM DB2 Express edtion and  VS Add-In just follow the below steps to establish connectivity from EF to DB2 database.


1) Create a sample project in VS2010
2) Add new ADO.NET Entity Data Model to the project












3) Click Next and select "New Connection"
4) In the connection dialog, click the "Change Datasource" button



















5) In the Data Sources screen, select "IBM DB2 and IDS servers"

















6) Select the "Server", enter "Username", "Password", "Database" and do a Test Connection to database. If DB connection is successful, goto next step.




















7) Select the options shown in the screenshot below and click "Next"



















8) Select the Tables, Views you need in this step as shown in the screenshot



















9) Voila, you should be able to see all the tables, views selected in the previous steps in the Model file














10) Now you should be able to consume the DB normally using EF.

Ok, now that you have done with the implementation; How do we redistribute the App to TEST or PROD server? Answer is yes, it is possible. You will need any one of the below drivers to achieve DB2 connectivity from TEST or PROD servers;

1) IBM Data Server Client: most complete, includes GUI Tools, drivers



2) IBM Data Server Runtime Client: a lightweight client with basic functionality, and includes drivers


3) DB2 Runtime Client Merge Modules for Windows: mainly used to embed a DB2 runtime client as part of a Windows application installation


4) IBM Data Server Driver for JDBC and SQLJ: allows Java applications to connect to DB2 servers without having to install a full client


5) IBM Data Server Driver for ODBC and CLI: allows ODBC and CLI applications to connect to a DB2 server without the large footprint of having to install a client


6) IBM Data Server Driver Package: Includes a Windows-specific driver with support for .NET environments in addition to ODBC, CLI and open source. This driver was previously known as the IBM Data Server Driver for ODBC, CLI and .NET


And of course, there are some limitations with this approach. Please read through the limitations As-Is provided by IBM before going forward with this approach.
 
http://www.ibm.com/developerworks/wikis/display/DB2/IBM%20Data%20Server%20LINQ%20Entity%20Framework%20Limitations

Friday, January 6, 2012

Binding dynamic XML objects to Silverlight Grids

Recently we had an requirement to bind the content of dynamic XML to Silverlight Grids.This is straightforward in ASP.NET with the help of DataSet. But we do not have DataSet in Silverlight or WPF. To achieve this we used the following approach;


The code is self-explanatory with the comments explaining each step;


public string Result
{
get
{
return _result;
}
set
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Load the xml string to XDocument
XDocument doc = XDocument.Load(new StringReader(value));
MemoryStream str = new System.IO.MemoryStream();
doc.Save(str);


//Finding the Name of the class
string objName = doc.Descendants().First().Name.LocalName.Replace("ArrayOf", "");


//Making it a fully qualified name by appending the corresponding
//namespace
objName = "MyCompany.MyApplication." + objName;


//Loading the assembly that contains the Entity which
//we are trying to de-serialize
//NOTE: To be able to do the below 3 steps, you need to ensure that
//the entities dll reference is added in Deployment.Parts of the
//App Manifest file
StreamResourceInfo sri = Application.GetResourceStream(new Uri("MyApplication.SL.Entities.dll",UriKind.Relative));
AssemblyPart myPart = new AssemblyPart();
System.Reflection.Assembly assm = myPart.Load(sri.Stream);


//Using reflection to build the List<T>
var pageToShowType = assm.GetType(objName);
Type t = typeof(List<>);
Type [] args = {pageToShowType};
Type r = t.MakeGenericType(args);


//De-serializing and assigning to the property to show in the grid
str.Position = 0;
DataContractSerializer serializer = new DataContractSerializer(r);
//Bind the ResultObject to the SL Grid
//NOTE: Ensure that SL Grid has AutoGenerateColumns = TRUE
ResultObject = serializer.ReadObject(str);
str.Close();


});


}


}