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.
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":[{...}]}.
Actually
<enableWebScript />
is not required for "pure" JSON support. TheWebScriptEnablingBehavior
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 becauseWebHttpElement
does not expose these properties for configuration. To work around this in 3.5 have supplied an implementation for what I call theEnhancedWebHttpElement
here in this answer to another StackOverflow question.Luckily Microsoft realized this shortcoming and enabled configuration of all the
WebHttpBehavior
settings via theWebHttpElement
in 4.0.You have specified integer parameters in your operation. URI template does not work well with int parameters. Please change it to string , It will work.
I think you have to write your own QuerystringConverter to use int with URITemplate.