Differences Between ASMX and WCF Services

Some differences between ASMX and WCF services are subtle and some differences between them are not subtle. The purpose of this section is to identify many of these differences and to provide guidance for how to handle them when preparing for, or when performing, migration. ASMX provides a very successful baseline for services, and WCF extends those capabilities for the next generation of services.

There are differences between ASMX and WCF, but it is important to also understand that WCF supports the same capabilities that ASMX provides. For example, you can use message types, XmlSerialization, custom SOAP headers, and Web Service Enhancements (WSE) in a WCF service. The remainder of this section describes some of these items; it also describes other areas that represent differences between ASMX and WCF.

The following subtopics describe the major differences between ASMX and WCF services:

  • Message Structure and Serialization
  • SOAP Extensions
  • Transport Protocols
  • Security
  • Exception Handling
  • State Management

Message Structure and Serialization

Serialization is the process of translating binary objects into a data format that can be transmitted across process boundaries, computer boundaries, and network boundaries. When serialized data reaches the destination, or endpoint, it can be deserialized back into binary objects for use by an application. Both ASMX and WCF use SOAP for messages passed between two endpoints. However, for serialization, each uses different classes that implement different rules.

ASMX uses the XmlSerializer to translate classes into XML for communication, and to translate the XML back into classes on the receiver’s end. All public members are serialized unless they are marked as non-serializable using the XmlIgnoreAttribute. A large number of attributes can also be used to control the structure of the XML. For example, a property can be represented as an attribute using the XmlAttributeAttribute, or as an element using the XmlElementAttribute. The use of these attributes provides a great deal of control over how a type is serialized into XML; however, that power comes with an unfortunate downside. It may be possible to create XML structures that are not easily translated by other type systems, such as Java; XML structures that are not easily translated can hamper interoperability.

WCF uses a DataContractSerializer to perform the same translation; however, the behavior is different from the XmlSerializer. The XmlSerializer uses an implicit model where all public properties are serialized unless they are marked with the XmlIgnoreAttribute, but the DataContractSerializer uses an explicit model where the properties and/or fields that you want to serialize must be marked with a DataMemberAttribute. It is important to note that WCF can also use the XmlSerializer to perform serialization operations.

A notable difference between ASMX and WCF is the WCF ability to serialize class members regardless of the access specifier used. This means it is now possible to serialize private fields. Using this capability, you can encapsulate fields in a data type. For example, you can provide read-only access to a private field by implementing only the get method on a property. You can then serialize that private field by adding the DataMember attribute to the field in a WCF service.

Another important difference is that the DataContractSerializer generates a simplified XML structure that increases its ability to interoperate between different operating systems. In addition, the ability for users to control the XML structure is limited. This simplified structure also means that future versions of WCF will be able to target this structure for optimization. Finally, in comparison to the XmlSerializer, the serialization of data is greatly improved with the DataContractSerializer.

Recommendation

Using WCF, you can use the XmlSerializer for types that are already created. However, to maximize interoperability, it is recommended to use WCF data contracts and the DataContractSerializer. The Web Service Software Factory (ASMX) guidance package, also referred to as the ASMX guidance package, creates types that should also migrate to WCF data contracts if no additional XML serialization attributes, such as XmlAttributeAttribute, are added. The ASMX guidance package includes an XmlNamespaceAttribute to specify the namespace of the types.

SOAP Extensions

Developers can use the SOAP extensions feature of ASP.NET to interact directly with SOAP messages. By using SOAP extensions, you can intercept the SOAP message and insert your own code into the SOAP message pipeline, which allows you to extend the capabilities of SOAP. For example, features such as security, transaction management, routing, and tracing can be implemented by using SOAP extensions. The downside of this capability is that it reduces the SOAP message’s ability to interoperate with other operating systems. In other words, other operating systems may not be able to handle a SOAP message that has been customized.

