Posts Tagged ‘ WCF ’

WCF in Azure – Lessons Learned

Recently I’ve been trying to get my WCF services working in Azure, this post shares some lessons learned. Some of these lessons will likely be obvious for those of you familiar with hosting WCF services in IIS, however I personally haven’t written web sites for about 5 years so even if my memory served me well (which often it doesn’t) things have changed somewhat.

WebRole vs WorkerRole

Probably one of the first questions you will run into is ‘which role do I choose to run my services in?’

WebRole – Choose this if you want your services hosted in IIS
WorkerRole – Choose this if you want to spin up your own ServiceHost instances.

Before trying to make my services work in Azure I was hosting them in a simple Console app and was therefore creating my own ServiceHost instances. So at first I tried getting my existing code working in a WorkerRole.

I could make it work in the local devfabric but I couldn’t make it work in the cloud, the worker role seemed to start ok but the endpoints were not being exposed publicly, or maybe they failed to be created?

I’m still not sure why because I changed tactics and changed my services run in IIS. The main reason for this is I figure running the services in IIS will be more robust and will provide better reporting.

My change of tactics brought on the next problem…

Getting WebRole Working with Service implementation in Different Project

My service implementation code was in it’s own separate project, the service contracts were in another project as well. All WCF in Azure examples I found had the service, the contract and .svc in the WebRole. I wanted to keep my existing structure and it turned out to be very easy to do.

All that was needed was to put some .svc files (one for each endpoint) into the WebRole project and voila, endpoints available in the devfabric and in the cloud.

Contents of the .svc files….

<%@ ServiceHost Language="C#" Debug="true" Service="ServiceNamespace.ServiceName" %>

Easy!

Note that the .svc files must be in the root directory of the WebRole project as Azure does not have a concept of Virtual Directories.

Ports

I still need to more play time to understand how this works more clearly. However what I did find is that if when I changed the port from 80 to 81 my endpoints were no longer visible in the cloud (they were visible in the devfabric).

Cloud Cover – Channel 9

I’d say this is an invaluable resource, lots of useful Azure info for developers….

Making Azure Services Available to Silverlight Clients

This is another thing that turned out to be quite simple.

To make any WCF service available to an SL client you must have a crossdomain.xml file. Normally you need to put this file in the IIS root directory, the way to do this for Azure is to simply drop the file into the root directory of the WebRole project.

Easy! Though I’d suggest host the services in ‘non-azure’ IIS and get it all working before switching to Azure. The crossdomain.xml thingy can be tricky, I’ve posted about wrestling with crossdomain.xml before.

Service Constructor

My web services were using an IoC container for various things and so the constructor of each service took a container. For an IIS hosted service you need to have a parameterless constructor so I had to make some semantic changes to the code to allow for this.

Summary

It took a bit of trial and error to get things working but overall I’d say most of the challenges I faced were more about my lack of knowledge rather than any real problems with Azure. I like it….and am looking forward to learning more ūüôā

SVCUTIL and ServiceContracts

Shared ServiceContract Library

I had what I thought was a simple plan, create a server side (WCF) sln and a client side sln then from both of them reference the same BusinessObject (Biz) library and ServiceContract library.

What I wanted to do was use svcutil.exe to generate the client side implementation of the contract for me, so when any of the service contracts changed all I had to do was run a batch file which basically ran svcutil.

The Problem

So when you do a ‘right click, add service reference’, tick the box to re-use the Biz and ServiceContract libraries, what happens is the Biz objects are not generated (good, that was expected) but the contracts ARE still generated (am I missing a simple check box somewhere??).

I don’t want the contracts to be generated as it means I now have two versions of the same contract.

If you use svcutil.exe to generated the metadata and then the proxy code, by providing a few of the right switches you get the same result as ‘add service reference’. Ok good, now that I’m using the cmd line utility I will now have the power to tailor the generated code to my exact measures….not quite. Unless I’m missing somethings obvious (which is likely I’ll admit) there is not any switch to tell svcutil to NOT generate the ServiceContracts. Yes I am using the /r: switch to provide the assembly that contains the contracts…

So I’m thinking, unless you are willing to accept and allow there to be two versions of your service contract (which actually is very common, anyone using VS right click, ‘add service reference’ will have this setup…thus the need to regularly update service reference) then really it is not possible to use svcutil.exe.

The Solution

Well I hope to come back and update this in the near future with the approach we end up choosing. For now though, this post looks like a good ‘leg up’ and is certainly worth a read. I’ll be exploring that idea and a few others and report back….

Why Bother?

Why go through the hassle, why not just use the old, ‘right click add service reference’? Well, every WCF ‘expert’ I know of says that approach is the beginners way of creating your WCF service proxies, either in their blogs or .net rocks episodes etc. It is certainly very quick but the generated code is overly verbose and as it is generated code you have less control over the way it works.

