Software Architecture – Design Problem Part 2 – DTO- MS Visual Studio 2010 – Net 4-0 – WCF – NHibernate – Silverlight

July 31, 2010

This is second post with reference to Design Architecture discussion on Project based on NHibernate + WCF+Sliverlight.
See the first Post last post here.

In my last post I had identified that we need DTO Objects.
DTO-Data Transfer Objects are customized object that can have different object structure then Objects used in OR Mapping/Nhibernate. When a request for object comes from client (Silverlight project) to server (ASP .Net project) having Service via WCF wire, at Server side, query is run on OR Mapping Object, utiizing full benefits of Lazy loading, business rules are applied, and finally data is ready to be send to client. At this point data is not in customized according to client needs and filtering of properties for objects is required to reduce the size of data being transferred. That where DTO objects comes in action.

Benefits of DTO objects:

1. It is always better from software design perspective to not expose object of data layer direct to client end that is silverlight via WCF.

2. Most important benefit is: filtering of object properties or Change in structure of objects that needs to be transferred across WCF wire. Let suppose you have invoice creation form having fields to be filled as like client, consignee, agent, shipper, sales person, operation manager and many other. So when loading invoice form data from all these entities like agents ……. will travel on WCF wire. Each entity may have a lot of properties, but on client side we only need id and name of all these entities. So we can make various versions of entities according to need for architecture.

3. With DTO approach, UI (silverlight) is only dependent on DTO objects, so the data layer can be changed to any tech like linq2sql,linq2entities or any other thing. Change in Data layer is very flexible with DTO.

Elements of Design Example:
You can download sample here.
Rename the file as sample.zip and then extract.

Solution Explorer will look like as:



This Example will fetch 2 different DTO objects with sample look and feel as below.


There is one entity class for nhibernate named as “Customer” with HBM set in Mapping.hbm.xml.

There are 2 DTO Classes. First DTO with properties as ClientID,ClientCode, Name.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace WCFNHibernateSilverLightSample.Web.DTOEntities
{
    [DataContract(IsReference = true)] 
    public class DTOCustomer
    {
        #region Fields
        private int _ClientID;
        private string _ClientCode;
        private string _Name;
        #endregion
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the GeneralClientMaster class 
        /// </summary> 
        public DTOCustomer()
        {
        }     
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the ClientID for the current GeneralClientMaster
        /// </summary>
        [DataMember]
        public virtual int ClientID
        {
            get { return _ClientID; }
            set { _ClientID = value; }
        }

        /// <summary>
        /// Gets or sets the ClientCode for the current GeneralClientMaster
        /// </summary>
        [DataMember]
        public virtual string ClientCode
        {
            get { return _ClientCode; }
            set { _ClientCode = value; }
        }
        [DataMember]
        public virtual string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        #endregion

    }

    
}

Second DTO class has extra parameter of Address as:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace WCFNHibernateSilverLightSample.Web.DTOEntities
{
    [DataContract(IsReference = true)]
    public class DTOCustomerVersionWithAddress
    {
        #region Fields
        private int _ClientID;
        private string _ClientCode;
        private string _Name;
        private string _Address;
        #endregion
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the GeneralClientMaster class 
        /// </summary> 
        public DTOCustomerVersionWithAddress()
        {
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the ClientID for the current GeneralClientMaster
        /// </summary>
        [DataMember]
        public virtual int ClientID
        {
            get { return _ClientID; }
            set { _ClientID = value; }
        }

        /// <summary>
        /// Gets or sets the ClientCode for the current GeneralClientMaster
        /// </summary>
        [DataMember]
        public virtual string ClientCode
        {
            get { return _ClientCode; }
            set { _ClientCode = value; }
        }
        [DataMember]
        public virtual string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }
        [DataMember]
        public virtual string Address
        {
            get { return _Address; }
            set { _Address = value; }
        }

        #endregion

    }
 
}

