用JSON格式从jQuery消费WCF服务

10

通过合同:

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; }
        }
    }
}

实现:

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")};
        }
    }
}

在web.config中配置如下:

<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>
我正在尝试通过jQuery从页面调用Foo:
<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>

但是我收到了一个400 - Bad Request错误,错误信息为"服务器在处理请求时遇到错误。异常消息是“反序列化类型为System.String的对象时出错。命名空间''中期望的结束元素'root'。找到了'namespace'中的'name'元素"

我是否漏掉了什么?

4个回答

15

你的params是一个对象,它形成了{"name": "someValue"}的JSON字符串。如果你说消息体的样式是Bare,我认为你的服务期望得到这样的内容:

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

因此,你的操作应该被定义为:

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

如果您想让当前代码工作,您应该将其更改为:

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

我认为将Bare和DTO结合起来是最佳实践。 - Bullines

6

我遇到了同样的问题。在设置BodyStyle=WebMessageBodyStyle.Wrapped之后,问题得到了解决。

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

Ladislav Mrnka所建议的是一个变通方法。但BodyStyle = WebMessageBodyStyle.Wrapped是正确的修复方法。 - Kuttan Sujith

4
尝试设置 BodyStyle=WebMessageBodyStyle.Wrapped 来源

0

BodyStyle = WebMessageBodyStyle.WrappedRequest 对我有用,如果你是从 Fiddler 或其他 REST 客户端发起请求, 但如果您是从 HTTPWebResponse 发起请求,则 Bare 将起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接