Share your interfaces
Extreme WCF

WCF the manual way…The RIGHT way
WCF Standards from iDesign

MARS to the Rescue

WCF Concurrency

When you create a WCF web service you most likely want it to have a ConcurrencyMode of ‘Multiple‘ so that your service will scale. Check this out if you need some convincing on this.

Here’s an error I recently ran into when multiple threads started hitting my database:

There is already an open DataReader associated with this Command which must be closed first.

I’m using enterprise libraries Data Access Block and my DB is an SQL Server 2005. For once the fix was really easy, I just had to change my connection string to include MultipleActiveResultSets=True.

That’s it!

Check out this link that helped me figure it out and this MSDN article more details.

A nice easy immediate fix for a problem I thought would require some re-engineering. Why can’t all problems be like that ūüėź

Silverlight Communication Exception

Cross Domain Access

I hope this article can save someone some of the pain I have just experienced trying to get my Silverlight 2 app talking to my ‘cross domain’ WCF service (that is hosted in a console app).

I’ll leave discussing why I didn’t just host my SL app with my WCF service and avoid all of hassles until the end of the article. I’m also not going to discuss how to set this up, I’ve provided links to articles that I found useful for this.

The Error

An error occurred while trying to make a request to URI ‘http://localhost:4522/MyService&#8217;. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. Please see the inner exception for more details.

Existing Blog Articles

I found many useful articles, many of them with at least one little extra thing to try, these are the most useful:-

  1. Silverlight forum discussion on the cross domain policy
  2. Great step by step article to showing how to setup an SL project to consume a WCF service hosted in a Console (I thought this for sure would have all my answers)
  3. MSDN has what looks like the content needed for both the crossdomain.xml and clientaccesspolicy.xml (but it’s not quite right).
  4. Interesting discussion on crossdomain.xml and clientaccesspolicy.xml.
  5. StackOverflow thread.
  6. Cross-domain Policy File Specification. This is what eventually led to me trying something that finally it all working!

All of this (and a number of others I looked at) helped, they really are great articles and I could see comments at the bottom saying things like “thanks got it working now!”. Problem was I had very closely checked and rechecked what I had done vs what was in these blogs and still I kept getting the error!

The Solution

After many hours of trying many different things I came across the¬† and tried an extra little line and voila…working service! That’s a great feeling isn’t it…when you’ve been trying to find a solution to a problem for hours…and hours…you know there must be an answer but everything you try should work but dammit it doesn’t…and then…suddenly…you tick some obscure buried box somewhere and the universe is back to the way it should be…

anyway I digress…this is what MSDN says you should put in your crossdomain.xml file

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

This is what actually works!

<?xml version=”1.0″?>
<!DOCTYPE cross-domain-policy SYSTEM “http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd”&gt;
<cross-domain-policy>
<allow-access-from domain=”*” />
<allow-http-request-headers-from domain=”*” headers=”SOAPAction” />
</cross-domain-policy>

I’ve highlight the important line. You’ll notice that the MSDN sample has headers=”*”,¬† this simply does not work. In fact if I add the extra line that makes it work and headers=”*” is still in the first line, then everything still fails. So delete headers=”*” and add the new line.

Another thing to note, I noticed amongst the articles posted on this subject that if you have a clientaccesspolicy.xml file then you don’t need a crossdomain.xml file. Maybe this is true with their setup but I have found that you must have a crossdomain.xml file, in fact after a bit more trial and error I have come to the conclusion that the clientaccesspolicy.xml just does NOT WORK! At least for me. If my SL app finds it then I get the error…no matter what I put in there. Only when my service does NOT return it but DOES return a crossdomain.xml file with the correct format above does it work.

Maybe this was all a peculiarity of hosting the WCF service inside a console app? Not sure. Don’t care at this point, the thing finally works…yay!

Do I Need a File

You can choose to create the required xml in code or you can have the physical file, your choice. Most of the examples just create it in code. It’s not the existence of the file that matters, just the contents and the web GET request must be able to retrieve the content.

By the way, all examples I have seen (including mine) leave your service completely unsecured. I strongly recommend learning how to set these policy files up properly so that your service isn’t nakedly exposed to the outside world.

What Didn’t Help

In case you have some other problem, these are the things I can say didn’t make a difference. Once I got it working I tried with and without these things and my cross domain connection still worked.

1. Does setting the ContentType help?

WebOperationContext.Current.OutgoingResponse.ContentType = “application/xml”;

Nope doesn’t matter.

2. Some blog samples show a return type of ‘Message’ and others a return type of ‘Stream’ for the method that this attribute goes on:-

[WebGet(UriTemplate = “ClientAccessPolicy.xml”, BodyStyle = WebMessageBodyStyle.Bare)]