A converter class will be required as below to transform “customer” to “DTOCustomer” and “DTOCustomerVersionWithAddress”.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WCFNHibernateSilverLightSample.Web.DTOEntities.DTOConvertor
{
    public class DTOConvertor
    {
        #region CustomerConvertor

        public static DTOCustomer ConvertFromCustomerToDTOCustomer(Customer cust)
        {
            DTOCustomer dtocus = new DTOCustomer();
            dtocus.ClientID =  cust.ClientID;
            dtocus.ClientCode =  cust.ClientCode;
            dtocus.Name =  cust.Name;            
            return dtocus;            
        }
        public static DTOCustomerVersionWithAddress ConvertFromCustomerToDTOCustomerVersionWithAddress(Customer cust)
        {
            DTOCustomerVersionWithAddress dtocus = new DTOCustomerVersionWithAddress();
            dtocus.ClientID = cust.ClientID;
            dtocus.ClientCode = cust.ClientCode;
            dtocus.Name = cust.Name;
            // Note here Transformation of properties from Nhibernate Object to DTO Objects
            // It is really a simple example. Very advance level tranformation can be done.
            dtocus.Address = cust.PostalAddress + " Tel: " + cust.Phone1 + " Fax: " + cust.Fax1 + " Email : " + cust.Email;
            return dtocus;
        }
        #endregion CustomerConvertor
    }
}

The WCF Service code will look like as

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Channels;
using NHibernate;
using WCFNHibernateSilverLightSample.Web.DTOEntities;
using WCFNHibernateSilverLightSample.Web.DTOEntities.DTOConvertor;

namespace WCFNHibernateSilverLightSample.Web
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "GetDataService" in code, svc and config file together.
    public class GetDataService : IGetDataService
    {
        public IList<DTOCustomer> GetCustomer()
        {
            IList<Customer> list;
            IList<DTOCustomer> listDTO =  new List<DTOCustomer>();
            NHibernate.ISession session = NHibernateHelper.OpenSession();
            ICriteria query = session.CreateCriteria(typeof(Customer));
            list = query.List<Customer>();

            foreach(Customer c in list)
            {
                listDTO.Add(DTOConvertor.ConvertFromCustomerToDTOCustomer(c));
            }
            return listDTO;
        }
        public IList<DTOCustomerVersionWithAddress> GetCustomerWithAddress()
        {
            IList<Customer> list;
            IList<DTOCustomerVersionWithAddress> listDTO = new List<DTOCustomerVersionWithAddress>();
            NHibernate.ISession session = NHibernateHelper.OpenSession();
            ICriteria query = session.CreateCriteria(typeof(Customer));
            list = query.List<Customer>();

            foreach (Customer c in list)
            {
                listDTO.Add(DTOConvertor.ConvertFromCustomerToDTOCustomerVersionWithAddress(c));
            }
            return listDTO;
        }
    }
}

You can download sample here.
Rename the file as sample.zip and then extract.

Advertisements

Software Architecture – Design Problem – MS Visual Studio 2010 + .Net 4.0 + WCF + NHibernate + Silverlight

July 28, 2010

Environment: MS Visual Studio 2010 + .Net 4.0 + WCF + NHibernate + Silverlight

This post assumes that you have initial knowledge of WCF, NHibernate, Silverlight.

See the sample code for this solution working here.
Rename file as up.zip for extracting.

Sample Project:

Entities Relation / Tables relation is like:

Region >> Country >> City >> Area

