Thursday, July 18, 2013

WCF Unleash-4

What is WCF RIA service?

WCF RIA service is a framework to develop n-tier application for Rich Internet Application (RIA). It is mainly used in RIA applications like Silverlight, AJAX client, etc. It solves the major problem while developing business application like decoupling the resource access, application logic and presentation layer. WCF RIA service was introduced in Silverlight 4 with .net framework 4, and it can be developed using visual studio2010.
Main problem developer are facing while developing the n-tier RIA application will be coordinating the application logic between middle tier and presentation tier. This problem will be solved by using WCF RIA service, it will synchronize the code between middle and presentation tier.
WCF RIA service will allow developer to write the set of service code and this server code will be available to the client side without manually duplicate that programming logic. RIA service client will be updated with business rule and entity present at the server side, when your recompile your project solution.
WCF RIA service will generate the code at the client side related to the service and domain entities declared at the server side.
RIA service exposes the data from server side to client side using Domain service, RIA service framework implements the each domain service as WCF service to access the data as business entity.
fig: WCF RIA Serive architecture
WCF RIA Serive architecture

Domain Service

Domain services are WCF services that expose the business logic of a WCF RIA Services application. Domain service contains set of business related data operation and it is exposed as WCF service.
Below diagram explains integration of the RIA service with WCF
The DomainService class is the base class for all classes that serve as domain services.
  • DomainServiceHost is the hosting class for domain service; internally
  • DomainServiceHost uses the WCF ServiceHost class to host the application.
A domain service class must be marked with the EnableClientAccessAttribute attribute to make the service available to the client project. The EnableClientAccessAttributeattribute is automatically applied to a domain service when you select the Enable client access check box in the Add New Domain Service Class dialog box. When the EnableClientAccessAttribute attribute is applied to a domain service, RIA Services generates the corresponding classes for the client project.


Example:
 [EnableClientAccess()]
    public class EmployeeDomainService : DomainService
    {
        private EmployeeData data = EmployeeData.Instance;
 
        public IEnumerable < Employee> GetEmployees()
        {
            return data.EmployeeList;
        }
    }

DomainContext class at the client side is used to consume the Domain service by using DomainClient object. DomainContext class available inside the name space "System.ServiceModel.DomainServices.Client"
fig: WCF RIA Domain Serive architecture
WCF RIA Domain Serive
 
 

Problem solved in RIA

  1. To have best performance of the RIA application, app logic need to be available in client and server side. This problem is solved by auto generating the code at the client side while recompiling the project.
  2. Asynchronous call – Asynch service call are supported in Domain service by using WCF infrastructure
  3. Handling large data and data across different tier – Large amount of data can be access and filter using IQueryable object. Since entity objects used in domain service are serializable and so it can be access across different layer
  4. Security/Access control – ASP.Net membership frameworks are integrated with RIA service to provide security systems to RIA service
  5. Validation – Entity can be validated based using adding attribute to the class members

Example:
  public class Member
    {
        [Key]
        public int MemberId { get; set; }
 
 
        public string Fname { get; set; }
 
        [Required]
        public string Lname { get; set; }
 
        public DateTime JoinDate { get; set; }
 
        [Range(30,90, ErrorMessage="sorry, you are either too young or too old for our club!")]
        public int Age { get; set; }
    }


Querying/Updating data in RIA Service

The below diagram are self explanatory to discuss about the querying or updating the data using RIA service
fig: WCF RIA to Query data

fig: WCF RIA to update data

How to Create WCF RIA Service

Let us understand more about the WCF RIA service by creating Silverlight client application which read and updated the Employee details from WCF RIA Service.
Step 1:Start the Visual Studio 2010 and click File -> New-> Project. Enter the project name and click “Create”
Project creation
Step 2:Select “Enable WCF RIA Services”. This will make your Silverlight application to user WCF RIA service
Select RIA service
Step 3:Create “Data” folder and add DataModel” class as shown below. This is the data class which will return list of Employee and update the employee list

Data Model class:
   public class Employee
    {
        [Key]
        public int EmpId { get; set; }

        public string Fname { get; set; }

        public string Lname { get; set; }

        public DateTime JoinDate { get; set; }

        public int Age { get; set; }
    }


    public partial class EmployeeData
    {
        private static readonly EmployeeData _instance = new EmployeeData();

        private EmployeeData() { }

        public static EmployeeData Instance
        {
            get
            {
                return _instance;
            }
        }


        private List < Employee > empList = new List < Employee>()
        {
            new Employee() { EmpId  = 1, Fname = "Sam", Lname = "kumar", 
                            JoinDate=new DateTime(2010,7, 21), Age=30},
            new Employee() { EmpId = 2, Fname = "Ram", Lname = "kumar", 
                            JoinDate=new DateTime(2009,6,8), Age=35},    
            new Employee() { EmpId = 3, Fname = "Sasi", Lname = "M", 
                            JoinDate=new DateTime(2008,3,5), Age=39},  
            new Employee() { EmpId = 4, Fname = "Praveen", Lname = "KR", 
                            JoinDate=new DateTime(2010, 5,1), Age=56},
            new Employee() { EmpId = 5, Fname = "Sathish", Lname = "V", 
                            JoinDate = new DateTime(2006,12,15), Age=72},  
            new Employee() { EmpId = 6, Fname = "Rosh", Lname = "A", 
                            JoinDate=new DateTime(2009,2,2), Age=25}
        };

        public IEnumerable< Employee > EmployeeList
        {
            get
            {
                return empList;
            }
        }


        public void Update(Employee updEmployee)
        {
            Employee existing = empList.Find(p => p.EmpId == updEmployee.EmpId);

            if (existing == null)
                throw new KeyNotFoundException("Specified Employee cannot be found");

            existing.Fname = updEmployee.Fname;
            existing.Lname = updEmployee.Lname;
            existing.JoinDate = updEmployee.JoinDate;
            existing.Age = updEmployee.Age;
        }
    }
Step 4:To expose the Employee related operation to the client side, Create domain service class. By right click project file and select Add new item.
Create Domain Service
Step 5:Add code to return the Employee list

Domain Service class:

// TODO: Create methods containing your application logic.
    [EnableClientAccess()]
    public class EmployeeDomainService : DomainService
    {
        //Create instance of the Data access layer
        private EmployeeData data = EmployeeData.Instance;

        public IEnumerable< Employee> GetEmployee()
        {
            return data.EmployeeList ;
        }

        public void UpdateEmployee(Employee emp)
        {
            data.Update(emp);
        }
    }
Step 6:Compile the solution – After compilation RIA service will generate the application logic at the client side using DomainContext object. Enable show all files option for the solution and view the auto generated code.
Auto generated code
Step 7:View the DomainContext class are created at the client side.

