Combined SOAP/JSON/XML in WCF, using UriTemplate
- by gregmac
I'm trying to build a generic web service interface using WCF, to allow 3rd party developers to hook into our software. After much struggling and reading (this question helped a lot), I finally got SOAP, JSON and XML (POX) working together.
To simplify, here's my code (to make this example simple, I'm not using interfaces -- I did try this both ways):
<ServiceContract()> _
Public Class TestService
Public Sub New()
End Sub
<OperationContract()> _
<WebGet()> _
Public Function GetDate() As DateTime
Return Now
End Function
'<WebGet(UriTemplate:="getdateoffset/{numDays}")> _
<OperationContract()> _
Public Function GetDateOffset(ByVal numDays As Integer) As DateTime
Return Now.AddDays(numDays)
End Function
End Class
and the web.config code:
<services>
<service name="TestService"
behaviorConfiguration="TestServiceBehavior">
<endpoint address="soap" binding="basicHttpBinding" contract="TestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="TestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="TestService"/>
<endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
<behavior name="poxBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="TestServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
This actually works -- I'm able to go to TestService.svc/xml/GetDate for xml, TestService.svc/json/GetDate for json, and point a SOAP client at TestService.svc?wsdl and have the SOAP queries work.
The part I'd like to fix is the queries. I have to use TestService.svc/xml/GetDateOffset?numDays=4 instead of TestService.svc/xml/GetDateOffset/4. If I specify the UriTemplate, I get the error:
Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.
But of course without using <enableWebScript/>, JSON doesn't work.
The only other thing I've seen that I think will work is making 3 different services (.svc files), that all implement an interface that specifies the contract, but in the classes specify different WebGet/WebInvoke attributes on each class. This seems like a lot of extra work, that frankly, I don't see why the framework doesn't handle for me. The implementation of the classes would all be the same, except for the attributes, which means over time it would be easy for bugs/changes to get fixed/done in one implementation but not the others, leading to inconsistent behaviour when using the JSON vs SOAP implementation for example.
Am I doing something wrong here? Am I taking a totally wrong approach and misusing WCF? Is there a better way to do this?
With my experience doing web stuff, I think it should be possible for some kind of framework to handle this ... I even have an idea in my head of how to build it. It just seems like WCF is supposed to be doing this, and I don't really want to reinvent the wheel.