So each region has many countries, Each country has many cities. Each City has many regions.
A typical Silverlight solution is created with 2 projects (One for silverlight(Client side project), other for ASP .Net Web project (server side ) having a WCF Service for data transfer from server side to client side.

Problem Definition:

Lets suppose you want to get list of City with lazy=”false” and fetch=”join”
for all entities So we will get following queries in SQL Profiler:

SELECT this_.CityID as CityID3_2_, this_.CountryID as CountryID3_2_, this_.CityCode as CityCode3_2_, this_.Description as Descript4_3_2_, this_.Active as Active3_2_, country2_.CountryID as CountryID1_0_, country2_.CountryCode as CountryC2_1_0_, country2_.Description as Descript3_1_0_, country2_.Active as Active1_0_, country2_.RegionId as RegionId1_0_, regions3_.RegionID as RegionID0_1_, regions3_.RegionCode as RegionCode0_1_, regions3_.Description as Descript3_0_1_, regions3_.Active as Active0_1_ FROM GeneralCityMaster this_ left outer join GeneralCountryMaster country2_ on this_.CountryID=country2_.CountryID left outer join GeneralRegionMaster regions3_ on country2_.RegionId=regions3_.RegionID

Again get list of City with lazy=”false” and fetch=”select”
for all entities So we will get following queries in SQL Profiler:

SELECT this_.CityID as CityID3_0_, this_.CountryID as CountryID3_0_, this_.CityCode as CityCode3_0_, this_.Description as Descript4_3_0_, this_.Active as Active3_0_ FROM GeneralCityMaster this_

For each country in list, there will be an select from country table as:

exec sp_executesql N'SELECT country0_.CountryID as CountryID1_0_, country0_.CountryCode as CountryC2_1_0_, country0_.Description as Descript3_1_0_, country0_.Active as Active1_0_, country0_.RegionId as RegionId1_0_ FROM GeneralCountryMaster country0_ WHERE country0_.CountryID=@p0',N'@p0 int',@p0=1

For each region in list, there will be an select from region table as:

exec sp_executesql N'SELECT regions0_.RegionID as RegionID0_0_, regions0_.RegionCode as RegionCode0_0_, regions0_.Description as Descript3_0_0_, regions0_.Active as Active0_0_ FROM GeneralRegionMaster regions0_ WHERE regions0_.RegionID=@p0',N'@p0 int',@p0=21

Two Problems:
There are 2 problems with above implementation.

Lazy load is false, so on server side that is ASP .Net / WCF Project, if we need some processing to be done, it is loading all data, no lazy initialization helps us.

Secondly, in both above cases data is joined from all the corresponding tables even if it is not required. Suppose we want to get data of cities only but unfortunately data of country and region is also fetched and transfer of such a heavy data across the WCF wire is very heavy activity.

If you will change lazy=”true” for entities, then WCF will pass following error.

{System.Net.WebException: The remote server returned an error: NotFound.
   at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
   at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
   at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)}

In order to see the real problem, configure WCF Log as explained
as explained at here

On looking into



Exeption will look like as:

There was an error while trying to serialize parameter http://tempuri.org/:GetCitiesResult. The InnerException message was 'Type 'CountryProxy' with data contract name 'CountryProxy:http://schemas.datacontract.org/2004/07/' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Stack trace will look like as:

System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriterMessage.OnBodyToString(XmlDictionaryWriter writer)
System.ServiceModel.Channels.Message.ToString(XmlDictionaryWriter writer)
System.ServiceModel.Diagnostics.MessageLogTraceRecord.WriteTo(XmlWriter writer)
System.ServiceModel.Diagnostics.MessageLogger.LogInternal(MessageLogTraceRecord record)
System.ServiceModel.Diagnostics.MessageLogger.LogMessageImpl(Message&amp; message, XmlReader reader, MessageLoggingSource source)
System.ServiceModel.Diagnostics.MessageLogger.LogMessage(Message&amp; message, XmlReader reader, MessageLoggingSource source)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.SerializeOutputs(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)
System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

This exception reflects that when WCF serializer tries to load countries, it fails because of lazy loading being true as country will be a proxy object, so it will pass the exception.

Solution:
After reviewing the suggestions provided by Sowmy Srinivasan’s Blog at:
http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx

and discussion on Johan Danforth’s Blog at:
http://weblogs.asp.net/jdanforth/archive/2008/12/22/nhibernate-and-wcf-is-not-a-perfect-match.aspx

I have introduced 3 new classes as:

1. HibernateDataContractSurrogate which implements IDataContractSurrogate which replaces proxy object with forcefully created object by the DataContractSerializer of WCF during serialization.

MSDN Reference:
http://msdn.microsoft.com/en-us/library/ms574969.aspx

2. ReferencePreservingDataContractSerializerOperationBehavior
Which is derived from DataContractSerializerOperationBehavior will extend the functionality provided by DataContract behavior.

3. ReferencePreservingDataContractFormatAttribute which provide attribute that will apply the behavior created above with name
ReferencePreservingDataContractSerializerOperationBehavior

