Search code examples
jqueryvb.netwcfjsondeserialization

WCF not deserializing JSON - Parameters in web service are null


I am having the same issues as per this question: WCF not deserializing JSON input

I am at a loss and desperate for a solution. I have scoured the net for answers, but I have found only this question that matches my exact problem. My datacontract parameter is also nothing when the service starts.

I have tried the points of the answer in the question above, but they provide me with no clues (The web service executes OK -I am not getting any exceptions - and I can't see what the deserializer is doing - or not doing as the case may be).

I am using POST, due to the size of the nested JSON.

Could some WCF wizard, or the original poster of that question, please enlighten me?

If more detailed information is needed, I will provide it on request. My issue is so very similar to that question I was hoping the OP could pass on how he resolved the problem.

Updated

Code snippets - I'm under NDA, so can't post specifics.

"In-Page JS":

var settings = {
        a: $("#a").val(),
        b: $("#b").val(),
        c: $("#c").val(),
        d: $("#d").val(),
        e: $("#e").val(),
        f: $("#f").prop("checked").toString(),
        g: $("#g").prop("checked").toString()
    };

    var data= {
        a: [1011,1012,1013],
        b: JSON.stringify(settings),
        c: "01/01/2011 23:59:59"
    };

Library.Services.Post("path/to/service/Service.svc/SaveSettings", data, true, function (result) {

        if (result.Succeeded) {
            ShowSuccess("Success.");
        }
        else {
            ShowError("Failure.");
        }

    });

"Library.Services.Post":

Post: function (serviceUrl, data, async, successHandler, errorHandler) {
        var continueOperation = true;

        if (!data) {
            data = "{}";
        }

        try {
            var obj = $.parseJSON(data);
            obj = null;
        }
        catch (err) {
            continueOperation = false;
            JS.ShowError("Data attribute is not a valid JSON object");
        }

        if (typeof (data) !== "string") {
            data = JSON.stringify(data);
        }

        if (continueOperation) {
            Library.Services._ajax("POST", serviceUrl, data, async, successHandler, errorHandler);
        }

        continueOperation = null;
    }

"Library.Services._ajax":

_ajax: function (method, serviceUrl, data, async, successHandler, errorHandler) {

        if (!typeof (successHandler) === "function") {
            continueOperation = false;
            ShowError("Success handler must be a function");
        }

        try {
            $.ajax({
                async: async,
                cache: false, // don't cache results
                type: method,
                url: Library.Services.baseUrl + serviceUrl,
                contentType: "application/json; charset=utf-8",
                data: data,
                dataType: "json",
                processData: false, // data processing is done by ourselves beforehand
                success: function (data, statusText, request) {

                    if (data != null) {
                        if (data.d && data.d.__type) {
                            data = data.d;
                        }
                        else {
                            // Wrapped message: return first property
                            $.each(data, function (name, value) {
                                data = value;
                                return false;
                            });

                        }
                    }

                    successHandler(data, statusText, request);

                },
                error: function (request, statusText, error) {
                    //debugger;    
                    var res = request.responseText;

                    if (request.status != 200) {
                        if (!request.isResolved()) {
                            ShowError(request.status + " " + request.statusText);
                        }
                        else {
                            ShowError("Request could not be resolved.");
                        }
                    }
                    else {
                        ShowError("Unknown error status.");
                    }

                    if (typeof (errorHandler) === "function") {
                        errorHandler();
                    }

                }
            });
        }
        catch (err) {
            ShowError("AJAX call failed");
        }
    }

"Service.svc":

<DataContract()>
Public Class SaveSettingsContract
    <DataMember(Order:=1)>
    Public a() As String

    <DataMember(Order:=2)>
    Public b()() As String

    <DataMember(Order:=3)>
    Public c As String

End Class

<OperationContract()>
<WebInvoke(BodyStyle:=WebMessageBodyStyle.Wrapped,
        RequestFormat:=WebMessageFormat.Json,
        ResponseFormat:=WebMessageFormat.Json)>
Public Function SaveSettings(ByVal settings as SaveSettingsContract) As WebServiceResults.BaseResult

   ' At this point in debugging, settings is Nothing


End Function

Solution

  • I believe I found the answer to this question.

    I think the reason the parameter was null was because this:

    var data= {
        a: [1011,1012,1013],
        b: JSON.stringify(settings),
        c: "01/01/2011 23:59:59"
    };
    

    should be this:

    var data = {
        settings: {
            a: [1011,1012,1013],
            b: JSON.stringify(settings),
            c: "01/01/2011 23:59:59"
        }
    }
    

    The data I wanted needed to be wrapped in a settings variable that matched the name of the parameter of the SaveSettings method. The service doesn't automatically put the data you send up into the settings parameter.

    It sounds blindingly obvious now I look back at it, but for some reason I missed this when I was creating the service originally.

    Edit: I believe I missed this because with the old asmx services, you could pass in the data in the same order as the parameters and the service automatically populated the parameters with the correct values. In WCF, however, that is not the case and you have to explicitly specify them.