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.
Actually <enableWebScript />
is not required for "pure" JSON support. The WebScriptEnablingBehavior
is only required if you want to support ASP.NET AJAX. More often than not, if you're trying to work with standard script libraries, you don't want to enable this support for your services.
Instead what you want to do for your JSON endpoint is just use the WebHttpBehavior
and set the DefaultOutgoingResponseFormat="JSON". The problem is, in .NET 3.5, you cannot control this setting through config because WebHttpElement
does not expose these properties for configuration. To work around this in 3.5 have supplied an implementation for what I call the EnhancedWebHttpElement
here in this answer to another StackOverflow question.
Luckily Microsoft realized this shortcoming and enabled configuration of all the WebHttpBehavior
settings via the WebHttpElement
in 4.0.
Drew's answer is spot on, but I think the question still stands. Is there a sane way of having JSON for AJAX () and the blessings of UriTemplate?
I think it is worth mentioning that JSON returned with is different than JSON generated with [WebGet(ResponseFormat=WebMessageFormat.Json)]. The former is wrapped around the the MS AJAX 'd' element e.g. {"d":[{...}]}.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With