Home > English > Getting something better than “Server not found.” from WCF in Silverlight

Getting something better than “Server not found.” from WCF in Silverlight

When developing applications in Silverlight it is inevitable that you will need to perform a request back to the server for data or processing. The common practice is to use Windows Communication Foundation (WCF). I find that WCF usually handles all of my needs and it works well when everything is happy and just right. However, if anything is not in its correct place, we can have tons of problems. Worse yet, we get your all time favorite message back in Silverlight stating:

“Server not found.”

Basically, WCF is telling us to go screw ourselves but in a much more politically correct way. Well there are several ways to attack this problem but I want to show you what I have come to love and use for all my projects involving WCF and Silverlight.

To give us some background, please review the following MSDN reference concerning Creating and Handling Faults in Silverlight. This article explains why we get our beloved message from WCF and what we can do about it. I think this is a must read for anybody wanting to understand what is going on and how they can go about fixing it themselves. I don’t think this is be the best solution but I do think it is a great reference. The reason for looking for something else is that I would like a solution that is a little easier to use and has less configuration required. I tend to follow this pattern because I have clients that want elegant solutions but they want it to be the least disruptive to their development process as possible.

Let’s move to the next blog post that I find very instrumental in dealing with exceptions in WCF. Oleg Sych wrote an excellent article, Simplifying WCF: Using Exceptions as Faults, back in 2008 that I believe is still very pertinent for us today. His solutions is very similar to the MSDN article that we already looked at but I believe it is more comprehensive and provides a good code base with which to use if you wanted to take his approach. I like what I read here but I still wanted something a little less intrusive from the perspective of ceremony and configuration.

This leads us to our last blog post. Here we find Jeroen Bernsen’s entry WCF ExceptionHandling in Silverlight. Like the other two articles, this post tries to solve the problem of dealing with exceptions thrown in WCF and how to get them back to the client in a friendly and easy way. If you read his post, you will see that you only need to create few objects to get our solution working and there is no need to modify your weg.config like in the other solutions. This is the reason why I like this solution the best.

I am going to provide the code below but you can also just follow along Jeroen’s post if you like.

The following class tells WCF to send fault messages with a 200 instead of a 500 response code. This change enables Silverlight to read the body of the message.

public class WcfSilverlightFaultBehavior : IDispatchMessageInspector
{
	public void BeforeSendReply(ref Message reply, object correlationState)
	{
		if (reply.IsFault)
		{
			HttpResponseMessageProperty property = new HttpResponseMessageProperty();

			// Here the response code is changed to 200.
			property.StatusCode = System.Net.HttpStatusCode.OK;

			reply.Properties[HttpResponseMessageProperty.Name] = property;
		}
	}

	public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
	{
		// Do nothing to the incoming message.
		return null;
	}
};

Next we have a sealed class that basically creates our attribute for using the previous class.

public sealed class WcfSilverlightFaultBehaviorAttribute : WcfBehaviorAttributeBase
{
	public WcfSilverlightFaultBehaviorAttribute()
		: base(typeof(WcfSilverlightFaultBehavior))
	{
	}
};

As you can see this is our attribute definition. We are deriving from a base class which we will review shortly.

The next class implements the IErrorHandler and allows us to handle WCF exceptions and package them in a way that we can still read on the client side.

public class WcfErrorBehavior : IErrorHandler
{

	void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
	{
		try
		{
			// Add code here to build faultreason for client based on exception
			FaultReason faultReason = new FaultReason(error.Message);
			ExceptionDetail exceptionDetail = new ExceptionDetail(error);

			// For security reasons you can also decide to not give the ExceptionDetail back
			// to the client or change the message, etc
			FaultException faultException =
				new FaultException(exceptionDetail, faultReason,
					FaultCode.CreateSenderFaultCode(new FaultCode("0")));

			MessageFault messageFault = faultException.CreateMessageFault();
			fault = Message.CreateMessage(version, messageFault, faultException.Action);
		}
		catch
		{
			// Todo log error
		}
	}

	///
	/// Handle all WCF Exceptions
	///
	bool IErrorHandler.HandleError(Exception ex)
	{
		try
		{
			// Add logging of exception here!
			Debug.WriteLine(ex.ToString());
		}
		catch
		{
			// Todo log error
		}

		// return true means we handled the error.
		return true;
	}

};

IErrorHandler has to methods that we must implement: ProvideFault and HandleError. You can read more on this interface here.