Domain Context class at client:
   /// 
    /// The DomainContext corresponding to the 'EmployeeDomainService' DomainService.
    /// 
    public sealed partial class EmployeeDomainContext : DomainContext
    {
        
        #region Extensibility Method Definitions

        /// 
        /// This method is invoked from the constructor once initialization is complete and
        /// can be used for further object setup.
        /// 
        partial void OnCreated();

        #endregion
        
        
        /// 
        /// Initializes a new instance of the < see cref="EmployeeDomainContext"/> class.
        /// 
        public EmployeeDomainContext() : 
                this(new WebDomainClient< IEmployeeDomainServiceContract>(new 
                              Uri("MyFirstRIAApplication-Web-EmployeeDomainService.svc", 
                                                        UriKind.Relative)))
        {
        }

        ........
        ........
Step 8:Add DataGrid to Main.xaml file to display the employee details query from DataModel and add two buttons to update and reject the data changed from client side.

Main.xaml 
 < Grid x:Name="LayoutRoot" Background="White">
        < StackPanel Orientation="Vertical" HorizontalAlignment="Left"  >
        < sdk:DataGrid x:Name="EmployeeGrid" AutoGenerateColumns="True"  
                        RowEditEnded="EmployeeGrid_RowEditEnded" />
            < Button Content="Accept" Height="23" Name="btnAccept" 
                        Width="75" Margin="5" Click="btnAccept_Click"  />
            < Button Content="Reject" Height="23" Name="btnReject" 
                        Width="75" Margin="5" Click="btnReject_Click"/>
        </StackPanel>
    </Grid>
    

Main.xaml.vb 

 public partial class MainPage : UserControl
    {
        //create instance of Doman context class
        EmployeeDomainContext ctx = new EmployeeDomainContext();

        public MainPage()
        {
            InitializeComponent();
            //Load query data , Read data from DAL layer to UI
            EntityQuery< Employee> query = ctx.GetEmployeeQuery();
            LoadOperation< Employee> lo = ctx.Load< Employee>(query);
            EmployeeGrid.ItemsSource = lo.Entities;
        }

        private void EmployeeGrid_RowEditEnded(object sender, 
                                DataGridRowEditEndedEventArgs e)
        {

        }

        private void btnAccept_Click(object sender, RoutedEventArgs e)
        {
            //Update the DAL with user changes
            ctx.SubmitChanges();
        }

        private void btnReject_Click(object sender, RoutedEventArgs e)
        {
            //Roll back the user changes
            ctx.RejectChanges();
        }
    }
Step 9:Run the application and see the output as shown below
RIA service output

Introduction to RESTful service

REST – Representational State Transfer
"REST, an architectural style for building distributed hypermedia driven applications, involves building Resource-Oriented Architecture (ROA) by defining resources that implement uniform interfaces using standard HTTP verbs (GET, POST, PUT, and DELETE), and that can be located/identified by a Uniform Resource Identifier (URI)."
Any Service which follows this REST architecture style is called as RESTful service. It became very popular because of it behavior, it is similar to the website i.e we can load the server information using web url in the browser. similarly we can also access/modify the server resource using Url in RESTful service
  • RESTful service will allow the client (written in different language)to access or modify the resource in the server using URL.
  • RESTful service uses the http protocol for its communication and it is stateless
  • RESTful service can transfer the data in XML,JSON,RSS,ATOM
SOAP POX(plain-old XML) REST
  • Simple Object Application Protocol
  • SOAP – is a package contain message information and it will be delivered by HTTP
  • Developers are mainly preferred to user because of its increase interoperability
  • Lot of tools are available in the market to generate the clients code from WSDL
  • Plain raw XML message will be used for communication
  • Developers using POX had to write their own code for XML and HTTP for request/response message.
  • So most of the developers moved back to SOAP
  • REST defines more of a transport-specific model
  • In reality HTTP is the only protocol that is used in practice today for building RESTful architecture.
This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping
  • To create a resource on the server, use POST.
  • To retrieve a resource, use GET.
  • To change the state of a resource or to update it, use PUT.
  • To remove or delete a resource, use DELETE.
RESTful service can be created by using WebGetAttribute and WebInvokeAttribute attribute. RESTful service has provided separate attribute for GET operation (WebGet) because it want to make use of complete features. Other operations like POST,PUT,DELETE will come under the WebInvoke attribute.

How to create RESTful service

Download Souce:

MyFirstRESTfulService.zip
This sample explains about the creating the RESTful service to create and updating the resource information available at the sever side. This Restful service will be consumed using client console application.
Step 1: For our example we are suing “EmployeeData” class as Data Access Layer for storing and reading the employee information.
Data Model class:

namespace MyFirstRESTfulService
{
    [DataContract]
    public class Employee
    {
        [DataMember]
        public int EmpId { get; set; }
        [DataMember]
        public string Fname { get; set; }
        [DataMember]
        public string Lname { get; set; }
        [DataMember ]
        public DateTime JoinDate { get; set; }
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public int Salary { get; set; }
        [DataMember]
        public string Designation { get; set; }
    }


    public partial class EmployeeData
    {
        private static readonly EmployeeData _instance = new EmployeeData();

        private EmployeeData() { }

        public static EmployeeData Instance
        {
            get
            {
                return _instance;
            }
        }


        private List< Employee> empList = new List < Employee>()
        {
            new Employee() { EmpId  = 1, Fname = "Sam", Lname = "kumar", JoinDate=new DateTime(2010,7, 21), Age=30,Salary=10000,Designation="Software Engineer"},
            new Employee() { EmpId = 2, Fname = "Ram", Lname = "kumar", JoinDate=new DateTime(2009,6,8), Age=35,Salary=10000,Designation="Senior Software Engineer"},    
            new Employee() { EmpId = 3, Fname = "Sasi", Lname = "M", JoinDate=new DateTime(2008,3,5), Age=39,Salary=10000,Designation="Projet Manager"},  
            new Employee() { EmpId = 4, Fname = "Praveen", Lname = "KR", JoinDate=new DateTime(2010, 5,1), Age=56,Salary=10000,Designation="Projet Manager"},
            new Employee() { EmpId = 5, Fname = "Sathish", Lname = "V", JoinDate = new DateTime(2006,12,15), Age=72,Salary=10000,Designation="Senior Software Engineer"},  
            new Employee() { EmpId = 6, Fname = "Rosh", Lname = "A", JoinDate=new DateTime(2009,2,2), Age=25,Salary=10000,Designation="Software Engineer"}
        };

        public List< Employee> EmployeeList
        {
            get
            {
                return empList;
            }
        }


        public void Update(Employee updEmployee)
        {
            Employee existing = empList.Find(p => p.EmpId == updEmployee.EmpId);

            if (existing == null)
                throw new KeyNotFoundException("Specified Employee cannot be found");

            existing.Fname = updEmployee.Fname;
            existing.Lname = updEmployee.Lname;
            existing.Age = updEmployee.Age;
        }

        public void Delete(int empid)
        {
            Employee existing = empList.Find(p => p.EmpId == empid);
            empList.Remove(existing);
        }
        public void Add(Employee newEmployee)
        {
            empList.Add(new Employee
            {
                EmpId = newEmployee.EmpId,
                Fname = newEmployee.Fname,
                Lname = newEmployee.Lname,
                Age = newEmployee.Age,
                JoinDate = DateTime.Now,
                Designation = newEmployee.Designation,
                Salary = newEmployee.Salary
            });
        }
    }
}
Step 2: Let’s start create EmployeeService (simple WCF) with ServiceContract, OperationContract and DataContract as shown below.
Interface and Implementation:
    [ServiceContract()]
    public interface IEmployeeService
    {
        [OperationContract]
        List< Employee > GetAllEmployeeDetails();

        [OperationContract]
        Employee GetEmployee(int Id);
               
        [OperationContract]
        void AddEmployee(Employee newEmp);
        
        [OperationContract]
        void UpdateEmployee(Employee newEmp);
        
        [OperationContract]
        void DeleteEmployee(string empId);
    }

     [AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed )]
   public  class EmployeeService: IEmployeeService 
    {
        
       public List < Employee > GetAllEmployeeDetails()
        {
            return EmployeeData.Instance.EmployeeList;
        }
      
        public Employee GetEmployee(int id)
        {
            IEnumerable< Employee > empList = EmployeeData.Instance.EmployeeList.Where(x => x.EmpId == id);

            if (empList != null)
                return empList.First< Employee >();
            else
                return null;
        }

     
       public void AddEmployee(Employee newEmp)
       {
           EmployeeData.Instance.Add(newEmp);
       }

       
        public void UpdateEmployee( Employee newEmp)
        {
            EmployeeData.Instance.Update(newEmp);
        }

      
         public void DeleteEmployee(string empId)
        {
            EmployeeData.Instance.Delete(System.Convert .ToInt32 (empId));
        }
    }
