I’m a big fan for using AJAX callback services in my AJAX enabled applications. I prefer the low level approach where the server acts as a service and only feeds data to the client and the client then manages updating the data and updating the UI with that data accordingly. On the .NET platform there are a lot of options available for doing this from using ASMX Web Services JSON support via the ASP.NET AJAX Web Services, to using WCF 3.5’s REST services to a number of free solutions that provide simple and easy to use connectivity from client to server.
A while back I’d talked about using WCF for REST services with jQuery and there was a ton of interest in this particular topic. I also noticed Dave Ward’s topic (which is great complement to mine) also has gotten a lot of traction and there certainly is a lot of interest in using WCF for AJAX callbacks. I get questions from people almost daily who want to know something related to the WCF functionality or – almost as frequently – asking whether WCF is the right choice for AJAX Web Services.
WCF REST Services – worth the hassle?
Let me start off by saying that I’m a huge fan of WCF as a service framework for building Web Services and any sort of inter application communication interface. However, I’m much less enthusiastic about the WCF REST functionality and the AJAX functionality in particular. That’s not to say that I don’t use them – I think in the end WCF will replace ASMX for Ajax callbacks. But the reality for me is that WCF REST set up and operation is more error prone and requires more resources than the older and simpler ASMX services.
In the end what it comes down to is that using WCF doesn’t really provide any significant improvements over ASMX based AJAX services. There ARE new features in this part of the WCF stack, but most relate to the actual REST functionality rather than the AJAX features which realistically shouldn’t be lobbed into the same technology space. If you are using ASMX now and you’re moving to WCF for those same AJAX services don’t expect any new features other than ‘it just works’.
There are really two new features in the WCF 3.5: REST functionality which is based on the REST architectural guidelines of using URL based routing, plus usage of Http Verbs to specify intent on service operations. And then there is the RPC style interface functionality that we typically use for AJAX based applications to make AJAX style callbacks to the server from client applications. In WCF 3.5 both of these technologies sit under the same umbrella because they basically use the same functionality – non-SOAP based HTTP endpoints – although from an application architectural POV they are used quite differently.
REST is meant to be URL and Http Verb based, but typical AJAX callbacks – especially those that are based on ASP.NET AJAX - really only use a single endpoint URL and POST data to the the server. ASP.NET AJAX applications aren’t really REST in that they don’t follow typical REST recommendations (not that this semantic difference matters much in a pragmatic sense).
WCF REST is WCF – sort of
I was excited to see a dedicated HTTP REST and AJAX interface to WCF introduced in .NET 3.5. Prior to .NET 3.5 WCF provided only SOAP based services and SOAP based services are notoriously difficult to consume for ‘light’ client interfaces that don’t have native SOAP clients. Consuming a SOAP endpoint in HTTP for example would be rather painful. Instead many client applications today use either plain xml (POX) end points or more likely for Javascript client applications JSON endpoints.
WCF REST provides the pure HTTP based endpoint infrastructure that allows returning non-SOAP content in XML, JSON, RSS and Atom formats, plus the ability to return pure data via .NET streams which allow returning any sort of binary data like images or HTML or anything else so any type of content can be served from a REST endpoint. What this means in a nutshell is that you can use the standard WCF messaging model to return non-SOAP based HTTP data to clients.
I’ve already been using WCF and having this functionality extended to JSON services initially sounded like a great idea. But it quickly became clear that pure WCF REST services are very different than other services: An existing WCF service doesn’t work out of the box as is as a REST service. Unlike other service types that can switch between protocols with just a few configuration switch settings REST requires that the service contract is marked up with REST specific service attributes on each operation like so:
[OperationContract]
[WebInvoke(
Method="GET",
ResponseFormat= WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate= "GetStockQuote/{symbol}")
]
StockQuote GetStockQuote(string symbol);
Each endpoint method specifies exactly the format that is used to return data to the client. There are quite a few custom attributes and they are mutually exclusive – any of the options unqiuely configure each endpoint so it’s not possible to create an endpoint that returns either Xml or Json, or a bare or wrapped response based say based on the type of input that was received. Based on the design of WCF’s functionality that actually makes as one endpoint maps exactly to one messaging format. But it makes for a bit of a hack if you plan to expose and/or accept data in different formats. Essentially you have to create multiple methods with different names to expose data in different formats and – optionally – provide a custom UriTemplate template to make it seem seamless. For example if I want to return data both in JSON and XML I might have to do something like this:
[OperationContract]
[WebInvoke(
Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate="Quotes/{symbol}")
]
StockQuote GetStockQuote(string symbol);
[OperationContract]
[WebInvoke(
Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Quotes/{symbol}/json")
]
StockQuote GetStockQuoteJson(string Symbol);
with two method implementations required that basically do exactly the same thing. The only difference is the UriTemplate and the ResponseFormat. Again this makes sense for the way WCF works, but from a logistic implementation POV this means if you want to support 4 different message formats you end up exposing 4 different endpoints/methods (even if each just calls a base function to do the actual processing).
What’s even worse though is that you can map an endpoint only to a single HTTP verb and document input/output type. You can’t have a single endpoint to serve both GET and POST or based on parameters serve either Xml or JSON. While this might be OK for a pure REST implementation, for a typical AJAX service this is not optimal. When building an AJAX API it’s not uncommon to want to have clients access through both query string parameters or POST variables. AFAIK this can’t be done with a single WCF end point because again you’re specifying a whole bunch of service specific behavior on each method in the service contract.
If you add 4 output types plus maybe two different operation types for that endpoint you end up with a plethora of methods to service that one endpoint. It gets messy REALLY quick and really makes you wonder: Wouldn’t it just have been easier to create an HttpHandler that has a single end point mapper and properly deserializes/serializes data based on a set of standardized input parameters? After all there is a DataContractJsonSerializer plus the XMLSerializer that can be used to serialize and de-serialize objects fairly easily. I’ve wondered this on several occasions even as I was putting together some of my relatively simple examples for my session. I imagine it only gets worse once you start building more complex services that expose a full complement of REST operations for REST manipulatable data or content.
Even if you stick with a single message format you are still required to specify the format on each Operation/Method. It sure would have been nice if WCF REST supported some mechanism to specify default formats for all those message format attributes that can be defined once at the Contract/Class level. But no – that’d be too easy.
All this service behavior markup too gets tedious as it has to be added to each endpoint method which means lots of repetition. If you decide later on you want to switch to a different message format you have to hunt through all service methods and change all of the attributes on them. Unlike other services were behavior is set once on the service and only occasionally overridden the pure REST interface requires individual attributes.
No Authentication
WCF REST also doesn’t support any authentication schemes unless you enable enable ASP.NET Compatibility. You can use Windows Authentication with REST Urls but you can’t even easily retrieve the log in info unless you’re using ASP.NET compatibility. So your choices for authentication are use ASP.NET compatibility (described below) and take advantage of Forms/Windows/Membership Authentication or roll your own. One of the big draws of WCF is that so much infrastructure is provided for you so you don’t have to reinvent the wheel for every protocol nuance. But WCF REST lacks most of that beyond the basic protocol implementations.
Single ASP.NET Authentication Mode Support
WCF REST only supports a single authentication mode in an IIS Web site. This means you can have EITHER anonymous or Windows Authentication going in the site, but not both. When you do both you get a nice yellow screen of death:
This is actually a potentially big deal if you plan on dropping WCF REST into an application that has to support both public and authenticated access. I haven’t seen a way to get around this issue and this will make WCF REST a non-starter in a number of situations – I know it has for me. You can’t always choose what format is used as the rest of the application might determine the security environment.
This seems like an arbitrary limitation, since obviously IIS supports mixing schemes. I can understand multiple actual auth schemes not being supported, but at the very least anonymous should always work. Alas it doesn’t and it’s a bummer.
No Support for Anonymous or object Types
This is huge especially if you are working with LINQ and potentially returning filtered data to the client. The following will compile but will blow up when you try to call the service:
[OperationContract]
public object GetAnonymousType()
{
return new { Name = "Rick", Date = DateTime.Now, Value = 212.22 };
}
The problem is that the DataContractJsonSerializer that WCF uses to serialize to JSON doesn’t support non-specific types for serialization. While this makes some sense for WCF as a whole (because a non-specific type can’t be provided in a contract accurrately), it’s something that should work for JSON which doesn’t provide a real service contract metadata item to the client.
Incidentally ASMX services do support Anonymous Type serialization although you can’t pass them back from the client which makes sense since you can’t specify the type signature for the parameter. It’s silly that WCF doesn’t support this.
Error Handling
In non ASP.NET Compatibility mode, you’ll also find that the error handling is horrible. Instead of an response that is returned as JSON to the client you get an HTML error page that is completely useless to the client that can do nothing other than try to parse out the error message. This makes sense for pure REST scenarios, but in a JSON callback scenario an HTML message does not provide anything useful to the client – what’s really needed is like standard WCF an error returned in the appropriate message format (ie. JSON). There’s no built-in way to return an error in a JSON scenario as an error object – instead HTML is returned. You can roll your own to do this (or again use the ASP.NET AJAX specific script factory) but that’s not a trivial task.
The REST Starter Kit improves this slightly. It provides some new WCF REST extensions that provide the abililty to throw errors from server code more easily and output error output pages that are much leaner than the typical Yellow Screen of Death you’d get by default. BTW, the starter kit provides a host of useful new features although one really has to wonder why this stuff wasn’t added to the core product in the first place.
Some of these limitations make sense for the platform – it’s the way WCF works, but maybe that’s precisely why the REST features are maybe not such good fit for WCF.
ASP.NET AJAX HostFactory makes things easier than ‘plain’ REST
What I described above mostly relates to pure REST interfaces where you specify every option you want to use explicitly on each method using the WebInvoke or WebGet attribute.This allows you maximum flexibility for your messages but it’s also tedious to do on each and every method. This is probably reasonable for ‘real’ REST based applications that are exposed to be accessed by the whole world , but for a typical AJAX callback service that gets only by your application to provide data for client pages that would be overkill. Typical AJAX applications aren’t concerned with REST semantics, but need to efficiently and consistently retrieve AJAX data.
Luckily Microsoft recognized this needs as well as the existing base of ASMX style AJA X services that work with the ASP.NET AJAX infrastructure. If all you’re after is compatibility with ASP.NET AJAX and to replace AMSX with WCF – there’s a shortcut that provides WCF REST the same functionality that ASMX based AJAX services provide. Microsoft was smart enough to release a SerivceFactory that provides in effect ASP.NET AJAX compatibility out of the box. It provides the same ‘wrapped’ JSON message format that ASP.NET AJAX uses, the script proxy (the /jsdebug option), error management by wrapping exceptions into objects that get marshalled back to the client as JSON objects. Some of these features – like the error management is only available to this specific ServiceFactory.
So to set up a pure AJAX service you can use the WebScriptServiceHostFactory on the service definition in the Service markup:
<%@ ServiceHost Language="C#"
Service="WcfAjax.MsAjaxStockService"
CodeBehind="MsAjaxStockService.svc.cs"
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
%>
which makes the service ‘config-less’ (the entries in Web.config can be removed), provides the /jsDebug proxy generation and serves and receives data in Microsoft’s wrapped JSON format and error marshalling as JSON. No settings in web.config are required and none of the endpoint methods require any attributes beyond the OperationContract to expose the method.
[OperationContract]
StockQuote GetStockQuote(string symbol);
When using this model the input is always a POST JSON string in the MS parameter format which is in the mode of parameter key value pairs (ie. { “parm1”: value, “parm2”: “value”}. Output is always returned in the MS wrapped format which has a ‘root’ object with a single property that actually holds the result value. The wrapped format includes a root node, plus type information on each marshalled object value returned from the server to facilitate two-way serialization.
{"d":
{"__type":"StockQuote:#WcfAjax",
"Company":"Microsoft Corpora",
"LastPrice":20.49,
"LastQuoteTime":"\/Date(1227751200000-1000)\/",
"LastQuoteTimeString":"Nov 26, 4:00PM",
"NetChange":0.50,
"OpenPrice":19.83,
"Symbol":"MSFT"
}
}
This format is specific to the WebScriptServiceHostFactory as far as I can tell. Although similar to the stadard BodymessageStyle.Wrapped the format is different as the base version does not include type information for objects and names the root node differently. IOW, this is a very ASP.NET AJAX specific implementation.
By default when using the WebScriptServiceHostFactory, ASP.NET compatibilty – the abilty to access the HttpContext object and its intrinsic ASP.NET objects – is not enabled. If you have existing ASMX services you want to migrate to WCF and those services rely on things like Session or Request you need to add one more setting to your Web.Config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Then on your service:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class RestStockService : StockServiceBase, IRestStockService
Options are Allowed, Required, NotAllowed. Note that this is specified on the implementation class rather than the service contract interface.
If you don’t need ASP.NET compatibility, it’s best to turn this option off, but if you have an existing ASMX service that uses say the session object to track users, it’s handy to be able to fall back onto ASP.NET objects. Realize when you do use ASP.NET features you are obviously tied to ASP.NET and IIS. REST services CAN be hosted in alternative hosts (self hosting for example) but if you use ASP.NET compatibility only ASP.NET app hosting is allowed.
Using the WebScriptHostFactory is a quick way to migrate existing ASMX services to WCF. However, keep in mind that realistically doing so will buy you nothing in terms of new functionality or features other than being able to say the app runs on WCF. However, going forward I suspect that any further improvements to the ASP.NET AJAX engine will be made to the WCF engine rather than ASMX, so going forward and especially for creating new services it’s probably not a bad idea to start using WCF services. It’s not really any more complicated than ASMX services as long as you use the WebScriptServiceHostFactory.
Stability
One big concern I’ve had with WCF is that I’ve had some stability problems with the .SVC file in my ASP.NET projects. The issues are mostly in the development environment, but it’s been a huge time sink. The problem I’ve run into is that the .svc file on the server somehow gets out of sync with the compiled code and causes a yellow screen of death for a compilation/temporary file error as I described here. These errors pop up randomly on apps that have been working just fine and even though the service file or the service related classes and interfaces have not changed.
Things get a little better if the following configuration setting is used in <system.web>:
<compilation debug="true" batch="false">
which makes this compilation error less of a problem. But it still happens to me from time to time and once it does it takes a few IIS restarts to get the application running again.
Do you need to use WCF rather than ASMX?
So where does that leave us? WCF REST provides new functionality but be prepared to spend some time with it, especially if you choose to not use the ASP.NET AJAX specific WebScriptHostFactory. Figuring out how to get WCF to return just the right contract can take a little tweaking.
As to switching from ASMX to WCF for AJAX services – if you have existing services that work with ASMX I really don’t see a compelling reason to switch to WCF. There are no new features so at best you get the same functionality you had before running WCF. If you do decide to go forward to WCF – updating is pretty easy. It basically involves migrating your classes by updating the various attributes [WebMethod] attributes to [OperationContract] attributes, so all in all that’s a pretty painless migration. Remember that if you use ASP.NET intrinsic objects anywhere in your service to enable AspNetCompatibilityEnabled in Web.config and set the attribute on the service class.
Going forward for new services using WCF is probably not a bad choice since it’s really no more complicated than ASMX to set up if you use the script factory.
Still I’m fairly wary of the new WCF features. I wanted to be exited and move forward, but ultimately WCF just doesn’t bring any benefit to the party, but rather makes things more complicated by requiring additional references and requiring more resource. Most AJAX based ‘service’ interfaces are not real services but are very closely tied to the Web application. They tend to be private services used for internal use of the application, rather than widely accessed public services. For that task WCF REST services might have more appeal.
Other Posts you might also like