Error when Behaviour Extension types are not fully qualified

April 23, 2008 at 12:58 pm | Posted in WCF | Leave a comment

Custom behaviour extensions are a great way to customise service behaviour such as implementing exception shielding as described here in Rory’s post  or message validation using the Microsoft Enterprise Library Validation Application block.

I recently implemented a custom WCF behaviour extension for shielding exceptions when I came across the following cryptic exception.

“An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.”

image

While the message was somewhat cryptic, it pointed me to the service behaviour were I realised I had specified the incorrect version on the type attribute.

Steps

1. Create new behaviour extension. My extension shielded and traced certain exceptions using the IErrorHandler.
2. Use SVC Configuration Editor to plug the extension in. It added the following configuration as expected.

<system.serviceModel>

  <extensions>

    <behaviorExtensions>

      <add name=ErrorHandlerBehavior

           type=Wcf.Demo.Service.ErrorHandlerElement, Wcf.Demo.Service,

                 Version=1.0.0.0, Culture=neutral, PublicKeyToken=null />

    </behaviorExtensions>

  </extensions>

</system.serviceModel>

3. Ran integration unit tests that passed.
4. The service build was integrated into TeamBuild which happen to automatically update my AssemblyInfo version files.
5. As soon as a TeamBuild kicked off and the assembly version changed, I received the cryptic error.
6. I realised I had an incorrect version configured in the web.config so I replaced the fully qualified type with:

<behaviorExtensions>

  <add name=ErrorHandlerBehavior

       type=Wcf.Demo.Service.ErrorHandlerElement, Wcf.Demo.Service />

</behaviorExtensions>

7. Ran tests and failed.

After attempting to diagnose the issue using tools such as Fusion Log Viewer, I checked Google (which I should have done first) and came across several posts also identifying the issue – including a closed and unresolved issue on Microsoft Connect. This is the second time round I have been to Microsoft Connect regarding a bug and it does not look like they will resolve this anytime soon.

A Way Forward

At this stage since there is no fix, a tedious workaround will have to be to get TeamBuild to modify the web.config and update the version number of the behaviour extension when applying a new version – which in my case is for every CI build triggered by a code checkin.

Links

Advertisements

Debugging WCF Clients and Services

April 15, 2008 at 2:09 pm | Posted in Visual Studio, WCF | 1 Comment

Debugging WCF services from the client through to the service is much easier when attaching the debugger to either the service or both the client and the service.

In the past, I have debugged services by firing up the client application and manually attaching to the WCF Service Host – which in this case is the ASP.NET worker process. This process is quite cumbersome.

Visual Studio has feature that supports attaching to multiple projects when starting up. 

In this example, I have a WCF service hosted in IIS which lives in the Wcf.Demo.IisServiceHost project. I also have a Wcf.Demo.TestHarness project which calls the service. I want to be able to attach the debugger to both the client and service by simply pressing F5.

Steps

1. Right click on the solution and select “Set StartUp Projects…“.

image

2. In the StartUp tab, select “Multiple startup projects” and select the projects you want to start up.

3. On the Action of the selected projects, select “Start” to start with the debugger attached.

image

If you now run (F5) the application, it will fire up both the Test Harness and a Internet browser to the service virtual directory. You can disable this.

4. Go to the Web project properties for the WCF web project and select “Don’t open a page“.

 image

Now when you hit F5, the test harness will launch and the debugger will be attached to both processes.

image

Handling Fault Contracts

April 15, 2008 at 1:35 pm | Posted in WCF | 1 Comment

Today I had an issue with catching Fault Contracts thrown from my WCF service. Every FaultException type raised by the service (excluding Communication Exceptions) were caught by the client as a FaultException instead of the expected FaultException<T>.

The issue was that I defined the FaultContractAttribute(type) on the operations in the Service Implementation class instead of on the Service Contract’s (Interface class) operations.

A service should always handle/shield exceptions and throw them as either a FaultException or a FaultException<T>. These types will not cause the channel to be faulted. I recommend defining Fault Contracts to convey information about the problem to client applications, and DO NOT provide the internal exception such as service stack traces. I’ll blog a post in the future on my recommendations service exception shielding patterns.

