tags:

views:

42

answers:

2

I have a service contract with several operation contracts defined. I have added a new endpoint to expose my operations as a restful webservice. Moreover I've updated operation definitions so that they can be called in a RESTful way

    [OperationContract]
    [WebInvoke(
    Method = "GET",
    ResponseFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate = "product/getall")]   
    Product[] GetAll()

Everything works fine my products are returned as XML... but I'd like to use JSON instead. If i change the code to

[OperationContract]
[WebInvoke(
Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "product/getall")]   
Product[] GetAll()

Response to product/getall call is empty. No exception is thrown, but I have a bad feeling that WCF JSON implementation somehow cannot cope with serialization. Anyone had similar problem? Any suggestions? Is i t possible to use JSON.NET to serialize/deserialize my objects?

A: 

Turn on the WCF tracing and view the trace log. That should pinpoint where the issue is. You can configure your web.config with the following settings to enable tracing.

<system.serviceModel>
  <diagnostics>
      <messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" />
  </diagnostics>
</system.serviceModel>

<system.diagnostics>
  <sources>
    <source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
      propagateActivity="true">
      <listeners>
        <add type="System.Diagnostics.DefaultTraceListener" name="Default">
          <filter type="" />
        </add>
        <add name="ServiceModelTraceListener">
          <filter type="" />
        </add>
      </listeners>
    </source>
    <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
      <listeners>
        <add type="System.Diagnostics.DefaultTraceListener" name="Default">
          <filter type="" />
        </add>
        <add name="ServiceModelMessageLoggingListener">
          <filter type="" />
        </add>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add initializeData="C:\Web_tracelog.svclog"
      type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
      name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
      <filter type="" />
    </add>
    <add initializeData="C:\Web_messages.svclog"
      type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
      name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
      <filter type="" />
    </add>
  </sharedListeners>
</system.diagnostics>
Wallace Breza
+1  A: 

I was able to get this to work - here's what I did. First off, my environment is VS2010 and I was using the VS web server (Cassini).

I didn't change your method signature or your WebInvoke attribute. The body of the GetAll() method is this:

[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "product/getall")]
Product[] GetAll()
{
    Product[] prods = new Product[3] {
        new Product() { Name="Foo", Desc="Bar"},
        new Product() {Name="Ha", Desc="Ho"},
        new Product() {Name="Who", Desc="What"}
    };

    return prods;
}

The web.config looks like this:

<system.serviceModel>
    <behaviors>
        <endpointBehaviors>
            <behavior name="WebApplication2.ProdServiceAspNetAjaxBehavior">
              <webHttp />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
        multipleSiteBindingsEnabled="true" />
    <services>
        <service name="WebApplication2.ProdService">
            <endpoint address="" behaviorConfiguration="WebApplication2.ProdServiceAspNetAjaxBehavior"
                binding="webHttpBinding" contract="WebApplication2.ProdService" />
        </service>
    </services>
</system.serviceModel>

Honestly, most of this is default out-of-the-box functionality. The only thing I changed was changing the endpointBehavior to use webHttp instead of the default enableWebScript. Other than that, it worked fine.

EDIT (forgot the Product class): Here's the Product class - I decorated it with DataContract and DataMember attributes:

[DataContract]
public class Product
{
    [DataMember()]
    public String Name { get; set; }
    [DataMember()]
    public String Desc { get; set; }
}

This was my output:

[{"Desc":"Bar","Name":"Foo"},{"Desc":"Ho","Name":"Ha"},{"Desc":"What","Name":"Who"}]

My guess is that you are using enableWebScript in your web.config. Change it to webHttp and see what happens. The enableWebScript setting is used for more ASMX type of compatibility (I believe). If you're returning JSON (which a lot of my GET service methods do), use webHttp (which is what I'm used to using).

Let me know what you get and I'll update my answer accordingly.

David Hoerster