So in short we have modified the behavior of data contract by using IDataContractSurrogate to replace proxy object with forcefully created object.

After this above change of introducing 3 classes, old exception of countryproxy will disappear, but a new exception will be there as below.

There was an error while trying to serialize parameter http://tempuri.org/:GetCitiesResult. The InnerException message was 'Type 'WCFNHibernateSilverLightSample.Web.City' with data contract name 'City:http://schemas.datacontract.org/2004/07/WCFNHibernateSilverLightSample.Web' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Trace as:

System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriterMessage.OnBodyToString(XmlDictionaryWriter writer)
System.ServiceModel.Channels.Message.ToString(XmlDictionaryWriter writer)
System.ServiceModel.Diagnostics.MessageLogTraceRecord.WriteTo(XmlWriter writer)
System.ServiceModel.Diagnostics.MessageLogger.LogInternal(MessageLogTraceRecord record)
System.ServiceModel.Diagnostics.MessageLogger.LogMessageImpl(Message&amp; message, XmlReader reader, MessageLoggingSource source)
System.ServiceModel.Diagnostics.MessageLogger.LogMessage(Message&amp; message, XmlReader reader, MessageLoggingSource source)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.SerializeOutputs(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)
System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

Solution for the above exception is provided at:
http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceknowntypeattribute.aspx

Introduce ServiceKnownType attribute in service contract with a helper class,
So the Service will look like as:

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IGetDataService" in both code and config file together.
    [ServiceContract]
    [ServiceKnownType("GetKnownTypes", typeof(Helper))]
    public interface IGetDataService
    {

        [OperationContract]        
        [ReferencePreservingDataContractFormat]
        IList<City> GetCities();
    }



// This class has the method named GetKnownTypes that returns a generic IEnumerable.
    static class Helper
    {
        public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
        {
            System.Collections.Generic.List<System.Type> knownTypes =
                new System.Collections.Generic.List<System.Type>();
            // Add any types to include here.
            knownTypes.Add(typeof(City));
            knownTypes.Add(typeof(Country));
            knownTypes.Add(typeof(Regions));
            knownTypes.Add(typeof(AreaMaster));
            
            return knownTypes;
        }
    }

So now the first problem has been solved. So now in business classes we can use objects with lazy loading working, only required object will be initialized. We have lazy loading true in OR Mapping, so on Server side “WCFNHibernateSilverLightSample.Web” project will access the object model with fully operational benefits of lazy loading.

See the sample code for this solution working here.

But second problem still exists. To solve the second problem, DTO (Data Transfer Objects) are used. DTO object are simple entity objects have the only those properties that needs to be transferred via WCF wire, So OR Mapping Nhibernate object will be different from DTO objects. Once the data is fetched in OR Mapping Nhibernate object, a transformation is done to DTO object and light weight DTO objects are passed with WCF to client end silverlight project.

I will do one more post to demonstrate this second problem in next post.

Both problems must be solved in a Good designed WCF/Sliverlight/Nhibernate project.

Happy Coding.


Software Architecture – Debugging in Silverlight+WCF

June 30, 2010

Story of Debugging in Silverlight+WCF

Environment: Silverlight + WCF + NHibernate

Normally, you will get error as:

“silverlight [Async_ExceptionOccurred]\Arguments: \Debugging resource strings are unavailable.”

So solution is to install Silverlight Developer Runtime, which is different from normal silverlight run time. Basically Silverlight Developer Runtime provides better debugging/resources information, so highly suggested for Silverlight debugging.

So now the most common error thrown by WCF will be as:
“the remote server returned an error notfound”

Actually, it is general statement that something has gone wrong in WCF.
Possible reasons are be any of the following:
• Connection string is wrong for DB Connection.
• Any configuration file like Configuration.cfg.xml (Used for NHibernate) is missing.
• Any dependency file like LinFu.DynamicProxy.dll ( Used for NHibernate) is missing.
• Entities have circular references.
• Any other thing.

So it is very hard to figure out actual reason.

Beside Fiddler2, solution is to configure Service log for WCF Service.
Make sure to have following piece of tags in web.config of Sliverlight Web project.

