Wednesday 4 April 2012

Wcf REST and IErrorHanlder:-

The interface comes with two methods.

ProvideFault allows you to handle the error and determine what is returned to the client.
HandleError method is called after the call has already completed, to possibly log the error.

If you use wcf starter kit it doesn’t work.A little work around  will solve the problem.

->Create wcf REST service.

    [ServiceContract]
    public class Service
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public string SayHello(string name)
        {
            int i = 0;
            int j = 1;
            int k = j / i;

            return "Hello " + name;
        }
    }
    [DataContract]
    public class CustomException
    {
        [DataMember]
        public string Description { getset; }
    }

->Create ErrorHandler class and inherit it from IErrorHandler and implement HandleError and ProvideFault methods.

public class ErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            //Log error here.
            return true;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            //Create error object .
            CustomException objCustomException = new CustomException();
            objCustomException.Description = error.Message;

            //Construct error message here.
            fault = Message.CreateMessage(version, "", objCustomException, new DataContractJsonSerializer(typeof(CustomException)));

            HttpResponseMessageProperty responseMessageProperty = new HttpResponseMessageProperty();

            //Set the status code here.
            responseMessageProperty.StatusCode = HttpStatusCode.InternalServerError;

            //Set the content type to json.
            responseMessageProperty.Headers[HttpResponseHeader.ContentType] = "application/json";

            fault.Properties[HttpResponseMessageProperty.Name] = responseMessageProperty;

            WebBodyFormatMessageProperty formatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            fault.Properties[WebBodyFormatMessageProperty.Name] = formatMessageProperty;
        }
    }
->Create Behavior Class and inherit it from WebHttpBehavior2.
public class Behavior : WebHttpBehavior2
    {
        protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            //Add error handler.
            endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandler());
        }
    }
->Create Host class and inherit it from WebServiceHost2 and override OnOpening method.
public class Host : WebServiceHost2
    {
        public Host(Type serviceType, bool dummy, params Uri[] baseAddresses)
            : base(serviceType, dummy, baseAddresses)
        {

        }

        protected override void OnOpening()
        {
            //Call base class OnOpening method.
            base.OnOpening();

            //Get the description of the service hosted.
            if (base.Description != null)
            {
                //Get the endpoints.
                foreach (var endpoint in base.Description.Endpoints)
                {
                    //Remove the WebHttpBehavior2(If you use wcfREST starter kit it automatically added to the service).
                    endpoint.Behaviors.Remove<WebHttpBehavior2>();
                   
                    //Get our custom behavior.
                    var item = new Behavior();

                    //Add the bahavior to endpoint.
                    endpoint.Behaviors.Add(item);
                }
            }
        }
    }

->Now open ServiceHost.svc file and add our custom factory class.

<%@ ServiceHost Language="C#" Debug="true" Service="WcfRESTIErrorHanlder.Service"
    CodeBehind="Service.svc.cs" Factory="WcfRESTIErrorHanlder.HostFactory" %>

using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using Microsoft.ServiceModel.Web;

namespace WcfRESTIErrorHanlder
{
    public class HostFactory : WebServiceHost2Factory
    {
        protected override ServiceHost CreateServiceHost(System.Type serviceType, System.Uri[] baseAddresses)
        {
            //Create host object.
            Host objHost = new Host(serviceType, true, baseAddresses);

            //Return host.
            return objHost;
        }
    }
}
Let me know, if you have any feedback. Mail me for source code. Enjoy reading my articles…
sekhartechblog@gmail.com

Wcf REST Authentication:-

In wcf REST starter kit we get Microsoft.ServiceModel.Web dll file which gives features like throwing exceptions and authentication.

Instead of writing  authentication code on each function we can use the wcfREST starter kit  RequestInterceptor class.

->Create wcf REST service.

    [ServiceContract]
    public class Service
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public string SayHello(string name)
        {
            //Return string.
            return "Hello " + name;
        }
    }
    [DataContract]
    public class Error
    {
        [DataMember]
        public string Message { get; set; }
    }


->Add new class AuthenticationInterceptor and inherit it from RequestInterceptor
class and override ProcessRequest method.
 
public class AuthenticationInterceptor : RequestInterceptor
    {
        public AuthenticationInterceptor()
            : base(false)
        {
        }
        public override void ProcessRequest(ref System.ServiceModel.Channels.RequestContext requestContext)
        {
            //Get the message object from the request context.
            Message msg = requestContext.RequestMessage;
            HttpRequestMessageProperty rmp = (HttpRequestMessageProperty)msg.Properties[HttpRequestMessageProperty.Name];

            //Get the list of query strings.
            NameValueCollection nmc = HttpUtility.ParseQueryString(rmp.QueryString);

            //Get the userId from the query string collection.
            string userId = nmc["UserId"];

            //Check the user id.
            if (userId != "Admin")
            {
                //If the user is not the Admin then generate the error response.
                GenerateErrorResponse(requestContext, HttpStatusCode.Unauthorized, "Please provide valid user id.");
               
               //Set the requestcontext to null to send the message.
               requestContext = null;
            }
        }

        //Generate the error response to the client.
        public void GenerateErrorResponse(RequestContext requestContext, HttpStatusCode statusCode, string errorMessage)
        {
            //Create error object.
            Error objError = new Error();

            //Set the error message.
            objError.Message = errorMessage;

            //Create message object.
            Message reply = Message.CreateMessage(MessageVersion.None, "", objError, new DataContractJsonSerializer(typeof(Error)));

            //Set the response type to json.
            HttpResponseMessageProperty responseProp = new HttpResponseMessageProperty();
            responseProp.StatusCode = statusCode;
            responseProp.Headers[HttpResponseHeader.ContentType] = "application/json";
            reply.Properties[HttpResponseMessageProperty.Name] = responseProp;

            WebBodyFormatMessageProperty formatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            reply.Properties[WebBodyFormatMessageProperty.Name] = formatMessageProperty;

            //Replies to a request message.
            requestContext.Reply(reply);
        }
    }

