I thoroughly enjoyed the opportunity to learn about the new WCF web programming model, and I am very excited to see the capabilities baked into WCF. The web is a great platform for integration, and so having first class support in WCF is critical for WCF to be useful in truly large-scale context. When I was speaking with Steve Maine, I mentioned that my base level for comparison for the programming model is starting from a raw socket. How far off of the raw socket experience am I, and what am I gaining from the extra layers?
OK. I might not actually go all the way down to a raw socket, but I would go at least to a CGI/Servlet/ISAPI Filter/IHttpHandler/HttpListener level. That is, assuming that I don't have to reinvent listeners or perhaps the extensible web server as a concept, how different and flexible is the WCF web programming model? I think that, in the case of Microsoft.ServiceModel.Web, the answer is going to be "A good bit."
But.
So.
My first naive attempt at a SmackDown failed relatively miserably. I thought I would pair up Harry "I Http" Handler versus Spidey "the web" .svc.
So, I added an IHttpHandler:
<%@ WebHandler Language="C#" Class="Hello" %>
using System;
using System.Web;
public class Hello : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/xml";
context.Response.Write("<Say>Hello, Cruel World.</Say>");
}
public bool IsReusable { get { return true; } }
}
(Note: I am using Windows Live Writer, and it doesn't allow me to paste rich text content. Argh. Copy Source As HTML to the rescue.)
I do a GET against the Handler, and viola!
Now granted, I am not even checking to see if the method is GET. I might want to add that in, eh? But for now, it works.
I added a WCF service to the web project (I skipped defining a service contract interface at this point to keep it simple. In actuality, I did it both with and without):
<%@ ServiceHost Language=C# Debug="true" Service="Improving.Samples.WCF.Web.Hello" %>
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Improving.Samples.WCF.Web
{
[ServiceContract()]
public class Hello
{
[OperationContract]
[WebGet()]
// Not very, um, resourcey, but...
public string GetMessage()
{
return "Hello, Cruel World";
}
}
}
wired up the service in the web.config, changed the binding from wsHttpBinding to webHttpBinding:
<system.serviceModel>
<services>
<service name="Improving.Samples.WCF.Web.Hello">
<endpoint contract="Improving.Samples.WCF.Web.Hello" binding="webHttpBinding" />
</service>
</services>
</system.serviceModel>
Do a GET in the browser, and voila!
OK. OK. Minor set back. Let's try to add the binding in:
<system.serviceModel>
<services>
<service name="Improving.Samples.WCF.Web.Hello">
<endpoint contract="Improving.Samples.WCF.Web.Hello" binding="webHttpBinding" />
</service>
</services>
<bindings>
<webHttpBinding />
</bindings>
</system.serviceModel>
D'oh. Another cup of coffee, please. After a bit of reflectoring, I add in the binding extension (which seems weird, because the binding element is a subclass of StandardBindingElement, hmmm... maybe I need to add the assemblies to the WCF directory?):
<system.serviceModel>
<services>
<service name="Improving.Samples.WCF.Web.Hello">
<endpoint contract="Improving.Samples.WCF.Web.Hello" binding="webHttpBinding" />
</service>
</services>
<bindings>
<webHttpBinding />
</bindings>
<extensions>
<bindingExtensions>
<add name="webHttpBinding"
type="System.ServiceModel.Configuration.WebHttpBindingCollectionElement, Microsoft.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
</system.serviceModel>
OK. So, back to the browser and, Voila!
Argh. OK. So, I expected the metadata to be disabled. I didn't exactly expect the help page, but I know how to disable it via the serviceDebug behavior from a previous spelunking exercise:
<system.serviceModel>
<services>
<service name="Improving.Samples.WCF.Web.Hello" behaviorConfiguration="hello">
<endpoint contract="Improving.Samples.WCF.Web.Hello" binding="webHttpBinding" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="hello">
<serviceDebug httpHelpPageEnabled="false" includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding />
</bindings>
<extensions>
<bindingExtensions>
<add name="webHttpBinding"
type="System.ServiceModel.Configuration.WebHttpBindingCollectionElement, Microsoft.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
</system.serviceModel>
Almost there. I can taste it...
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en-US">The message with Action '' cannot be processed at the receiver,
due to a ContractFilter mismatch at the EndpointDispatcher.
This may be because of either a contract mismatch (mismatched Actions between sender and receiver)
or a binding/security mismatch between the sender and the receiver.
Check that sender and receiver have the same contract and the same
binding (including security requirements, e.g. Message, Transport, None).</Text>
</Reason>
</Fault>
So, at the end of the day, I am beginning to wonder whether I can use WCF Web programming from within IIS/ASP.NET. And I am beginning to believe that the answer is "No." I am sure that if it *is* "No," it is really just a "Not there yet" rather than a "Not going there." There are challenges with integrating especially the URITemplate functionality into the IIS stack, because IIS doesn't really want to talk to you unless you have an extension (e.g. .aspx, .ashx, .svc). I am guessing that they were wrestling with that limitation. If it was an explicit design decision, I would have liked to have known this sooner, e.g. in a readme.txt or, um, say, an SDR presentation. I actually commented about this when I first learned about URITemplate and friends, but the conversation took a bit of a turn, and I didn't push on it. I wish I had have, because it would have saved me some of my spare time to focus on the features that are there today. Unless I hear otherwise, I probably won't spend any more time trying to work from within a web project. Did I stop short of the prize? Or is it actually a limitation for these bits?
For now, we'll be filing this one under "Simple things should simple."
Posted by: Erik Johnson | 2007.05.08 at 10:39 AM
Posted by: Darrel Miller | 2007.05.08 at 11:28 AM
Posted by: Steve Maine | 2007.05.08 at 11:59 AM
Posted by: Steve Maine | 2007.05.08 at 01:54 PM
Posted by: J.D. Hicks | 2008.03.11 at 04:29 PM
Posted by: Capo | 2008.10.09 at 01:44 PM