Does the return type matter? Nope doesn’t matter (well I only tried these two types, I guess it should be one of these)

3. I read you should decorate your services with this attribute…is it needed?

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

Nope, didn’t help. (note that it didn’t help with THIS problem, I’m sure there is some good reason for why you would use it)

So Why Bother With Cross Domain?

  1. In an enterprise environment it is very likely that you will need to call a number of different services. Sure you could have one WCF service that is just for your SL app that then goes off and talks to all of the disparate services for the SL app but that just doesn’t seem right to me. (just an opinion and hey in some cases it probably is appropriate…)
  2. Isn’t it all about separation of concerns? When I’m working on server side code I only want server side projects in my solution and vice versa for client solutions. This keeps the number of projects in my solution down…thereby keeping Visual Studio (and resharper) at least a little bit responsive.
  3. When the server is working I just want it running. I don’t want to have to compile and start the server every time I want to debug something in my client code.

Hmmm, I’m sure there’s other reasons but I can’t think now given it’s 3am ūüė¶

Anyway I hope this helps someone save some time ūüôā

WCF Concurrency Mode Tip

Don’t Keep the Default Setting!

When you mark your WCF endpoints with the ServiceBehaviour attribute, are you setting the ConcurrencyMode to Multiple?

The default is Single, meaning only a single thread will invoke the instance method on the reciever object. This may be desirable in certain situations however if you want your service to be scalable then Multiple would be the recommended choice.

Checkout this great article that offers a great explanation of the differences…this is an excerpt from the ‘thoughts’ at the end of the article

ConcurrencyMode should be set to Multiple. In my view, if a receiving application is going to scale, it must set concurrency mode to Multiple. If single or Reentrant are used, messages stack up as they wait to be processed, and that is badness.”

WCF CommunicationException: Error Serializing Parameter

WCF Serialization Issue

I really need to learn more about WCF.

I recently had a problem with serializing my business objects when trying to send to a WCF web service. The fix was the most simple thing in the world but it took me a considerable amount of time to discover it because I thought the problem was something else which led to a whole bunch of unnecessary changes which made matters worse…you know how the story goes ūüôā

This is the lovely errror I was getting when calling my Save method on my web service:-

System.Runtime.Serialization.SerializationException:¬†Type¬†‘System.DelegateSerializationHolder+DelegateEntry‘¬†with¬†data¬†contract¬†name¬†‘DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System’¬†is¬†not¬†expected.¬†Add¬†any¬†types¬†not¬†known¬†statically¬†to¬†the¬†list¬†of¬†known¬†types¬†–¬†for¬†example,¬†by¬†using¬†the¬†KnownTypeAttribute¬†attribute¬†or¬†by¬†adding¬†them¬†to¬†the¬†list¬†of¬†known¬†types¬†passed¬†to¬†DataContractSerializer.

Ok, so

  1. what was I trying to do
  2. what caused the problem
  3. and what was the (annoyingly simple) fix??

The Setup

First of all, I setup up a pretty much ‘out of the box’ WCF web service with a couple of simple changes shown here (You can download the sample project (with some dummy biz objects etc) here.)

Changes to WCF configuration

Changes to WCF configuration

(The relevant part is I’m reusing the types in the Biz assembly client side and server side.)

So just briefly, architecturally I have a Biz project which is referenced by my WCF Service and my client side Service Access Layer (SAL). My unit Test project is my ‘client’ in this case and is referencing both the SAL and Biz projects.

What I was trying to do was save a ‘Dog’ (one of my biz classes) using the web service. This Dog class looks something like this:

Dog Biz layer class

Dog Biz layer class

The Problem

So what, in this most simple of classes, was causing my serialization issue? The combination of two things…

The Cluprits

  1. The [Serializable] attribute
  2. and the FetchingBall event

When I create a new Dog and do NOT add a handler for FetchingBall, the Dog serialized to and from the WCF service no problems at all. Once you add an event handler….boom, the nice SerializationException occurs.

Now my ‘real’ biz objects implement INotifyPropertyChanged so 99% of the time there will be handlers and so 99% of the time they would fail to be serialized…not particularly useful!

The Fix

Mark your object with the [DataContract] attribute.

Done!

Well Ok you also need to now mark all of your properties/fields that you want to be included in the serialization with the [DataMember] attribute as using the DataContractSerializer is an ‘opt-in’ approach.

You can take off the [Serializable] attribute or you may have them both. Personally I want my Biz objects to be serializable in case I want to save them client side.

Extra Notes

If you want to see this in action just download the test project. The first two tests in Tests.cs are the important ones. It is currently setup so the second one will fail (as it registers a handler for the event).

Try it and then try uncommenting the [DataContract] attribute on the Dog class, then run them again and the second one should also work!