->Add the above AuthenticationInterceptor to the ServiceHost.

<%@ ServiceHost Language="C#" Debug="true" Service="WcfRestAuthentication.Service" CodeBehind="Service.svc.cs" Factory="WcfRestAuthentication.HostFactory"%>

using Microsoft.ServiceModel.Web;
using System.ServiceModel;

namespace WcfRestAuthentication
{
    public class HostFactory : WebServiceHost2Factory
    {
        protected override ServiceHost CreateServiceHost(System.Type serviceType, System.Uri[] baseAddresses)
        {
            //Create WebServiceHost2 object with serviceType and baseAddresses.
            WebServiceHost2 host = new WebServiceHost2(serviceType, true, baseAddresses);

            //Add AuthenticationInterceptor to host.
            host.Interceptors.Add(new AuthenticationInterceptor());
           
            //Return host object.
            return host;
        }
    }
}



Let me know, if you have any feedback. Mail me for source code. Enjoy reading my articles…
sekhartechblog@gmail.com

Wcf REST Exceptions:-

We can send the exceptions from wcf REST to  client using WebFaultException or by using WebProtocolException which comes in wcf REST starter kit.The following example demonstrates the WebProtocolException implementation.

In wcf REST starter kit we get Microsoft.ServiceModel.Web dll file which gives features like throwing exceptions and authentication.

To get the features of wcf REST starter kit in IIS hosted services you should add the factory in ServiceHost file like below.

<%@ ServiceHost Language="C#" Debug="true" Service="WcfRESTException.Service" CodeBehind="Service.svc.cs"  Factory="Microsoft.ServiceModel.Web.WebServiceHost2Factory"%>

->Create a custom exception class with property Description.
    [DataContract]
    public class CustomException
    {
        [DataMember]
        public string Description { get; set; }
    }

->Create wcf REST service with SayHello method.
[ServiceContract]
public class Service
{
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public string SayHello(string name)
        {
            //Create custom exception object with proper error description.
            CustomException objCustomException = new CustomException();
            objCustomException.Description = "error description";

            //Throw the exception.
            throw new WebProtocolException(HttpStatusCode.BadRequest, "", objCustomException, null, null);

            //Return string.
            return "Hello " + name;
        }
}
->There is no need of web.config file modification.Wcf Rest starter kit do it for you.

Let me know, if you have any feedback. Mail me for source code. Enjoy reading my articles…
sekhartechblog@gmail.com

Tuesday 3 April 2012

WebBrowser Javascript Communication In Wpf:-

Using web browser control we can display the web content.If we want to call wpf function from the javascript we have to use web browser’s ObjectForScripting property.In the following example  InvokeMeFromJavascript function is called from the javascript.
 ->Create new wpf application and add web browser control.

     <Grid>
        <WebBrowser Name="wbMain"/>
    </Grid>

->Create new class JavascriptInterface and add new method InvokeMeFromJavascript.

    [ComVisible(true)]
    public class JavascriptInterface
    {
        //MainWindow object.
        MainWindow objMainWindow;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="mainWindow">MainWindow object.</param>
        public JavascriptInterface(MainWindow mainWindow)
        {
            //Get the MainWindow object.
            this.objMainWindow = mainWindow;
        }

        /// <summary>
        /// Called from the javascript.
        /// </summary>
        /// <param name="result"></param>
        public void InvokeMeFromJavascript(string result)
        {
            //Display the result.
            MessageBox.Show("Message from javascript: " + result);
        }
    }
 
->Create new ASP.Net application and add new html page.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        function invoke() {
            //Call the web browser function.
            window.external.InvokeMeFromJavascript('Hai...');
        }
    </script>
</head>
<body>
    <input type="button" onclick="invoke();" value="Invoke" />
</body>
</html>

->In window load event set the web browser url to the above html page and set the ObjectForScripting property.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
            //Create the JavascriptInterface object.
            JavascriptInterface objJavascriptInterface = new JavascriptInterface(this);

            //Set the JavascriptInterface object to the web browser control.
            this.wbMain.ObjectForScripting = objJavascriptInterface;

            //Set the url to web browser control.
            wbMain.Source = new Uri("Your page url…");
}

Now you can call the wpf functions from javascript.


Let me know, if you have any feedback. Mail me for source code. Enjoy reading my articles…
sekhartechblog@gmail.com