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

Wednesday, February 8, 2012

Generic Error Handling in WCF REST

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

1) Implement the IErrorHandler interface

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

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

public class CustomMessageBehavior : IEndpointBehavior

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

3) Configure the dispatcher in the Web.Config

Job done!!

Wednesday, October 19, 2011

Consume WCF REST service in F#

Today I successfully implemented the code for consuming WCF REST service in F#. Funny part here is that, this is my first program in F#.. LOL

Ok.. Here is the code for consuming WCF REST in F#.

module FSModule

#light

open System
open System.Text
open System.Net
open System.IO
open System.Web

// F# uses indenting to define scope. So ensure that you indent properly to get it working
let GetDataFromRest =
     let buffer = Encoding.ASCII.GetBytes("<HelloService_SayHello><input>Hello from F#</input></HelloService_SayHello>") //This is needed if its a POST call
     let req = WebRequest.Create(new Uri("http://localhost/HelloService.svc/SayHello")) :?> HttpWebRequest
     req.Method <- "POST"
     req.ContentType <- "application/xml" //Use accordingly XML or JSON
     req.ContentLength <- int64 buffer.Length
     let reqSt = req.GetRequestStream()
     reqSt.Write(buffer,0,buffer.Length)
     reqSt.Flush()
     req.Close()

     let res = req.GetResponse () :?> HttpWebResponse
     let resSt = res.GetResponseStream()
     let sr = new StreamReader(resSt)
     let x = sr.ReadToEnd()
     sr.Close()
     x.ToString()

Done... To invoke this, you can either use F# or C# or even VB.NET :)

F#

let result = GetDataFromRest()
printfn result

C#

string result = FSModule.GetDataFromRest()

Tuesday, August 23, 2011

Getting OperationContract name in WCF MessageDispatcher

There may be times where you need to identify the OperationContract name in WCF MessageDispatcher and do some processing based on that. Here is how you can do that;

In case of WCF Endpoint

In the AfterReceiveRequest method, do the following to get the Operation name;

MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
Message originalMessage = buffer.CreateMessage();
XmlDictionaryReader xmlDict = orginialMessage.GetReaderAtBodyContents();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlDict.ReadOuterXml());

string action = doc.DocumentElement.Name; //here you will get the OperationContract name

In case of WCF REST Endpoint

In the AfterReceiveRequest method, do the following to get the Operation name;



MessageProperties props = request.Properties;
string action = props["HttpOperationName"].ToString(); //here you will get the OperationContract name

Dreaded System.Security.SecurityException: Security Error... Silverlight and WCF REST

Recently I faced the dreaded System.Security.SecurityException: Security Error.. while developing the SL4 application consuming the WCF REST service. After a lot of trials fixed this dreaded issue. So thought of sharing my experince on SL4 consuming WCF REST service.

1) Ensure that crossdomain.xml and clientaccesspolicy.xml files are available in C:\Inetpub\wwwroot folder.
2) If you are using HTTPS, ensure the following;
  • Ensure clientaccesspolicy.xml contains explicit <domain uri="https://*"></domain>
  • Ensure only SSL access is enabled. The SL app and WCF REST service should not be accessible in HTTP mode.
  • Ensure crossdomain.xml contains <site-control permitted-cross-domain-policies="master-only"/> <allow-access-from domain="*" />
Do IISRESET. Then you should be able to get rid of this dreaded error.

Thursday, August 18, 2011

WCF REST - Two things made me wondering 2 or 3 days (stream.Position = 0 and WebMessageBodyStyle.Bare

Recently I developed one WCF REST service which has to be consumed in Silverlight 4.0. Since it is a WCF REST service, we will be dealing with JSON or XML format. But my customer wanted the support for object/contract as well [Don't ask me why not use simple WCF :) ]. So I did implement Datacontract Serialization. I was facing these 2 issues and looking throught web for answers. Finally after 2 days, the solution just struck in my mind.

Issue 1:
Root element is missing

I had the following code for deserialization.

XDocument doc = XDocument.Load(result);
MemoryStream str = new MemoryStream();
doc.Save(str);

DataContractSerializer serializer = new DataContractSerializer(typeof(EntityTypesCollection));
EntityTypesCollection typeColls = (EntityTypesCollection)serializer.ReadObject(str); //I was receiving the error "Root element is missing" here

I kept checking, what am I doing wrong... Finally after some brain crunches, finally figured out that we need to position the stream to 0.
str.Position = 0;

Voila, Issue 1 solved. Now the second issue.

Issue 2:
Response XML was wrapped like this;
<operation_response><operation_result>[Actual Result]</operation_result></operation_response>

I found a lot of complicated approaches to the simple 2 lines of deserialization code. Like filtering out the XElements from the response and through LINQ building back the contract.

Suddenly I noticed that, I mentioned the BodyStyle as WebMessageBodyStyle.Wrapped. This when I changed to WebMessageBodyStyle.Bare, Voila the response XML just came out like I wanted. Finally, the simple 2 lines of deserialization code worked..

So folks, be aware these 2 issues when you work witn WCF REST and serialization/deserialization.