HandleError is just a boolean method that indicates whether or not a Fault message has already been generated (true) or for WCF to do its normal processing (false).

ProvideFault is a void method that allows us to package the fault exactly how we want to. This is very nice and gives us all the flexibility we need to customize or change how we wish to package our faults.

Next we have a sealed class that basically creates our attribute for using the previous class.

public sealed class WcfErrorBehaviorAttribute : WcfBehaviorAttributeBase
{
	public WcfErrorBehaviorAttribute()
		: base(typeof(WcfErrorBehavior))
	{
	}
};

As you can see this is our attribute definition. We are deriving from a base class which we will now review.

public abstract class WcfBehaviorAttributeBase : Attribute, IServiceBehavior
{
	private Type _behaviorType;

	///
	/// Constructor
	///
	/// <param name="typeBehavior" />IDispatchMessageInspector, IErrorHandler of IParameterInspector
	public WcfBehaviorAttributeBase(Type typeBehavior)
	{
		_behaviorType = typeBehavior;
	}

	void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription,
		System.ServiceModel.ServiceHostBase serviceHostBase,
		System.Collections.ObjectModel.Collection endpoints,
		System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
	{
	}

	void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription,
		System.ServiceModel.ServiceHostBase serviceHostBase)
	{
		object behavior;
		try
		{
			behavior = Activator.CreateInstance(_behaviorType);
		}
		catch (MissingMethodException e)
		{
			throw new ArgumentException("The Type specified in the BehaviorAttribute " +
				"constructor must have a public empty constructor.", e);
		}
		catch (InvalidCastException e)
		{
			throw new ArgumentException("The Type specified in the BehaviorAttribute " +
				"constructor must implement IDispatchMessageInspector, IParamaterInspector of IErrorHandler", e);
		}

		foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
		{
			if (behavior is IParameterInspector)
			{
				foreach (EndpointDispatcher epDisp in channelDispatcher.Endpoints)
				{
					foreach (DispatchOperation op in epDisp.DispatchRuntime.Operations)
						op.ParameterInspectors.Add((IParameterInspector)behavior);
				}
			}
			else if (behavior is IErrorHandler)
			{
				channelDispatcher.ErrorHandlers.Add((IErrorHandler)behavior);
			}
			else if (behavior is IDispatchMessageInspector)
			{
				foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
				{
					endpointDispatcher.DispatchRuntime.MessageInspectors.Add((IDispatchMessageInspector)behavior);
				}
			}
		}

	}

	void IServiceBehavior.Validate(ServiceDescription serviceDescription,
		System.ServiceModel.ServiceHostBase serviceHostBase)
	{
	}

};

As you can see in the code, this class derives from Attribute so that we can use it as an Attribute and also implements the IServiceBehavior interface. By implementing the IServiceBehavior interface, we no longer need to do any ceremony in the weg.config file. We have a single Type variable that allow us to be flexible from our classes that derive from us. As long as they pass in the type of behavior we handle the rest in the base class. IServiceBehavior has three methods: AddBindingParameters, ApplyDispatchBehavior, and Validate. You can read more on this interface here.

AddBindingParameter is used to pass to a binding element the custom information for the service so that it can support the service correctly.

ApplyDispatchBehavior is used to change run-time property values or insert custom extension objects.

Validate is used to examine the description and validate that the service can execute properly.

The method that we are interested in is the ApplyDispatchBehavior. First we try to create an instance of the underlying type that was passed in the constructor. Next we iterate over all of the ChannelDispatchers. Based on what type of behavior object we have, we determine what needs to happen in the current iteration of the ChannelDispatcher.

All of these classes will live on the server side and will need to be accessible from your WCF service.

Here is what you need to do to mark up your service:

[WcfErrorBehavior()]
[WcfSilverlightFaultBehavior()]
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService : ITestService
{
	public WcfErrorBehaviorAttribute()
		: base(typeof(WcfErrorBehavior))
	{
		public int DoSomething()
		{
			...
		}
	}
};

Congratulations, you are done! You can now have all of those nasty exceptions from WCF finally show up in your Silverlight client. Here is a sample screen shot of an exception thrown due to bad username and password to SQL Server before we apply the attributes:

Now with our attributes applied:

This makes all the difference! Hope this helps and again I want to stress that the credit of this blog goes to the articles that we previously mentioned.

Advertisements
  1. Alfredo
    May 17, 2011 at 2:37 pm

    Great!!!! You saved me!

  1. April 8, 2011 at 3:19 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: