BradLaney
BradLaney

Reputation: 2413

WCF JSONP returns blank/empty document when NULL is returned

I am using the JSONP samples provided by Microsoft. http://msdn.microsoft.com/en-us/library/cc716898(v=vs.90).aspx

JSONPEncoderFactory JSONPBindingExtension JSONPBindingElement JSONPBehavior

Everything works fine, except when returning null. Instead of what I want, which is: callback(null); It returns a blank document which causes an error with most JSONP frameworks like

jQuery.ajax({jsonp:"callback"}); 

I put breakpoints on every method call in the custom classes and the one that does all the work:

public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)

The closest I've came to finding a solution is mere speculation. I thought that maybe the WebServiceHost class might have a method I can override to build in the functionality I am expecting, but so far I have come up empty handed.

I wanted to also mention I am not using the WebScriptServiceHostFactory class because of the following issue:

Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.

If I use this factory, returning null causes the functionality I am looking for. However, then I cannot use TemplateUri's, and I am using those for the HMAC encryption. Since I cannot use headers in JSONP requests are formatted as

/Service/Action/publicKey-signature?params

I tried finding a standard for HMAC over a JSONP type request but couldn't find anything. This was the cleanest I could come up with. Params is used as the signature.

UPDATE:

The things I were missing when attempting the below solution were you have to make sure that on your web.config you build a webHttpBinding that has crossDomainScriptAccessEnabled="true". Also you have to make sure to not use the behavior. Also do not use the WebScriptServiceHostFactory. You can use the WebServiceHostFactory, but then you must have this in a web.config (or do it for the single service through binding):

<system.serviceModel>
    <standardEndpoints>
        <webHttpEndpoint>
            <standardEndpoint crossDomainScriptAccessEnabled="true" />
        </webHttpEndpoint>
    </standardEndpoints>
</system.serviceModel>

Upvotes: 0

Views: 521

Answers (1)

carlosfigueira
carlosfigueira

Reputation: 87238

The 4.0 framework has native JSONP support, and it does support URI templates, as shown in the example below. You'll need to enable the support on the WebHttpBinding class (or in config, if you prefer).

public class StackOverflow_7974435
{
    [ServiceContract]
    public class Service
    {
        [WebGet(UriTemplate = "/Sum?x={x}&y={y}")]
        public int Add(int x, int y)
        {
            return x + y;
        }
        [WebGet(UriTemplate = "/Data?isNull={isNull}")]
        public string GetData(bool isNull)
        {
            return isNull ? null : "Hello world";
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        WebHttpBinding binding = new WebHttpBinding { CrossDomainScriptAccessEnabled = true };
        WebHttpBehavior behavior = new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Json };
        host.AddServiceEndpoint(typeof(Service), binding, "").Behaviors.Add(behavior);
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        Console.WriteLine("Not a JSONP call");
        Console.WriteLine(c.DownloadString(baseAddress + "/Sum?x=6&y=8"));

        Console.WriteLine("A JSONP call");
        Console.WriteLine(c.DownloadString(baseAddress + "/Sum?x=6&y=8&callback=MyFunction"));

        Console.WriteLine("A JSONP call returning string");
        Console.WriteLine(c.DownloadString(baseAddress + "/Data?isNull=false&callback=MyFunction"));

        Console.WriteLine("A JSONP call returning null");
        Console.WriteLine(c.DownloadString(baseAddress + "/Data?isNull=true&callback=MyFunction"));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

Update: added also another operation which returns null, and the calls to it. In the first call (returning string), the service returns MyFunction("Hello world");, while in the second case it correctly returns MyFunction(null);. As I mentioned in the comments, if you're not using the ASP.NET AJAX framework, do not use the WebScriptEnablingBehavior, as it's not meant to be used for other frameworks.

Upvotes: 1

Related Questions