<system.serviceModel>
	<diagnostics>  
		<messageLogging   
  		logEntireMessage="true"   
             logMalformedMessages="false"  
             logMessagesAtServiceLevel="true"   
             logMessagesAtTransportLevel="false"  
             maxMessagesToLog="3000"  
            maxSizeOfMessageToLog="2000"/>  
      </diagnostics> 
      <bindings>
        <basicHttpBinding>
          <binding name="Binding1"            
          maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
        </basicHttpBinding>
      </bindings>
      <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                  <dataContractSerializer maxItemsInObjectGraph="500000" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
    </system.serviceModel>


    <system.diagnostics>       
	     <sharedListeners>   
          <add name="WcfListener"   
                  type="System.Diagnostics.XmlWriterTraceListener"   
                  initializeData="d:\logs\wcfLog.svclog"  />   
      </sharedListeners>       
      <sources>         
       <!-- switchValue attribute has no impact on MessageLogging -->   
      <source name="System.ServiceModel.MessageLogging">  
            <listeners>  
              <add name="WcfListener" />  
            </listeners>  
         </source>        
        <source name="System.ServiceModel"  
                        switchValue="Warning, ActivityTracing"  
                      propagateActivity="true" >  
          <listeners>  
           <add name="WcfListener" />  
         </listeners>  
        </source>        
       </sources>      
   </system.diagnostics>  

This configuration will create a log at d:\logs\wcfLog.svclog. It is a very messy log file, so WCF/SVC log viewer is required to read and analyzed the log data.
Install the WCF/SVC log viewer using web installation of Windows SDK
from following location. As size of SDK is very big(In GBs), so you can install selected features.

http://www.microsoft.com/downloads/details.aspx?FamilyId=0BAF2B35-C656-4969-ACE8-E4C0C0716ADB&displaylang=en

The Service Trace Viewer supports three file types:
• WCF Tracing File (.svcLog)
• Event Tracing File (.etl)
• Crimson Tracing File
Service Trace Viewer enables you to open any supported trace file, add and integrate additional trace files, or open and merge a group of trace files simultaneously.

The Service Trace Viewer provides the following different views. They are displayed as tabs on the left pane of the Viewer, and can also be accessed from the View menu.
• Activity View
• Project View
• Message View
• Graph View


Trace for exception will look like as:


On Clicking the red colored exception, details will be displayed in the below panel as:


Graph view of trace will look like as:

Reference:
http://msdn.microsoft.com/en-us/library/ms732023.aspx


Software Architecture – Tips for Development Model with Microsoft Visual Studio 2010+ .Net Framework 4.0 + Sliverlight 4.0

June 27, 2010

Environment:
Microsoft Visual Studio 2010+ .Net Framework 4.0 + Sliverlight 4.0
WCF + Nhibernate + Sliverlight

Assumption: This document assumes that you have initial understanding of WCF and NHibernate.

Tips:
1. Entities will be shared b/w NHibernate and WCF, so sample entity will look like as:

[DataContract]    
    public class City
    {
        public City() { }

        [DataMember]
        public virtual int CityID { get; set; }

        [DataMember]
        public virtual string CityCode { get; set; }

        [DataMember]
        public virtual string Description { get; set; }
             
    }

Corresponding HBM will look like as:

<class name="SilerverlightTest.Web.City, SilerverlightTest.Web" table="GeneralCityMaster" lazy="false" >
      <id name="CityID" column="CityID">
        <generator class="native" />
      </id>
      <property name="CityCode" column="CityCode" />
      <property name="Description" column="Description" />
       </class>

2. Incase there are circular references between the entities of Data contract, all entities must be marked as IsReference = true. See below:

 [DataContract(IsReference = true)] 
public class CurrencyRate : ParentClass<CurrencyRate>
{
 }

Search goolge with keywords “WCF + NHibernate + circular reference” for more details and see top 5 links for theory related to it.

3. As lazy loading can’t work across the WCF wire, so all entities must be marked as lazy=”false” in HBM file. See Below.

<class name="Pegasus.BusinessObjects.General.Main.Company, PCMS-SL.Web" table="GeneralCompanyMaster" lazy="false" >