To catch Fault Contract types on the client, make sure that each Fault Contract type you require for that service operation, ensure that the FaultContractAttribute(Type) is specified.

Service code

Error Handler

The following code is implemented in the IErrorHandler class and is based on Rory’s post on Implementing IErrorHandler . In this example, all exceptions in my WCF service are changed to FaultException<ServiceFault>.

public void ProvideFault(Exception error,
                         MessageVersion version,
                         ref Message fault)
{
    // Return a 'ServiceFault' Fault Contract
    ServiceFault faultDetail = new ServiceFault("An error occured");

    // Construct FaultException with Fault Contract and FaultReason
    FaultException<ServiceFault> faultException = 
        new FaultException<ServiceFault>(faultDetail, 
        new FaultReason("FaultReasonText"));

    // Construct MessageFault to return.
    MessageFault messageFault = faultException.CreateMessageFault();

    fault = Message.CreateMessage(version, 
        messageFault, 
        faultException.Action);
}

Service Contract

Now this is where I went wrong. I did not decorate my service contract with the FaultContractAttribute. This attribute accepts a Type parameter which should be the type of the Fault Contract.

namespace DJ.Wcf.Demo.ServiceContracts

{

    [ServiceContract(Name = “DJ.Wcf.Demo.DemoService”, Namespace = “DJ.Wcf.Demo”)]

    public interface IDemoService

    {

        [OperationContract]

        [FaultContract(typeof(ServiceFault))]

        DemoData GetDemoData(Int32 demoId);

    }

}

Service Fault Contract code

Here is a defined Fault Contract used by the service and client. Being a Data Contract, it could contain a collection of error messages e.g. a collection of validation error messages for a set of fields that were incorrectly set on the service operation.

using System;
using System.Runtime.Serialization;

namespace Wcf.Demo.ServiceContracts
{
    [DataContract]
    public class ServiceFault
    {
        public ServiceFault(String message)
        {
            Message = message;
        }

        [DataMember]
        public String Message
        {
            get;
            set;
        }
    }
}

Client code

The service calling code below shows several catch statements. When the service passes back a ServiceFault, it will be caught in: catch (FaultException<ServiceFault>. All other FaultException and FaultException<T> types will be handled by: catch (FaultException fault) block.

Unhandled service exceptions will be raised and caught in:  catch (CommunicationException cex) which will cause the WCF channel to fault, thus forcing the client to create a new channel.

try
{
    using (ChannelFactory<IDemoService> channel = 
        new ChannelFactory<IDemoService>("DemoService"))
    {
        IDemoService service = channel.CreateChannel();
        channel.Open();

        return service.GetPerson(42);
    }
}
catch (FaultException<ServiceFault> serviceFault)
{
    MessageBox.Show(serviceFault.Message);
}
catch (FaultException fault)
{
    MessageBox.Show("Unknown Service Fault");
}
catch (TimeoutException tex)
{
    MessageBox.Show("Service call timed out. Please retry.");
}
catch (CommunicationException cex)
{
    MessageBox.Show("Unknown Communications exception occured.");
}

Controlling the serialized order of WCF Data Contract Members

April 12, 2008 at 1:08 am | Posted in WCF | Leave a comment

There are situations where you wish to specify the order of fields when they are serialized. I believe that a good designed service should not specify the ordering of fields nor should a service consuming application expect it..

In some applications, it is useful to know the order in which data from the various data members is sent or is expected to be received (such as the order in which data appears in the serialized XML). Sometimes it may be necessary to change this order…..

Recently, I started using ReSharper (now I’m hooked). I used it to reformat my code based on a style which alphabetically reordered all the properties in the data contracts. The changes were checked in, unit tested, integrated united tested and deployed to Test. The changes I made broke the client application as the application was relying on the serialised Xml to be in a certain order. In my opinion this is definately not service design.

I was told about the DataMemberAttribute.Order property by Rory and reluctantly added the Order property to every data contract member. This change still broke the client application. The reason was that the client application was using the XmlSerializer which does not change its behvaior with the new DataMember attributes.

The solution was to serialise a Data Contract using the DataContractSerializer. I still consider this to be a dirty solution because the ordering of the properties must always be the same, otherwise the consumer may break.

Data Contract

The following data contract lists fields in alphabetical order. The Order attribute forces the DataContractSerializer to output elements in the requested order.

    [DataContract]

    public class Person

    {

        [DataMember(Order = 2)]

        public Int32 Age { get; set; }

 

        [DataMember(Order = 0)]

        public String FirstName { get; set; }

 

        [DataMember(Order = 1)]

        public String LastName { get; set; }

 

    }

 

Serializing using the XmlSerializer

    Person person = new Person { Age = 25, FirstName = “Bob”, LastName = “Jane” };

    using (FileStream writer = new FileStream(“Person.xml”, FileMode.Create))

    {

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));

        xmlSerializer.Serialize(writer, person);

        writer.Close();

    }

