Migrating ASP.NET Web Services to WCF
27/11/2008
I am currently in the middle of a project where we are migrating a (large) amount of web services built on top of ASP.NET in .NET 2.0 (commonly referred to as ASMX Web Services) over to the Windows Communication Foundation (WCF) platform available in .NET 3.0.
The primary reason we want to do that, is because we would like to take advantage of the binary message serialization support available in WCF to speed
up communication between the services and their clients. This same technique was possible in earlier versions of the .NET Framework thanks to a technology called Remoting, which is now superceded by WCF. In both cases it requires that both the client and server run on .NET in order to work. But I digress.
Since the ASMX model has been for a long time the primary Microsoft technology for building web services on the .NET platform, I figured they must have laid out a nice migration path to bring all those web services to the new world of WCF. It turned out, they did!
The quick way
If you built your ASMX web services with code separation (that is, all programming logic resided in a separate code-behind file instead of being embedded in the ASMX file) it is possible to get an ASMX web service up and running in WCF pretty quickly by going through a few easy steps:
- Your WCF web service class no longer inherits from
the System.Web.Services.WebService class so remove it. - Change the System.Web.Services.WebService attribute on the web service class to the System.ServiceModel.ServiceContract attribute.
- Change the System.Web.Services.WebMethod attribute on each web service method to the System.ServiceModel.OperationContract attribute.
- Substitute the .ASMX file with a new .SVC file with the following header:
<% @ServiceHost Service="MyNamespace.MyService" %>
- Modify the application configuration file to create a WCF endpoint that clients will use to send their requests to:
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="MetadataEnabled"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="MyNamespace.MyService" behaviorConfiguration="MetadataEnabled"> <endpoint name="HttpEndpoint" address="" binding="wsHttpBinding" contract="MyNamespace.IMyService" /> <endpoint name="HttpMetadata" address="contract" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost/myservice" /> </baseAddresses> </host> </service> </services> </system.serviceModel>
- Decorate all classes that are exchanged by the web service methods as parameters or return values with the System.RuntimeSerialization.DataContract attribute to allow them to be serialized on the wire.
- Decorate each field of the data classes with the System.RuntimeSerialization.DataMember attribute to include it in the serialized message.
Here is a summary of the changes you’ll have to make to your ASMX web service:
| Where the change applies | ASMX | WCF |
| Web service class inheritance | WebService | - |
| Web service class attribute | WebServiceAttribute | ServiceContractAttribute |
| Web service method attribute | WebMethodAttribute | OperationContractAttribute |
| Data class attribute | XmlRootAttribute | DataContractAttribute |
| Data class field attribute | XmlElementAttribute | DataMemberAttribute |
| HTTP endpoint resource | .ASMX | .SVC |
As a side note, if you are using .NET 3.5 SP1 the porting process gets a little easier, since WCF will automatically serialize any object that is part of a service interface without the need of any special metadata attached to it. This means you no longer have to decorate the classes and members exposed by a WCF service contract with the DataContract and DataMember attributes.
Important considerations
The simple process I just described works well for relatively simple web services, but in any real-world scenario you will have to take into consideration a few number of aspects:
- WCF services are not bound to the HTTP protocol as ASMX web services are. This means you can host them in any process you like, whether it be a Windows Service or a console application. In other words using Microsoft IIS is no longer a requirement, although it is a valid possibility in many situations.
- Even if WCF services are executed by the ASP.NET worker process when hosted in IIS, they do not participate in the ASP.NET HTTP Pipeline. This means that you have no longer access to the ASP.NET infrastructure services such as HttpContext, HttpSessionState, HttpApplicationState, ASP.NET Authorization and Impersonation in your WCF services.
So what if your ASMX web services are making extensive use of the ASP.NET session store or employ the ASP.NET security model? Is it a show-stopper?
Luckily enough, no. There is a solution to keep all that ASP.NET goodness working in WCF. It is called ASP.NET Compatibility Mode.
Backwards compatibility
Running WCF services with the ASP.NET Compatibility Mode enabled will integrate them in the ASP.NET HTTP Pipeline, which of course means all ASP.NET infrastructure will be back in place and available from WCF at runtime.
You can enable this mighty mode from WCF by following these steps:
- Decorate your web service class with the System.ServiceModel.Activation.AspNetCompatibilityRequirements attribute as following:
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MyService : IMyService
{
// Service implementation
}
- Add the following setting to the application configuration file:
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> </system.serviceModel>
Remember that this will effectively tie the WCF runtime to the HTTP protocol, just like with ASMX web services, which means it becomes prohibited to add any non-HTTP endpoints for your WCF services.
Good luck and please, let me know your feedback!
/Enrico