Step2: This service can be hosted as normal WCF service by creating the ServiceHost object and adding endpoint with different binding. This is already explained in “ConsoledHosted WCF Service”.
As it is mention in introduction section of RESTful service, all the resource located in server side can be accessed using url. Method exposed at the server side can be call using url, to do that we need to decorate the service method with “WebGet” or “WebInvoke” attribute as mention below
    [ServiceContract()]
    public interface IEmployeeService
    {
        [WebGet(UriTemplate = "Employee")]
        [OperationContract]
        List< Employee > GetAllEmployeeDetails();

        [WebGet(UriTemplate = "Employee?id={id}")]
        [OperationContract]
        Employee GetEmployee(int Id);

        [WebInvoke(Method = "POST", UriTemplate = "EmployeePOST")]
        [OperationContract]
        void AddEmployee(Employee newEmp);

        [WebInvoke(Method = "PUT", UriTemplate = "EmployeePUT")]
        [OperationContract]
        void UpdateEmployee(Employee newEmp);

        [WebInvoke(Method = "DELETE", UriTemplate = "Employee/{empId}")]
        [OperationContract]
        void DeleteEmployee(string empId);
    }
Step4: In the above interface declaration, you can find that we have added UriTemplate”, it is nothing but a relative path for accessing the service method using url. These methods can be called from client application or browser by typing url as “WCf Service url” + “Relative Path” E.g: http://localhost:8090/MyService/EmployeeService/Employee
Step 5:Method” is another option we can add to the WebInvoke attribute to specify the mode of transfer like “PUT”, “POST”, or “DELETE”
Step 6: Now we have completed with service implementation project. Let’s start with Hosting the RESTful service. For this example we are using console application for hosting service. WCF framework has provided new class to host the RESTful service i.e WebServiceHost. By hosting the restful service with WebServiceHost host class will automatically set the binding and other configuration setting. In the below code you can see that I have only mention url for the hosting.
                Uri httpUrl = new Uri("http://localhost:8090/MyService/EmployeeService");
                WebServiceHost host = new WebServiceHost(typeof(MyFirstRESTfulService.EmployeeService), httpUrl);
                host.Open();
            
                foreach (ServiceEndpoint se in host.Description.Endpoints)
                        Console.WriteLine("Service is host with endpoint " + se.Address);
                //Console.WriteLine("ASP.Net : " + ServiceHostingEnvironment.AspNetCompatibilityEnabled);
                Console.WriteLine("Host is running... Press < Enter > key to stop");
                Console.ReadLine();