WCF does not support the use of SOAP extensions, but it does have other extensibility points that can be used to intercept and manipulate SOAP messages. For example, you can use a behavior extension to hook into the WCF Dispatcher with a class that implements IDispatchMessageInspector.

Recommendation

Avoid the use of SOAP extensions when developing new ASMX services that will be migrated to WCF unless you are willing to rewrite them or if you are confident that WCF provides a similar capability.

Transport Protocols

ASMX services use the HTTP transport protocol for communications with Internet Information Services (IIS) as the host. An ASMX service file has the file name extension .asmx, which is accessed using a Uniform Resource Locator (URL); for example, http://localhost/ASMXEmployee/EmployeeManager.asmx.

WCF services can also use the HTTP protocol, but unlike ASMX services, you also have the option to use other transport protocols. The following protocols are supported by WCF:

  • Hypertext Transfer Protocol (HTTP)
  • Transmission Control Protocol (TCP)
  • Message Queuing (also known as MSMQ)
  • Named pipes

Many different hosts can also be used with WCF services. For example, IIS can be used as a host with the HTTP transport protocol. Windows services and stand-alone applications can be used as a host for other transport protocols.

Accessing a service hosted in IIS is similar to accessing an ASMX service; for example, http://localhost/WCFEmployee/EmployeeManager.svc.

The only difference between the two services is the file name extension. However, you can also configure a WCF service to use the .asmx file name extension, as described in the Service Configuration topic. WCF services that use other transport protocols are accessed using methods associated with the specific protocol.

When migrating an ASMX service to WCF, the protocol you choose is based on the client applications that will be accessing the service. If you need to support ASMX client applications, you also need to use the HTTP protocol. In addition, when configuring a WCF service for ASMX client applications, you need to configure the service to use BasicHttpBinding, as described in the Service Configuration topic.

Recommendation

When migrating services from ASMX to WCF, and if ASMX client applications need to access the migrated service, use the HTTP protocol and configure the new service to use BasicHttpBinding.

Security

Typically, authentication and authorization with ASMX is done using IIS and ASP.NET security configurations and transport layer security. In addition, Web Service Extensions (WSE) can be used to provide additional security capabilities, such as message layer security.

WCF can use the same security components as ASMX, such as transport layer security and WSE. However, WCF also has its own built-in security, which allows for a consistent security programming model for any transport. The security implemented by WCF supports many of the same capabilities as IIS and WS-* security protocols. However, when using IIS, you must also enable anonymous access to the service so that WCF security is implemented.

A powerful reason for migrating an ASMX service to WCF is to take advantage of new security capabilities that are provided by WCF. For example, WCF provides support for claims-based authorization that provides finer-grained control over resources than role-based security. In addition, instead of depending on a transport protocol such as HTTP and extensions such as WSE, security is built into WCF. The end result is that security is consistent regardless of the host that is used to implement a WCF service.

Recommendation

When possible, migrate both client applications and services to WCF to take advantage of the new security features that are available with WCF. Use of the WCF Security guidance package is also recommended when configuring security for WCF services and client applications.

If a migrated WCF service must support ASMX client applications, you can use transport security associated with HTTP and HTTPS. You can also use WSE 3.0, but you must configure a custom WCF binding for this to work. For additional information about using WSE 3.0 with WCF, see Interoperating with WSE Sample on MSDN.

Exception Handling

With ASMX services, unhandled exceptions are always returned to client applications as SOAP faults. An ASMX service can also throw the SoapException class, which provides more control over the content of the SOAP fault that is returned to the client application.

However, when an unhandled exception occurs, the default configuration of WCF protects sensitive data from exposure by not returning sensitive information in SOAP fault messages. You can override this behavior by adding a serviceDebug element to the service behavior in the configuration file that is associated with a WCF service. Overriding this behavior is not recommended for deployment; it should be used only in a development environment.

Similar to the SoapException class used with ASMX services, you can also throw a custom exception by using the FaultException<T> type, where T is a data contract that contains the exception information. The use of custom exceptions also requires the declaration of a FaultContract on operations that will throw the exception.