19/01/2009 at 15:49
In ASP.NET web service I have this code:
string value = (string)this.Application.Get(name);
What is similar ir WCF? How I can get and set information in HttpApplicationState?
Thanks
20/01/2009 at 10:37
In a WCF service you can access the HttpApplicationState object through the HttpContext, this way:
public void MyWcfService(){
System.Web.HttpApplicationState app = System.Web.HttpContext.Current.Application;
}
20/01/2009 at 12:14
This means I need to use System.ServiceModel.Activation.AspNetCompatibilityRequirements attribute. But is it possible to use HttpApplicationState without this attribute?
Or maybe there is other way how to store variables in memory?
27/01/2009 at 00:09
Yes, the HttpContext will not be available in WCF unless you run your service in the ASP.NET runtime.
Well, you have a couple of options for managing state in WCF services. You could configure you service to always use the same instance to respond to all incoming requests. This way the service object will actually be a singleton, and its data be persisted across all calls. Another option is to use WCF Sessions, and maintain the same service object during the context of a conversation between the service and a particular client (Note that this is different than how Session works in ASP.NET).
In order to configure this aspect of a WCF service you will have to decorate your service implementation class with the ServiceBehaviorAttribute, like in this example:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]public class MyService : IMyService {
// ...
}
If you are looking into using sessions in WCF, I recommend you to check out this excellent article.
27/01/2009 at 06:18
[...] here to see the original: Migrating ASP.NET Web Services to WCF asp asp-net ASP.NET Security authentication goodness-working mode-backwards net [...]
04/02/2009 at 00:48
I need to store variable in memory which is always there not only in session. (like global variable). I need to crete one method which can set this variable.
This variable is set by one user with extra rights. And all other users then can read this variable. This variable always stay in memory while IIS resets or user with extra rights change it.
In ASP.NET web service I do it with this line of code:
this.Application.Set(name, value);
What is easyest way how to do this in WCF if I don’t want to run service in the ASP.NET runtime?
Thanks
05/02/2009 at 23:38
WCF does not provide any way out of the box to globally store custom data like ASP.NET does with the HttpApplicationState object.
However, if the variable you are talking about needs only to be accessed from within same service class, you could configure your WCF service to use a singleton instance to respond to all requests, like in my previous example. This service instance and all its variables will then have the same lifetime as the hosting process.
If the variable must be available from different services instead, then you really need to provide your own solution. You could implement the singleton design pattern and make an instance of a custom class globally available to your application.
17/07/2009 at 20:11
Great post, i know wcf but never gone such a conceptual details in few lines. :-)
30/07/2009 at 23:51
Just curious, since i have just started working on migrating our asmx services to wcf services, and so far I really did not see a big improvement in performance. Our wcf service is using tcp binding, what is your finding on the comparison?
31/07/2009 at 13:08
Well, since WCF is a superset of ASMX, in order to compare the two technologies you really should measure WCF performance using the BasicHttpBinding, because that’s what ASMX supports. In that regard you can find a nice (although not completely “neutral”) comparison here on MSDN, which shows that WCF is in average 20-40% faster than ASMX in processing requests.
I’m not sure what you are measuring in your particular case, but you should at least see a big improvement in message size over ASMX, since the NetTcpBinding uses binary encoding and the TCP protocol is more lightweight than HTTP.
04/08/2009 at 22:50
Thanks for the response.
Agree a fair comparison is asmx vs basicHttpBinding, but our goal really isnt to compare, rather to improve the speed of existing apps. So when my new wcf/tcp service comes back with pretty much the same response time as asmx, I am just a little puzzled, and disappointed. But then again, I could be doing something wrong.