tags:

views:

6927

answers:

3

Hi,

I am proper struggling getting that "magic" moment when WCF is configured nicely and jQuery is structuring its requests/understanding responses nicely.

I have a service:

<%@ ServiceHost Language="C#" Debug="true" Service="xxx.yyy.WCF.Data.ClientBroker" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"   %>

This was recommended by the man Rick Strahl at http://www.west-wind.com/WebLog/posts/310747.aspx to avoid having to define the behaviours within web.Config.

My interface for the WCF service sits in another assembly:

 namespace xxx.yyy.WCF.Data
{

    [ServiceContract(Namespace = "yyyWCF")] 
    public interface IClientBroker
    {
     [OperationContract]
     [WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
     IClient GetClientJson(int clientId);

    }
}

The concrete service class is:

namespace xxx.yyy.WCF.Data
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    class ClientBroker : IClientBroker 
    {
     public IClient GetClientJson(int clientId)
     {
                    IClient client=new Client();

      // gets and returns an IClient
                    return client;

     }


    }
}

My IClient is an Entity Framework class so is decorated with DataContract/DataMember attributes appropriately.

I am trying to call my WCF service using the methods outlined on Rick Strahl's blog at http://www.west-wind.com/weblog/posts/324917.aspx (the "full fat" version). The debugger jumps into the WCF service fine (so my jQuery/JSON is being understood) and gets the IClient and returns it. However, when I return the response, I get various useless errors. The errors I am getting back don't mean much.

I am using POST.

Am I right to be using an Interface instead of a concrete object? As it does get into the WCF service, it does seem to be the encoding of the result that is failing.

Also, using .NET 3.5 SP1.

Does anyone have any ideas?

+1  A: 

I am 99% sure you cant return an interface. I dont think Interfaces are serializable.

check out this thread

Mike_G
Thanks Mike, you are indeed right. So much for my nice Interface-based API, eh?! Have demoted my WCF interface to JSON strings, bringing serialization "in house".
Program.X
+5  A: 

At first glance there are three problems with your code:

1: you should use the ServiceKnownTypeAttribute to specify known types when exposing only base types in your operation contracts:

[ServiceContract(Namespace = "yyyWCF")]     
public interface IClientBroker
{
    [OperationContract]
    [ServiceKnownType(typeof(Client))]
    [WebInvoke(
        Method="GET",
        BodyStyle=WebMessageBodyStyle.WrappedRequest,
        ResponseFormat=WebMessageFormat.Json)]
    IClient GetClientJson(int clientId);

}

2: You should use WebMessageBodyStyle.WrappedRequest instead of WebMessageBodyStyle.Wrapped because the latter is not compatible with WebScriptServiceHostFactory.

3: IMHO using Method="GET" would be more RESTful for a method called GetClientJson than Method="POST"

Another advice I could give you when working with WCF services is to use SvcTraceViewer.exe bundled with Visual Studio. It is a great tool for debugging purposes. All you need is to add the following section to your app/web.config:

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="sdt"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "WcfDetailTrace.e2e" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

Then invoke the web method and WcfDetailTrace.e2e file will be generated in your web site root directory. Next open this file with SvcTraceViewer.exe and you will see lots of useful information. For example it could say:

Cannot serialize parameter of type 'MyNamespace.Client' (for operation 'GetClientJson', contract 'IClientBroker') because it is not the exact type 'MyNamespace.IClient' in the method signature and is not in the known types collection. In order to serialize the parameter, add the type to the known types collection for the operation using ServiceKnownTypeAttribute.

Of course you should not forget commenting this section before going into production or you might end up with some pretty big files.

Darin Dimitrov
Thank Darin, It turns out my problem is with JSON serializing Entity Framework objects (blogged: http://tinyurl.com/cc4k37). But your tip about SvcTraceViewer was invaluable in reminding me of this great tool and also spotting the exception. Also: Agreed about REST for some methods, just not this 1!
Program.X
A: 

Related to the question, a while ago I posted an article on my blog showing all the steps needed to get a WCF service working together with jQuery code on the client side:

http://yoavniran.wordpress.com/2009/08/02/creating-a-webservice-proxy-with-jquery/

poeticGeek