Step 7: We can access the RESTful service using browser. Just type the url in the web browser to read all the employee details
WebGet method call
If we need to get specific employee details, pass the employee as query parameter as we mention in UriTemplate of the service.
WebGet method call
Step 8:Now we can start with client application. For this example we can create a console application to read the employee information and add new employee to the server resource. Below code first read the employee details from the server and add new employee and once again it read the employee details to confirm the added resource.
WebChannelFactory < IEmployeeService > cf =
               new WebChannelFactory< IEmployeeService >(
                   new Uri("http://localhost:8090/MyService/EmployeeService"));
            IEmployeeService client = cf.CreateChannel();
            var d = client.GetEmployee(1);
            //Load all the Employee from the server and display
           foreach (Employee e in   client.GetAllEmployeeDetails() )
           {
           Console.WriteLine(string.Format("EmpID:{0}, Name:{1} {2}",e.EmpId ,e.Fname ,e.Lname ));
           }

            //Add new user
           client.AddEmployee(new Employee() { EmpId = 11, Fname = "John", Lname = "J", JoinDate = new DateTime(2010, 7, 24), Age = 34, Salary = 10000, Designation = "Software Engineer" });
        
            Console.WriteLine("******************After adding new user ****************");

        //Load all the Employee from the server and display
         foreach (Employee e in   client.GetAllEmployeeDetails() )
           {
           Console.WriteLine(string.Format("EmpID:{0}, Name:{1} {2}",e.EmpId ,e.Fname ,e.Lname ));
           }
            Console.ReadLine();
        }
Step 9: Run the application to view the output as shown below
Restful service output 

JSON using WCF service

Download Souce:

MyFirstRESTfulService.zip
This article explains about configuring the WCF service to send the response business entity as JSON objects.
JSON –JavaScript Object Notation.
“The JSON text format is syntactically identical to the code for creating JavaScript objects “.
In most of the browser based application, WCF can be consumed using javascript or jquery. When client makes the call to the WCF, JSON or XML is used for mode of communication. WCF has option to send the response in JSON object. This can be configured with WebGet or WebInvoke attribute.
In this sample we can create the sample RESTful service to expose the method to read/add/update/delete the employee information. Read the “How to create REST ful Service” articles for more information.
On top of the Restful service we need to update the ResponseMode attribute to send the business entity as JSON object. Below code shows how to configure the JSON response format.
[ServiceContract()]
    public interface IEmployeeService
    {
        [WebGet(UriTemplate = "Employee", ResponseFormat=WebMessageFormat.Json )]
        [OperationContract]
        List < Employee > GetAllEmployeeDetails();

        [WebGet(UriTemplate = "Employee?id={id}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        Employee GetEmployee(int Id);

        [WebInvoke(Method = "POST", UriTemplate = "EmployeePOST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void AddEmployee(Employee newEmp);

        [WebInvoke(Method = "PUT", UriTemplate = "EmployeePUT", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void UpdateEmployee(Employee newEmp);

        [WebInvoke(Method = "DELETE", UriTemplate = "Employee/{empId}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        void DeleteEmployee(string empId);
    }
You can see that WCF response are send as JSON object while accessing data using browser.
JSON browse Below sample is the ASP.Net web application is used to explains about the CRUD from WCF service with response as JSON object.
GET Method
 function RefreshPage() {
          var serviceUrl = "http://saravana:8090/MyService/EmployeeService/Employee";

          $.ajax({
              type: "GET",
              url: serviceUrl,
              dataType: 'json',
              contentType: "application/json; charset=utf-8",
              success: function (data) {
                  var itemRow = "< table >";
                  $.each(data, function (index, item) {
                      itemRow += "<tr><td>" + item.EmpId + "</td><td>" + item.Fname + "</td></tr>";
                  });
                  itemRow += "</table>";

                  $("#divItems").html(itemRow);

              },
              error: ServiceFailed
          });
      }
POST Method
function POSTMethodCall() {
           var EmpUser = [{ "EmpId": "13", "Fname": "WebClientUser", "Lname": "Raju", "JoinDate": Date(1224043200000), "Age": "23", "Salary": "12000", "Designation": "Software Engineer"}];
           var st = JSON.stringify(EmpUser);
           debugger;
          $.ajax({
              type: "POST",
              url: "http://saravana:8090/MyService/EmployeeService/EmployeePOST",
              data: JSON.stringify(EmpUser),
               contentType: "application/json; charset=utf-8",
              dataType: "json",
              success: function (data) {
                  // Play with response returned in JSON format
              },
              error:ServiceFailed
          });

      }
<
PUT Method
 function PUTMethodCall() {
          var EmpUser = [{ "EmpId": "3", "Fname": "WebClientUser", "Lname": "Raju", "JoinDate": Date(1224043200000), "Age": "23", "Salary": "12000", "Designation": "Software Engineer"}];

          $.ajax({
              type: "PUT",
              url: "http://saravana:8090/MyService/EmployeeService/EmployeePUT",
              data: EmpUser,
              contentType: "application/json; charset=utf-8",
              dataType: "json",
              success: function (data) {
                  // Play with response returned in JSON format
              },
              error: ServiceFailed
          });

      }
<
DELETE Method
 function DELETEMethodCall() {
          $.ajax({
              type: "DELETE",
              url: "http://saravana:8090/MyService/EmployeeService/Employee/2",
              data: "{}",
              contentType: "application/json; charset=utf-8",
              dataType: "json",
              success: function (data) {
                  // Play with response returned in JSON format
              },
              error: function (msg) {
                  alert(msg);
              }
          });

      }

Handling Exception in Silverlight application from WCF

This article explains about handling the exception in Silverlight application from WCF. I have created the sample Silverlight application, which uses the WCF service for process the data. While testing the application I came to know that exception message thrown from WCF cannot be received at the client side(Silverlight application) even after using the FaultException. I was always getting System.ServiceModel.CommunicationException: The remote server returned an error: NotFound.
Later I came to know that WCF throws the HTTP 500 series Fault message but Silverlight can handle only 200 series. So we need to convert the 500 series to 200 error message for Silverlight. Here is the sample application for exception handling between WCF and Silverlight.
Step 1: We can customize the Endpoint behavior of the WCF service by inheriting the Beha and implementing the IEndpointBehavior. Actual code for converting the 500 error serice to 200 serivce in BeforeSendReply method.
Create a ClassLibrary project and name it as “Silverlight_WCF_FaultBehavior” and name the class as “SilverlightFaultBehavior”. Copy and paste the follwing code inside the SilverlightFaultBehavior class.
Imports System.ServiceModel.ConfigurationrviceModel.Configuration
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Channels
Imports System.ServiceModel

    Public Class SilverlightFaultBehavior
        Inherits BehaviorExtensionElement
        Implements IEndpointBehavior


        Public Overrides ReadOnly Property BehaviorType() As System.Type
            Get
                Return GetType(SilverlightFaultBehavior)
            End Get
        End Property

        Protected Overrides Function CreateBehavior() As Object
            Return New SilverlightFaultBehavior
        End Function

        Public Sub AddBindingParameters(ByVal endpoint As ServiceEndpoint,
                                     ByVal bindingParameters As BindingParameterCollection)
                                     Implements IEndpointBehavior.AddBindingParameters

        End Sub

        Public Sub ApplyClientBehavior(ByVal endpoint As ServiceEndpoint, 
                                       ByVal clientRuntime As ClientRuntime) 
                                       Implements IEndpointBehavior.ApplyClientBehavior

        End Sub

        Public Sub ApplyDispatchBehavior(ByVal endpoint As ServiceEndpoint, 
                          ByVal endpointDispatcher As EndpointDispatcher) 
                          Implements IEndpointBehavior.ApplyDispatchBehavior
            Dim inspector As New SilverlightFaultMessageInspector()
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector)
        End Sub

        Public Sub Validate(ByVal endpoint As ServiceEndpoint)
                                         Implements IEndpointBehavior.Validate

        End Sub

        Public Class SilverlightFaultMessageInspector
            Implements IDispatchMessageInspector

            Public Function AfterReceiveRequest(ByRef request As Message, 
                                     ByVal channel As IClientChannel,
                                     ByVal instanceContext As InstanceContext) As Object 
                                     Implements IDispatchMessageInspector.AfterReceiveRequest
                ' Do nothing to the incoming message. 
                Return Nothing
            End Function

            Public Sub BeforeSendReply(ByRef reply As System.ServiceModel.Channels.Message,
                                       ByVal correlationState As Object) 
                                       Implements IDispatchMessageInspector.BeforeSendReply
                If reply.IsFault Then
                    Dim [property] As New HttpResponseMessageProperty()

                    ' Here the response code is changed to 200. 
                    [property].StatusCode = System.Net.HttpStatusCode.OK
                    reply.Properties(HttpResponseMessageProperty.Name) = [property]
                End If
            End Sub
        End Class

    End Class


Note: Highlighted code shows the conversion for 500 serices to 200 series error code.
Step 2: Build the project
Step 3: Create a new WCF service with Interface and implementation class as follows
Interface
<ServiceContract()> _
Public Interface IService
    <OperationContract()> _
    Function Add(ByVal num1 As Integer, ByVal num2 As Integer) As Integer
    <OperationContract()> _
    Function Subtract(ByVal num1 As Integer, ByVal num2 As Integer) As Integer

   
End Interface

Implementation
Public Class Service
    Implements IService

    Public Sub New()
    End Sub

    Public Function Add(ByVal num1 As Integer, ByVal num2 As Integer)
                                         As Integer Implements IService.Add
        Throw New FaultException("Error thrown by user for Add operation")
        'Return num1 + num2
    End Function

    Public Function Subtract(ByVal num1 As Integer, 
                            ByVal num2 As Integer) As Integer Implements IService.Subtract
        Return num1 - num2
    End Function
End Class


< Add the Silverlight_WCF_FaultBehavior project dll as reference to WCF Service
Step 5:
Step 5: In WCF we can extend the binding and behavior by using <extention> tag. In our case also we are extending the custom endpoint behavior as shown below. In the <behaviorExtensions> tag we need specify the fully qualified name of the cutom behaviour assembly.
Modify the Web.config file as shown bellow
<system.serviceModel>
    <services>
      <service name="Service" behaviorConfiguration="ServiceBehavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="basicHttpBinding" contract="IService"
         behaviorConfiguration="SilverlightFaultBehavior">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced 
              to reflect the identity under which the deployed service runs.  If removed, 
              WCF will infer an appropriate identity automatically.-->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and 
          remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value 
          below to true.  Set to false before deployment to avoid disclosing exception 
          information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="SilverlightFaultBehavior">
          <silverlightFaults/>
        </behavior>
      </endpointBehaviors>
    </behaviorss=“BlueCode”>>
    <extensions>
      <behaviorExtensions>
        <add name="silverlightFaults" 
        type="Silverlight_WCF_FaultBehavior.SilverlightFaultBehavior, 
        Silverlight_WCF_FaultBehavior, Version=1.0.0.0, Culture=neutral, 
        PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensionss=“BlueCode”>>
  </system.serviceModel>
Step 6: Create the any sample silverlight application as “Silverlight_WCF_Exception” and add this WCF service as Service Reference.
url: http://localhost/MathService/Service.svc
Step 7: Add a button to the MainPage.xaml and call the WCF method as shown below
    Private Sub Button_Click(ByVal sender As System.Object,
                             ByVal e As System.Windows.RoutedEventArgs)
        Dim proxy As New ServiceProxy.ServiceClient
        AddHandler proxy.AddCompleted, AddressOf AddOperationCompleted
        proxy.AddAsync(5, 6)
    End Sub

    Private Sub AddOperationCompleted(ByVal sender As Object, 
                                    ByVal e As ServiceProxy.AddCompletedEventArgs)
        If e.Error IsNot Nothing Then
            MessageBox.Show(e.Error.Message)
        Else
            MessageBox.Show(e.Result)
        End If
    End Sub

Step 8: Output will look like this
Conclution: This article explains about handling the exception in Silverlight application from WCF
 
 

Custom message header

This article explains about customizing the wcf message flowing between service and client.
There are certain scenario in which you to pass some information from client to service, but not as parameter in operation contracts. Example, logging system at the service we need to log user or machine information, which made request to the service. In this kind of scenario we should not pass user or machine information as parameter in operation contract. Instead we can pass the information through message flowing between client and service vice versa. The information we need to send can be appended with message header and it can be received at the server side.
Let as create sample service and client application, in which client will send “User name” information through request message and service will respond with confirmation message.
I have created Math service with Add and Subtract functionality. Client consuming this service will send his user name information as string with requested message. Once request reached the service, it will read the information from the message header and display using console window. When service responding to the client, along with operation result, it will also send confirmation message to client through message header.
Step 1: Create IMathService interface decorated with Service and Operational contract attribute
IMathService.vb
<ServiceContract()> _
Public Interface IMathService
    <OperationContract()> _
    Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
    <OperationContract()> _
    Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer
End Interface
Step 2:In this class, we have implemented Add and Subtract functionality.
PrintRequestedUserID() method will read the “UserID” message header from incoming message using OperationContext. This User information is displayed in console window.
SendResponseWithMessage() method will send a confirmation message to the client as Message header through Operation context.
MathService.vb
Public Class MathService
    Implements IMathService

    Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer 
    Implements IMathService.Add
        'This method call will retrive message send from client using MessageHeader
        PrintRequestedUserID()
        'This method call will send message to client using MessageHeader
        SendResponseWithMessage()
        Return a + b

    End Function

    Public Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer 
    Implements IMathService.Subtract
        'This method call will retrive message send from client using MessageHeader
        PrintRequestedUserID()
        'This method call will send message to client using MessageHeader
        SendResponseWithMessage()
        Return a - b
    End Function

    Private Sub PrintRequestedUserID()
        Dim userID As String = String.Empty
        'Read the message header using "Name" and "NameSpace"
        userID = OperationContext.Current.IncomingMessageHeaders
                                    .GetHeader(Of String)("UserID", "ns")
        Console.WriteLine("Requested user: " + userID)
    End Sub

    Private Sub SendResponseWithMessage()
        'Creating new message header with "Content" value assigned in constructor
        Dim mess As New MessageHeader(Of String)("This is sample message from service")
        'Assigning Name and NameSpace to the message header value at server side
        Dim header As System.ServiceModel.
                    Channels.MessageHeader = mess.GetUntypedHeader("ServiceMessage", "ns")
        'Adding message header with OperationContext 
        'which will be received at the client side
        OperationContext.Current.OutgoingMessageHeaders.Add(header)
    End Sub
End Class
Step 3: Hosting the MathService using console application
MyServiceHost.vb
       Module MyServiceHost

    Sub Main()
        'Hosting the Math service using console application
        Dim host As New ServiceHost(GetType(MyService.MathService))
        host.Open()
        Console.WriteLine("Service is running... Press  to exit.")
        Console.ReadLine()
    End Sub

End Module

Web.Config
      <system.serviceModel>
    <services><service name="MyService.MathService" 
    behaviorConfiguration="MyServiceBehavior">
        <endpoint address ="MathService" binding="basicHttpBinding" 
        contract="MyService.IMathService"/>
        <endpoint  address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8090/MyService"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors >
        <behavior name ="MyServiceBehavior">
          <serviceMetadata httpGetEnabled ="true"/>
            <serviceDebug includeExceptionDetailInFaults ="True"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Step 4: Created console client application which add “UserID” as message header to service using Operation context before calling Add() functionality. Once the response is received from the service, it is trying to read the confirmation message from service using Operation context.
Sub Main()
        'Creating proxy class for service
        Dim proxy As IMathService = Nothing
        proxy = ChannelFactory(Of IMathService).CreateChannel(New BasicHttpBinding(), 
                    New EndpointAddress("http://localhost:8090/MyService/MathService"))

        'Lifetime of OperationContextScope defines the scope for OperationContext.
        Dim scope As OperationContextScope = Nothing
        scope = New OperationContextScope(proxy)
       
        'Creating new message header with "Content" value assigned in constructor
        Dim mess As New MessageHeader(Of String)
                         (System.Security.Principal.WindowsIdentity.GetCurrent().Name)
        'Assigning Name and NameSpace to the message header value at client side
        Dim header As System.ServiceModel.Channels.MessageHeader 
                                    = mess.GetUntypedHeader("UserID", "ns")
        'Adding message header with OperationContext 
        'which will be received at the server side
        OperationContext.Current.OutgoingMessageHeaders.Add(header)

        'Making service call
        Console.WriteLine("Sum of {0},{1}={2}", 1, 2, proxy.Add(1, 2))
        'Displaying confrimation message from service
        Console.WriteLine("Response Message: " + OperationContext.Current.
                    IncomingMessageHeaders.GetHeader(Of String)("ServiceMessage", "ns"))
        Console.ReadLine()
    End Sub

End Module

<ServiceContract()> _
Public Interface IMathService
    Inherits IClientChannel

    <OperationContract()> _
    Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
    <OperationContract()> _
    Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer
End Interface

Step 5: Run the MyServiceHost
Step 6: Run the MyClientApplication
Below figure shows the message flowing between service and client
Client application output
Console hosted service output screen
Conclusion:
This article explain about customizing the wcf message header


 
 

1 comment:

  1. In case you are interested in making cash from your visitors with popup advertisments - you should run with one of the most established networks: Clicksor.

    ReplyDelete