【问题标题】:How to accept JSON in a WCF DataService?如何在 WCF 数据服务中接受 JSON?
【发布时间】:2011-10-18 13:04:06
【问题描述】:

我正在尝试了解如何使用 WCF 数据服务(基于 EF 4.1)来创建一个将作为 JSON 对象传递的实体持久化的静态 Web 服务。

我已经能够创建一个可以接受带有一组原始数据类型作为参数的 GET 请求的方法。我不喜欢那个解决方案,我更愿意在 http 请求正文中发送一个带有 JSON 对象的 POST 请求。

我发现我无法让框架为我将 json 序列化为对象,但我可以手动完成。

我的问题是我似乎无法读取 POST 请求的正文 - 正文应该是 JSON 有效负载。

下面是粗略的破解。我已经尝试了一些不同的迭代,似乎无法从请求正文中获取原始 JSON。

有什么想法吗?更好的方法来做到这一点?我只想发布一些 JSON 数据并进行处理。

    [WebInvoke(Method = "POST")]
    public void SaveMyObj()
    {
        StreamReader r = new StreamReader(HttpContext.Current.Request.InputStream);
        string jsonBody = r.ReadToEnd();  // jsonBody is empty!!

        JavaScriptSerializer jss = new JavaScriptSerializer();
        MyObj o = (MyObj)jss.Deserialize(jsonBody, typeof(MyObj));

        // Now do validation, business logic, and persist my object
    }

我的 DataService 是一个实体框架 DataService 扩展

System.Data.Services.DataService<T>

如果我尝试将非原始值作为参数添加到方法中,我会在跟踪日志中看到以下异常:

System.InvalidOperationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
'Void SaveMyObj(MyNamespace.MyObj)' has a parameter 'MyNamespace.MyObj o' of type 'MyNamespace.MyObj' which is not supported for service operations. Only primitive types are supported as parameters.

【问题讨论】:

    标签: c# json wcf-data-services ef4-code-only


    【解决方案1】:

    为您的方法添加参数。您还需要 WebInvoke 上的一些附加属性。

    这是一个例子(根据记忆,可能有点偏)

    [WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "modifyMyPerson")]
    public void Modify(Person person) {
       ...
    }
    

    使用人员类是这样的:

    [DataContract]
    public class Person {
    
    [DataMember(Order = 0)]
    public string FirstName { get; set; }
    
    }
    

    而json是这样发送的

    var person = {FirstName: "Anthony"};
    var jsonString = JSON.stringify({person: person});
    // Then send this string in post using whatever, I personally use jQuery
    

    编辑:这是使用“包装”的方法。如果没有包装方法,您将取出BodyStyle = ... 并将JSON 字符串化,您只需执行JSON.stringify(person)。我通常只使用包装方法,以防我需要添加其他参数。

    编辑完整代码示例

    Global.asax

    using System;
    using System.ServiceModel.Activation;
    using System.Web;
    using System.Web.Routing;
    
    namespace MyNamespace
    {
        public class Global : HttpApplication
        {
            protected void Application_Start(object sender, EventArgs e)
            {
                RouteTable.Routes.Add(new ServiceRoute("myservice", new WebServiceHostFactory(), typeof(MyService)));
            }
        }
    }
    

    Service.cs

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Web;
    
    namespace MyNamespace
    {
        [ServiceContract]
        [ServiceBehavior(MaxItemsInObjectGraph = int.MaxValue)]
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
        public class MyService
        {
            [OperationContract]
            [WebInvoke(UriTemplate = "addObject", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
            public void AddObject(MyObject myObject)
            {
                // ...
            }
    
            [OperationContract]
            [WebInvoke(UriTemplate = "updateObject", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
            public void UpdateObject(MyObject myObject)
            {
                // ...
            }
    
            [OperationContract]
            [WebInvoke(UriTemplate = "deleteObject", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
            public void DeleteObject(Guid myObjectId)
            {
                // ...
            }
        }
    }
    

    并将其添加到Web.config

      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
      </system.serviceModel>
    

    【讨论】:

    • 我的服务似乎不允许非原始类型作为参数。我正在使用实体框架 DataService(扩展 System.Data.Services.DataService)。如果我在参数中有任何类型的非原始类型,则会出现异常:code... 有一个类型为“MyNamespace.MyObj”的参数“MyNamespace.MyObj bv”,服务操作不支持该参数。仅支持原始类型作为参数。code
    • 这是一个不幸的缺点......如果我是你,我会放弃DataService&lt;T&gt;,除非你从中获得一些其他好处。我将编辑我的帖子以获得我使用的对我非常有用的完整代码示例。
    • 好建议,不确定是否是 DataService 的限制。据我了解,我使用该 DataService 进行自动 REST CRUD 操作(仅限 GET req)。在这种情况下,我不想要自动 CRUD,因为我需要在持久化之前执行一些验证和业务逻辑。我会尝试你的方法并在这里更新。
    • 这对我很有用。我的问题肯定是由于扩展了DataService&lt;T&gt;,令人失望的是它不支持服务方法调用的对象参数。
    • @codemonkey 这实际上是 OData 标准的限制,而不是 WCF 数据服务本身的限制。您可以破解 WCF 数据服务以获取发布数据。 Glenn Gailey 在这篇名为“Uploading Data to a Service Operation”的相关博文中简要提到了这一点:blogs.msdn.com/b/writingdata_services/archive/2011/07/05/… 话虽如此,不建议使用这种 hack,因此应序列化复杂类型(在博文中也提到)。
    猜你喜欢
    • 2013-03-09
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多