Consuming WCF from jQuery as JSON

2019-01-18 12:49发布

问题:

With a contract:

namespace ACME.FooServices
{
    [ServiceContract]
    public interface IFooService
    {
        [OperationContract]
        [WebInvoke(Method = "POST",
                   ResponseFormat = WebMessageFormat.Json,
                   RequestFormat = WebMessageFormat.Json,
                   BodyStyle = WebMessageBodyStyle.Bare)]        
        FooMessageType Foo(string name);
    }

    [DataContract]
    public class FooMessageType
    {
        string _name;
        string _date;

        [DataMember]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [DataMember]
        public string Date
        {
            get { return _date; }
            set { _date = value; }
        }
    }
}

And implementation:

using System;
using System.ServiceModel.Activation;

namespace ACME.FooServices
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class FooService : IFooService
    {
        public FooMessageType Foo(string name)
        {
            string l_name = (String.IsNullOrWhiteSpace(name)) ? "Anonymous" : name;

            return new FooMessageType {Name = l_name, Date = DateTime.Now.ToString("MM-dd-yyyy h:mm:ss tt")};
        }
    }
}

Configured in the web.config as:

<system.serviceModel>
    <services>
        <service name="ACME.FooServices.FooService">
            <endpoint address="" behaviorConfiguration="ACME.FooBehaviour" binding="webHttpBinding" contract="ACME.FooServices.IFooService" />
        </service>
    </services>
    <behaviors>
        <endpointBehaviors>
            <behavior name="ACME.FooBehaviour">
                <webHttp />
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>

I'm trying to call Foo from a page via jQuery:

<script type="text/javascript" language="javascript">
    $(document).ready(function () {
        $("#msgButton").click(function () {
            var params = {};
            params.name = $("#nameTextbox").val();

            $.ajax({
                type: 'POST',
                url: "http://acme.com/wcfsvc/FooService.svc/Foo",
                data: JSON.stringify(params),
                contentType: 'application/json; charset=utf-8',
                success: function (response, status, xhr) { alert('success: ' + response); },
                error: function (xhr, status, error) { alert("Error\n-----\n" + xhr.status + '\n' + xhr.responseText); },
                complete: function (jqXHR, status) { alert('Status: ' + status + '\njqXHR: ' + JSON.stringify(jqXHR)); }
            });
        });
    });        
</script>

But I'm getting a 400 - Bad Request error with the message "The server encountered an error processing the request. The exception message is 'There was an error deserializing the object of type System.String. End element 'root' from namespace '' expected. Found element 'name' from namespace".

Am I missing something?

回答1:

Your params is object and it forms { "name" : "someValue" } JSON string. If you say that message body style is Bare I think your service expects something like this:

[DataContract]
public class SomeDTO
{
    [DataMember(Name = "name")]
    public string Name { get; set; }
}

And because of that your operation should be defined defined as:

[OperationContract]
[WebInvoke(Method = "POST",
           ResponseFormat = WebMessageFormat.Json,
           RequestFormat = WebMessageFormat.Json,
           BodyStyle = WebMessageBodyStyle.Bare)]        
FooMessageType Foo(SomeDTO data);

If you want your current code to work you should probably change it to:

[OperationContract]
[WebInvoke(Method = "POST",
           ResponseFormat = WebMessageFormat.Json,
           RequestFormat = WebMessageFormat.Json,
           BodyStyle = WebMessageBodyStyle.WrappedRequest)]        
FooMessageType Foo(SomeDTO data);


回答2:

i got the same issue. after setting BodyStyle=WebMessageBodyStyle.Wrapped it solved.

[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]


回答3:

Try setting BodyStyle=WebMessageBodyStyle.Wrapped

source



回答4:

BodyStyle = WebMessageBodyStyle.WrappedRequest worked for me if you are requesting from fiddler or other rest clients but if you are requesting from HTTPWebResponse Bare would be working