The following code example demonstrates how a DataContract is used to define a FaultContract declared on a service operation in a ServiceContract.

[DataContract]
public class FindEmployeeFault
{
    [DataMember]
    public string Request;
    [DataMember]
    public string Description;
}

[ServiceContract]
public interface IEmployeeManager
{
    [OperationContract(Action = "FindEmployeeByLastName")]
    [FaultContract(typeof(EmployeeService.FaultContracts.FindEmployeeFault))]
    EmployeeService.DataContracts.Employee FindEmployeeByLastName(string request);
}

This next code example demonstrates how to catch a FaultException that may be thrown by the service operation shown in the preceding code example.

// client function used to find an employee
public Employee FindEmployee( string lastName )
{
    Employee employee = null;
    try
    {
        employee = proxy.FindEmployeeByLastName( lastName   );
    }
    catch( FaultException<FindEmployeeFault> ex )
    {
        Console.WriteLine("FaultException<FindEmployeeFault>: While finding " 
            + ex.Detail.Request
            + ". Because: " 
            + ex.Detail.Description );
    }
    return employee;
}

The filtering of exception data that is returned from a service is described using an Exception Shielding pattern. The pattern describes how exception handlers can be used to filter the data that is returned to a client application. To help facilitate the creation of exception handlers in WCF services, the Service Factory: Modeling Edition includes the Data Contract Model that contains a fault contract shape that you can use to create WCF fault contracts.

Recommendation

WCF provides exception shielding, but you should always define exception handlers for both ASMX and WCF services. For more information, see Exception Handling in Service Oriented Applications.

State Management

ASMX services have access to the HttpContext class, which provides access to state managers with a different scope, such as application scope and session scope. ASP.NET also provides control over how state data is managed. Consequently, you should minimize the use of state in a service because of the effect it has on the scalability of an application.

WCF provides extensible objects that can be used for state management. Extensible objects implement the System.ServiceModel.IExtensibleObject<T> interface. The two main classes that implement the IExtensibleObject interface are ServiceHostBasedand InstanceContext. The ServiceHostBased class provides the ability for all service instances in the same host to access the same state data. On the other hand, the InstanceContext class only allows access to state data within the same service instance.

To implement state management in WCF, you need to define a class that implements the IExtension interface, which is used to hold the state data. Instances of this class can then be added to one of the IExtensibleObject classes using the Extensions property. The following code example shows how to implement state using the InstanceContext.

internal class StateData: IExtension<InstanceContext>
{
    public string Identifier = string.Empty;
    public string Data = string.Empty;

    public StateData( string data )
    {
        Identifier = Guid.NewGuid().ToString();
        Data = data;
    }
}

public string AddStateData( string data )
{
    StateData state = new StateData( data );
    OperationContext.Current.InstanceContext.Extensions.Add(state);
    return state.Identifier;
}

public string GetStateData( string identifier )
{
    Collection<StateData> dataCollection = 
        OperationContext.Current.InstanceContext.Extensions.FindAll<StateData>();

    string result = string.Empty;
    foreach( StateData data in dataCollection )
    {
        if( data.Identifier == identifier )
        {
            Result = data.Data;
            break;
        }
    }
    return result;
}

Recommendation

The ability to control where state is maintained in WCF is much more limited than in ASP.NET. As a result, state management is commonly used as the primary reason for enabling the ASP.NET compatibility mode, which provides access to ASP.NET components; this means you have much more control over where state is maintained. For example, when a service is configured for ASP.NET compatibility, you have access to HTTP context classes that provide the same functionality as the ASMX implementation.

When developing new ASMX services, you should avoid the use of state in your services; all services should be stateless.

Original source from Microsoft, edited and moved here as the content on Microsoft was in fear of being removed.

Catching Exceptions with Elmah within WCF