4. Incase of ManyToOne relationship in class of HBM files, make sure to add option not-found=”ignore” so that if relation is missing then exception is not thrown.

<many-to-one name="ModifiedBy" column="ModifiedBy" class="Pegasus.BusinessObjects.General.Administration.Employees, PCMS-SL.Web" cascade="none"   lazy="false" not-found="ignore"/>

5. In all *.svc.cs, services must be marked as [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
See Blow:

 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AccountsManager : IAccountsManager
    {
}

6. For many issues, WCF Service will show following error as:
{System.TimeoutException: The HTTP request to ‘http://localhost/PCMS-SL.Web/businessmanagers/MastersManager.svc&#8217; has exceeded the allotted timeout. The time allotted to this operation may have been a portion of a longer timeout. —> System.Net.WebException —> System.Net.WebException
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.c__DisplayClass5.b__4(Object sendState)
at System.Net.Browser.AsyncHelper.c__DisplayClass2.b__0(Object sendState)

That is general error, possible error can be anything that is specified above.So try to investigate the root cause of this error.

7. In order to see the exception generated in WCF Service enble error in web.config of ASP Project as:

<behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>

8. Copy ClientAcessPolicy.xml at the root of ASP .net Project, with content as:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from>
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Otherwise following error will occur:

An error occurred while trying to make a request to URI “http://localhost:1498/SecurityManager.svc&#8221;. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.

Search google with this exception and see top 5 urls for theory related to it.

9. NHibernate will list for IList for collection definition. But WCF Look for List so a trick is to use properties as :

<bag name="InstrumentList" cascade="all" inverse="true" lazy="false">
        <key column="Cityid" />
        <one-to-many class="SilerverlightTest.Web.Instrument, SilerverlightTest.Web"  />
      </bag>

Code for collection will be as:

public virtual IList<Instrument> InstrumentList {get;set;}

        [DataMember(Name = "InstrumentList")]
        public  List<Instrument> InstrumentListPrivate
        {
            get { return  new List<Instrument>(this.InstrumentList) ; }
            set { this.InstrumentList = value; }
        }  

For reference see the link below:
http://stackoverflow.com/questions/1538811/nhibernate-and-wcf-ilist-conflict

10. Exception as:
{System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. —> System.Net.WebException: The remote server returned an error: NotFound. —> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.c__DisplayClass5.b__4(Object sendState)
at System.Net.Browser.AsyncHelper.c__DisplayClass2.b__0(Object sendState)
— End of inner exception stack trace —
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)

That is general error, possible error can be anything that is specified above. So try to investigate the root cause of this error.


Software Architecture – To study the tips-tricks-Guidelines related to performance tuning for NHibernate based application

April 1, 2010

1 Objective:

To study the tips/tricks/Guidelines related to performance tuning for NHibernate based application.

2 Problem definition:

Any fool can start a software to build, but to make it live on client’s production environment as a living legend is not easy task, it requires high end skills in Software Architecture. Performance is always a major concerns, which contribute to failures of software projects.

OR Mapping is generally slower then direct ADO .Net connection. That is true for both nHibernate and LINQ2SQL. Applications which have a lot of data centric operations are not suited for NHibernate in general for OR Mapping. However application which have application centric operations or calculation going on are best suited for NHibernate or OR Mapping.

So if you are making a Enterprise CRM Product, then NHibernate(OR mapping) is not a good choice because of inherited performance issues. ( Because of heavy data centric operations)

If you are making a multi player online game or simulator, then NHibernate is a good choice because a few data operations are required and more processing is required at application logic.

So think twice before starting a project and make good choice at the start of application and rest in peace rest of your life….:)

Bad Architecture decisions cause trouble for whole development team and project.

3 Performance Tuning tips for NHibernate:

After some googleing and reading online documentation, I have finalized, following list of 21 points regarding performance tuning for a NHibernate application.

3.1 NHibernate’s SessionFactory is an expensive operation so a good strategy is to creates a Singleton which ensures that there is only ONE instance of SessionFactory in memory:

public class NHibernateSessionManager 
    { 
        private readonly ISessionFactory _sessionFactory; 

        public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager(); 

        private NHibernateSessionManager() 
        { 
            if (_sessionFactory == null) 
            { 
                System.Diagnostics.Debug.WriteLine("Factory was null - creating one"); 
                _sessionFactory = (new Configuration().Configure().BuildSessionFactory()); 
            } 
        } 

        public ISession GetSession() 
        { 
            return _sessionFactory.OpenSession(); 
        } 

        public void Initialize() 
        { 
            ISession disposeMe = Instance.GetSession(); 
        } 
    } 

Then in your Global.Asax Application_Startup, you can initialize it:

protected void Application_Start() 
{ 
    NHibernateSessionManager.Instance.Initialize(); 
} 

3.2 Fetching strategy is key to performance tuning in Nhibernate project. A fetching strategy is the strategy NHibernate will use for retrieving associated objects if the application needs to navigate the association.

Two things are important: when is the association fetched, and how is it fetched (what SQL is used).

Clearly understand and use following:

Join fetching

Select fetching
Subselect fetching

“Extra-lazy” collection fetching

Batch fetching

Also follow:

Immediate fetching

Lazy collection fetching

Proxy fetching

Best tip is to analyze the trade off b/w eager loading vs lazy loading. It varies case of case for implementation.

3.3 Make read-only classes immutable.

3.4 Multi query is executed by concatenating the queries and sending the query to the database as a single string. This means that the database should support returning several result sets in a single query. At the moment this functionality is only enabled for Microsoft SQL Server and SQLite.

IMultiQuery multiQuery = s.CreateMultiQuery()

    .Add(s.CreateQuery("from Item i where i.Id &gt; ?")

            .SetInt32(0, 50).SetFirstResult(10))

    .Add(s.CreateQuery("select count(*) from Item i where i.Id &gt; ?")

            .SetInt32(0, 50));

IList results = multiQuery.List();

IList items = (IList)results[0];

long count = (long)((IList)results[1])[0];

3.5 Multi Criteria like Multi query allows to perform several criteria queries in a single round trip.

IMultiCriteria multiCrit = s.CreateMultiCriteria()

    .Add(s.CreateCriteria(typeof(Item))

            .Add(Expression.Gt("Id", 50))

            .SetFirstResult(10))

    .Add(s.CreateCriteria(typeof(Item))

            .Add(Expression.Gt("Id", 50))

            .SetProject(Projections.RowCount()));

IList results = multiCrit.List();

IList items = (IList)results[0];

long count = (long)((IList)results[1])[0];

3.6 NHibernate 1.2 supports batching SQL update commands (INSERT, UPDATE, DELETE) for SQL Server and .NET Framework 2.0 or above.Update batching is enabled by setting hibernate.adonet.batch_size to a non-zero value.

3.7 Most Important tip is to avoid looping b/w object collections , when conditional data fetching / manipulation is required. Looping b/w collection of large size can really hurt the performance. Use HQL to transform your conditions to Criterias that can really save you processing time.

Lets take example of getting Voucher entities having voucher details collection with some conditions. So don’t traverse the collection of vouchers and voucher details, use HQL to fetch the required entities.

System.Collections.IList list = null;

NHibernate.ICriteria crit = Common.Common.Instance.GetSession.CreateCriteria(typeof(VoucherDetail), "VoucherDetail");

crit.CreateCriteria("VoucherHead" ,"VH");

crit.Add(NHibernate.Criterion.Expression.Eq("Account", objacc));

crit.Add(NHibernate.Criterion.Expression.Eq("VH.SupInvNo", InvNo));

crit.Add(NHibernate.Criterion.Expression.Eq("SrNo", Convert.ToInt16(0)));            crit.Add(NHibernate.Criterion.Expression.Not(NHibernate.Criterion.Expression.Eq("VH.VoucherID", ID)));

            crit.SetFetchMode("VoucherDetail", NHibernate.FetchMode.Eager);

            crit.SetFetchMode("VoucherHead", NHibernate.FetchMode.Eager);

            setFinancialYearCriteria(crit, typeof(VoucherDetail));

            list = crit.List();

3.8 Use SQL Profiler and NH Profiler to view the queries generated by OR Mapping.

3.9 Use query plan to analyze the queries sent by nhibernate.

3.10 Create good indexes on tables to get better results.

3.11 Use “Database Engine Tuning Advisor” to get feedback from SQL Server regarding optimization.

3.12 Best practices for DB normalization can really help to solve the slow down of application. Bad DB design really kills NHibernate speed.

3.13 Using value type objects for your properties and components as opposed to reference types, when you have a choice, this will lower memory footprint.

3.14 Consider your logging strategy for production (less verbose) and usually disable show_sql in production.

3.15 When expensive data queries are envolved or there are limitations of OR Mapping coming up, it is better to use native SQL queries in NHibernate. That increases the performance of application.

3.16 In case of extreme database centric operations, store procedures can also speed up the performance.

string sql = "exec GetJobExpenseAccounts ";

   NHibernate.ISQLQuery qry= Common.Common.Instance.GetSession.CreateSQLQuery(sql);

3.17 Avoid composite keys (exception legacy databases). Composite keys are problematic for database design as well as OR/M therefore avoid them. reference

3.18 Remove any columns and properties that you will never or should never need or use.

3.19 Have a good strategy for flushing and transaction management. Remember that if you commit a transaction that you do not need to flush the object. reference

3.20 Enable 2nd level cache and have a strategy for using it for some of your classes. For details view manual here.

3.21 Read Collection optimization tips in NHibernate documentation. For details view manual here.

References:

http://scottwhite.blogspot.com/2009/04/nhibernate-performance-tuning.html

http://www.codeproject.com/KB/database/NHibernate_Perf.aspx

http://www.codeproject.com/KB/database/NHibernate_Perf2.aspx

http://www.iamnotmyself.com/2008/07/02/NHibernateTestingThePerformanceUrbanLegend.aspx

http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx

http://www.objectreference.net/post/NHibernate-and-Execution-Plans.aspx

http://devlicio.us/blogs/billy_mccafferty/archive/2007/03/03/nhibernate-performance-tuning.aspx


White Paper On ConCurrency For PCMS Application Architecture

March 1, 2010

Dated: 19th July 2009
Version: 1.0
By:Shahzad Sarwar
To: Related Project Managers/Consultants
Development Team

What is Concurrency/Locking?

Locking is a method used to protect records that will be accessed by multiple users so that concurrency errors do not occur (when multiple users change records near simultaneously resulting in inconsistencies).
“Locking” refers to preventing access in some way to the file in order to protect it while a user is making an update.

Types of Concurrency
There are 2 types of locking / Concurrency
• Pessimistic Concurrency
• Optimistic Concurrency
Difference between Pessimistic Concurrency and Optimistic Concurrency
In Pessimistic concurrency the server acquires locks to block access to data that another process is using. Pessimistic concurrency avoids conflicts by acquiring locks on data that is being read, so no other process can modify that data, it also acquires locks on data being modified so no other processes can access that data for either reading or modifying. Readers block writers and writers block readers.

In Optimistic Concurrency the server uses row versioning to allow data readers to see the state of the data before the modifications occur. Older versions of data rows are saved so a process reading data can see the data as it was when the process started reading and not be affected by any changes being made to that data. A process that modifies data is unaffected by processes reading the data because the readier is accessing a saved version of the data rows, readers do not block writers and writers do not block readers.


nHibernate A detailed overview

December 11, 2009


Presentation Agenda on nhibernate

By: Shahzad Sarwar
To: Development Team

Part 1: 1st Aug 2009 3:30 PM
What is OR Mapping. 3
What is nHibernate? 3
XML Configuration File 3
Persistent vs transient Objects 4
Nhibernate Basic 4
Code generation 5
1. Avva Open source Solution 5
2. NConstruct Lite 14
CRUDE Operation Sample 20
Nhibernate Analyiser: 20
1. SQL Server Analyiser 20
2. nhIbernate Analyiser 23

Part 2: Later
• Version 2.1 new features
• Performance tuning
• Proxing
• Cache
• Design pattern for NHibernate
• Case Specific provider

Attachment Below
Agenda-For-OR Mapping-Presentation