The XML is written in the order the fields are defined in the class.

  <?xml version=1.0?>

  <Person xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance

          xmlns:xsd=http://www.w3.org/2001/XMLSchema>

    <Age>25</Age>

    <LastName>Jane</LastName>

    <FirstName>Bob</FirstName>

  </Person> 

Serializing using the DataContractSerializer

    Person person = new Person { Age = 25, FirstName = “Bob”, LastName = “Jane” };

    using (FileStream writer = new FileStream(“Person.xml”, FileMode.Create))

    {

        DataContractSerializer contractSerializer = new DataContractSerializer(typeof (Person));

        contractSerializer.WriteObject(writer, person);

        writer.Close();

    }

 

The XML is written in the expected order defined by the Order property, even though the data contract defines in another order.

  <Person xmlns=http://schemas.datacontract.org/2004/07/Wcf.Demo.ServiceContracts

          xmlns:i=http://www.w3.org/2001/XMLSchema-instance>

    <FirstName>Bob</FirstName>

    <LastName>Jane</LastName>

    <Age>25</Age>

  </Person>

 

So if you require a specific order to be xml serialized, make sure you use the DataContractSerializer.

CA1304 – Must specify CultureInfo when using FaultReason

April 9, 2008 at 12:36 pm | Posted in Code Analysis, Visual Studio, WCF | 1 Comment

Today I came across the following issue when running Code Analysis over my WCF Error Shielding solution.

CAError

Because I have “Treat Warnings as Errors” enabled for all projects, Code Analysis fails.

Rory Primrose has recently blogged a very nice Error Handling solution which have implemented in a WCF service. As soon as I implemented the solution and specified to return a custom Fault Contract, WCF returned an exception indicating that the “FaultReason” was not provided. So I constructed a new FaultReason, and passed it in to the FaultException(Fault, FaultReason).

The FaultReason class contains a set of System.ServiceModel..::.FaultReasonText objects, each of which contains a description of the fault in a specific language.

Sample

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)

{

// Return a ‘ServiceFault’ Fault Contract

ServiceFault faultDetail = new ServiceFault(“An error occured”);


// Construct FaultException with FaultContract and FaultReason

FaultException<ServiceFault> faultException =

new FaultException<ServiceFault>(faultDetail, new FaultReason(“FaultReasonText”));


MessageFault
messageFault = faultException.CreateMessageFault();

fault = Message.CreateMessage(version, messageFault, faultException.Action);

}

I compiled the code in Debug which was successful. I then switched on Code Analysis and it raised CA1304 : Microsoft.Globalization. The Code Analysis rule made sense to ensure I was using CultureInfo for the reason text.

However, the FaultReason does not provide any ‘public‘ constructor overrides to accept the CultureInfo. It does however provide an internal FaultReason(string text, CultureInfo cultureInfo) constructor.

FaultReason

After the help of Rory who confirmed with David Kean from the Code Analysis Team that this was a bug, I submitted feedback to Microsoft Connect.

You can keep track of this bug here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=337431&wa=wsignin1.0

In the meantime, I have suppressed this CA rule in my GlobalSupressions.cs for the project.

Blog at WordPress.com.
Entries and comments feeds.