We all use the excellent ELMAH to deal with unhandled exceptions in an ASP.NET 3.5 web or MVC application. This works extremely well for all of the site, now what about WCF how can we get Elmah to work for us?

You can use the HttpHandler, and Decorate your Service(s) with an Error Handling attribute.

The ServiceErrorBehaviourAttribute:

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

/// <summary>
/// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
/// ...and errors reported to ELMAH
/// </summary>
public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
{
    readonly Type _errorHandlerType;

    public ServiceErrorBehaviourAttribute(Type errorHandlerType)
    {
        this._errorHandlerType = errorHandlerType;
    }

    public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
        var errorHandler = (IErrorHandler)Activator.CreateInstance(_errorHandlerType);
        foreach (var channelDispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
        {
            channelDispatcher.ErrorHandlers.Add(errorHandler);
        }
    }
}

Now the HttpErrorHandler:

using Elmah;
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

/// <summary>
/// Your handler to actually tell ELMAH about the problem.
/// </summary>
public class HttpErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return false;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        if (error == null) return;

        ErrorLog.GetDefault(null).Log(new Error(error));
    }
}

Now it is just a simple case of adding an attribute to the WCF Service:

[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class Game : IGame
{

Here is a small sample application showing it in action

WcfService1.zip (8.26 kb)

Overloading Methods in WCF

Is this possible?

It is possible to overload a method in WCF.  However, when you want to expose overloaded methods as operations in a WCF contract, there is more to it than simply writing two or more methods with the same name.

Consider the following example:

[ServiceContract]
public interface ICalendarService
{
   [OperationContract]
   ScheduledEvent[] GetScheduledEvents(DateTime date);

   [OperationContract]
   ScheduledEvent[] GetScheduledEvents(DateTime start, DateTime end);
}

Now, try to actually implement this interface and host it as a WCF service.  An InvalidOperationException will be raised when you invoke ServiceHost.Open. 

As far as the C# compiler is concerned, this is a completely legal piece of code.  The interface contains two methods.  The methods have the same name, but their signatures are unique since their parameters differ.  The interface and methods are decorated with attributes.  However, WCF doesn’t have any special hooks into the compiler. Consequently, the compiler doesn’t have any special knowledge about the attributes.  It is simply going to emit their information in the assembly metadata.

When WCF attempts to start the service, it essentially interrogates the metadata to generate a WSDL contract.  WSDL is all about technology neutral, message based communication.  It doesn’t support object-oriented concepts such as inheritance and overloading.  (Actually, I think the earliest versions of WSDL allowed overloading to a certain extent, but it has since been removed in the newer versions.)  So, WCF basically detects there are two methods with the same name and raises an exception to indicate this isn’t allowed even though the code compiled without any errors.

Regardless, WCF still provides the ability to overload methods.  This can be achieved by using the name property of the OperationContract attribute.  By default, the name of the method will be used for the value of the name property.  However, you can explicitly set the value of the name property to provide a unique value.  Under the covers, WCF will use the value you supply as the name of the corresponding operation in the generated WSDL.

Here is our previous example revised to use alias method names:

[ServiceContract]
public interface ICalendarService
{
   [OperationContract(Name = "GetScheduledEventsByDate")]
   ScheduledEvent[] GetScheduledEvents(DateTime date);

   [OperationContract(Name = "GetScheduledEventsByDateRange")]
   ScheduledEvent[] GetScheduledEvents(DateTime start, DateTime end);
}

You may be wondering how the method will appear to the consumer of the service.  Will it appear as two different names (based on the the alias) or as overloaded methods with the same name?  This will depend upon the proxy class used by your client.  If you use the proxy class that is automatically generated by svcutility.exe, the alias method names will be used.  However, you can manually edit the generated proxy class to achieve the appearance of overloaded methods on the client as well.  This can be accomplished by applying the same attributes to the methods defined in the interface that is used by the proxy class.

Original article from Jeff Barnes