Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Thursday, February 17, 2011

Handling WCF Faults in .NET 2.0 client applications

WCF handles errors and convey these details to the client using Fault contracts. SOAP fault messages are included in the metadata for an operation contract and when the exception is raised in these methods create a fault for the clients to get more details about the exceptions. But when you have a client that runs on 2.0 version of .NET framework, they can't make use of these fault contracts. In this case you need to send your faults as SOAP exceptions as in Web services.
For e.g.
public void MyServiceMethod()
{
    try
    {
//Application Logic
    }
    catch (System.Security.SecurityException securityException)
    {
        throw GenerateSoapException("ServiceMethodName", "YourNamespace", securityException.Message, "1000", securityException.Source, ServiceFaultLocation.FromServerCode);
    }
}

private SoapException GenerateSoapException(string uri,
                            string serviceNamespace,
                            string message,
                            string errNum,
                            string source,
                            ServiceFaultLocation faultLocation)
{
    XmlQualifiedName faultCodeLocation = SetFaultCode(faultLocation);

    XmlDocument xmlDoc = new XmlDocument();
    XmlNode rootNode = CreateExceptionNode(serviceNamespace, message, errNum, source, xmlDoc);
    SoapException soapException = new SoapException(message, faultCodeLocation, uri, rootNode);
    return soapException;
}

private XmlNode CreateExceptionNode(string serviceNamespace, string message, string errNum, string source, XmlDocument xmlDoc)
{
    XmlNode rootNode = xmlDoc.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, SoapException.DetailElementName.Namespace);
    XmlNode errorNode = PopulateErrorDetails(serviceNamespace, message, errNum, source, xmlDoc);

    rootNode.AppendChild(errorNode);
    return rootNode;
}

private XmlNode PopulateErrorDetails(string serviceNamespace, string message, string errNum, string source, XmlDocument xmlDoc)
{
    XmlNode errorNode = xmlDoc.CreateNode(XmlNodeType.Element, "Error", serviceNamespace);
    XmlNode errorNumberNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorNumber", serviceNamespace);
    errorNumberNode.InnerText = errNum;
    XmlNode errorMessageNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorMessage", serviceNamespace);
    errorMessageNode.InnerText = message;
    XmlNode errorSourceNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorSource", serviceNamespace);
    errorSourceNode.InnerText = source;
    errorNode.AppendChild(errorNumberNode);
    errorNode.AppendChild(errorMessageNode);
    errorNode.AppendChild(errorSourceNode);
    return errorNode;
}

private XmlQualifiedName SetFaultCode(ServiceFaultLocation code)
{
    XmlQualifiedName faultCodeLocation = null;
    switch (code)
    {
        case ServiceFaultLocation.FromClientCode:
            faultCodeLocation = SoapException.ClientFaultCode;
            break;
        case ServiceFaultLocation.FromServerCode:
            faultCodeLocation = SoapException.ServerFaultCode;
            break;
    }
    return faultCodeLocation;
}

Later in your client you can use this SOAP exception and parse the XML message to get the details of the exception.

Thursday, December 9, 2010

Using the EntityFramework POCO repository implementation in WCF – Part 2

The POCO entities that we used in the WCF implementation in the previous post are detached from the object context when passed to the client application. Before trying to perform operations like Save, insert or delete we need to attach these objects to the context and mention the change on the entity so that the Context.SaveChanges method updates the model accordingly. Let’s see an example on how the Customer object with some orders added and which have some changes are updated in the DB when the update method is called on the repository.
public override void Update(Customer entity)
{
    OrderRepository orderRepository = new OrderRepository(this.Context as IUnitOfWork);
    orderRepository.SaveAll(entity.Orders);
    base.Update(entity);
}

The CustomerRepository’s Update method first updates/ adds orders via the order repository. The order repository has a SaveAll method that iterates through all orders and perform the necessary operations on the order.
public class OrderRepository : BaseRepository<Order>, IOrderRepository
{  

    public void SaveAll(IEnumerable<Order> orders)
    {
        orders.ToList().ForEach(order =>
            {
                if (order.Id == Guid.Empty)
                    Add(order);
                else
                    Update(order);
            });           
    }
}

The BaseRepository also has some changes inorder to attach and add the additional information on the attached entity to do the CRUD.
public abstract class BaseRepository : EF4Recipies.Repository.IRepository where T : BaseEntity
{
   
    public virtual void Add(T entity)
    {
        entity.Id = entity.Id == Guid.Empty ? Guid.NewGuid() : entity.Id;
        entity.CreatedDate = entity.ChangedDate = DateTime.Now;
        ValidateAndAddToObjectSet(entity);
    }

    private void ValidateAndAddToObjectSet(T entity)
    {
        entity.Validate();
        Attach(entity);
        Context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Added);
    }

    public virtual void Remove(T entity)
    {
        Attach(entity);
        Context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Deleted);
        Context.DeleteObject(entity);
    }

    public virtual void Update(T entity)
    {
        Attach(entity);
        Context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
        var entityFromDb = GetById(entity.Id);
        if (entityFromDb != null && StructuralComparisons.StructuralEqualityComparer.Equals(entity.Timestamp, entityFromDb.Timestamp))
        {
            entity.ChangedDate = DateTime.Now;
            entity.Validate();
        }
        else
            throw new InvalidOperationException("Concurrency exception");
    }
}
Test cases:
[TestMethod]
public void UpdateOrders_should_insert_new_orders_created_and_save_the_changes_on_the_existing_ones()
{
    var proxy = new ShoppingCartServiceClient.ShoppingCartServiceClient("WSHttpBinding_IShoppingCartService");
    var customerWithOrders = proxy.GetById(new Guid("1931FEDC-2CCA-437E-A3BD-D5842879530D"));
    if (customerWithOrders != null)
    {
        customerWithOrders.Email = "myNewEmail@mailserver.com";
        customerWithOrders.Orders.Add(
            new Order
            {
                OrderDate = DateTime.Now,
                OrderNumber = string.Format("ORD{0:MMddYYYYHHmmss}", DateTime.Now),
                CustomerId = customerWithOrders.Id,
                Customer = customerWithOrders
            });

        var existingOrder = customerWithOrders.Orders.First(o => o.Id != Guid.Empty);
        existingOrder.OrderNumber = string.Format("ORDCH{0:MMddYYYYHHmmss}", DateTime.Now);
        proxy.UpdateOrders(customerWithOrders);
        var order = proxy.SearchByOrderNumberAndCustomerDetails("ORDCH", customerWithOrders);
        Assert.IsNotNull(order);

    }
    else
        Assert.IsFalse(true, "Failed to load customer with orders");
}

Tuesday, December 7, 2010

Using the EntityFramework POCO repository implementation in WCF – Part 1

Entity Framework 4.0 allows creation and usage of POCO entities for implementing persistence ignorant entity types from an Entity Data Model. We can use a WCF service and expose operation contracts to the clients so that they can perform operations like insert, save, get etc on these entities. In this post I’ll use the sample created in the post implementation of the Repository using EF 4.0 POCO objects and expose them via a WCF service.
We need to make some changes to the object model and context to expose it using WCF. The object model which I have created has multiple references within itself when being serialized. For e.g. the customer can have multiple orders and the order has a reference back to the customer. When the WCF's data contract serializer attempts to serialize this object, it results in a stack overflow exception due to the cyclic relationship between the parent-child relation. .NET 3.5 SP1 includes a IsReference parameter in the DataContract attribute which will automatically retain the cyclic object relationships for the objects. We can use this attribute on the base entity in our sample to mention cyclic references.
[DataContract(IsReference = true)]
public abstract class BaseEntity
{
    [DataMember]
    public Guid Id { get; set; }

    [DataMember]
    public DateTime CreatedDate { get; set; }

    [DataMember]
    public DateTime ChangedDate { get; set; }

    [DataMember]
    public byte[] Timestamp { get; set; }

    public abstract void Validate();
}

Next we need to turn off change tracking proxies created for our entities. These would normally be created because we have marked the entities properties as virtual. These proxies cannot be serialized and if they were generated the navigation properties on the POCO objects will not serialize and your response comes back empty resulting in the “The underlying connection was closed: The connection was closed unexpectedly” exception. For turning off change tracking proxies we need to add the below given code to the BaseRepository constructor
public BaseRepository(IUnitOfWork unitOfwork)
{
    if (unitOfwork == default(ShoppingCartContext)) throw new ArgumentNullException("UnitOfWork cannot be null");
    Context = unitOfwork as ShoppingCartContext;
    Context.ContextOptions.LazyLoadingEnabled = false;
    Context.ContextOptions.ProxyCreationEnabled = false;
}

Since Lazy load is disabled, to include the child entities in the model, we need to explicitly specify the include statements for each objects. For e.g  the CustomerRepository GetAll method is changed to
public override IEnumerable<Customer> All()
{
    return Context.Customers
        .Include("Orders")
        .Include("Orders.OrderProducts")
        .Include("Orders.OrderProducts.Product");
}
This will include the Orders, OrderProducts for the orders and Product for each orderProduct in the Orders for the customer.
Now we can try to use the updated model in our service.
[ServiceContract]
public interface IShoppingCartService
{
    [OperationContract]
    Customer GetById(Guid id);
}

public class ShoppingCartService : IShoppingCartService
{
    public ShoppingCartService()
    {
        unitOfWork = UnitOfWork.Default;
    }

    public Customer GetById(Guid id)
    {
        var customerRepository = new CustomerRepository(unitOfWork);
        return customerRepository.GetById(id);
    }

    IUnitOfWork unitOfWork;
}

Test cases
[TestMethod]
public void GetAllOrdersByCustomer_should_retrive_all_orders_placed_by_a_customer()
{
    var proxy = new ShoppingCartServiceClient.ShoppingCartServiceClient("WSHttpBinding_IShoppingCartService");
    var customer = proxy.GetById(new Guid("1931FEDC-2CCA-437E-A3BD-D5842879530D"));
    Assert.IsNotNull(customer);
}

Next we’ll add new methods to the service to perform more operations on the context to add, remove and update properties on the entities.

Friday, August 14, 2009

WCF - Event-based asynchronous pattern

WCF Guidance for WPF Developers

Asynchronous proxies generated with svcutil support two modes of asynchronous operations: delegate-based opertations and event-based operations. Delegate-based asynchronous operations follow the traditional asynchronous delegate pattern whereby each call is broken into two: a begin operation, and an end operation.

Eg:

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IProjectService/GetProjects", ReplyAction="http://tempuri.org/IProjectService/GetProjectsResponse")]

System.Collections.ObjectModel.ObservableCollectionProject> GetProjects();

[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IProjectService/GetProjects", ReplyAction="http://tempuri.org/IProjectService/GetProjectsResponse")]

System.IAsyncResult BeginGetProjects(System.AsyncCallback callback, object asyncState);

System.Collections.ObjectModel.ObservableCollectionProject> EndGetProjects(System.IAsyncResult result);

The drawback of the delegate-based asynchronous pattern is that every callback must synchronize access to UI components, and to other instance members belonging to the main Window. This requires developers to write synchronization logic which quickly adds to code clutter, and can become hard to follow. The event-based pattern solves this problem by exposing an event that is executed on the UI thread that can be used to notify the client about the completion of the operation. This logic is encapsulated in the proxy. You can use the svcutil tool with the /async /targetClientVersion:Version35 option to generate proxies with Async event support.

This option adds a EventArgs type that inherits from the AsyncCompletedEventArgs type for each asynchronous operations on the service. Later in the code you can use the event based asynchronous pattern to as given in the example below to query the service methods.

__AsyncProxy = new WCFSampleProjects.Proxies.Async.ProjectServiceClient("ProjectServiceAsync");

__AsyncProxy.InnerChannel.Faulted += new EventHandler(AsyncProxyFaulted);

__AsyncProxy.GetProjectsAsync();

__AsyncProxy.GetProjectsCompleted += new EventHandlerGetProjectsCompletedEventArgs>((y, z) =>

{

var __Projects = z.Result;

__Projects.ToList<Project>().ForEach(item => Console.WriteLine(item.Title));

});