如何在 WCF 数据服务中接受 JSON?

发布于 2024-11-27 10:54:16 字数 1305 浏览 5 评论 0原文

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

我已经能够创建一个可以接受以一组原始数据类型作为参数的 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.

I'm trying to understand how to use WCF Data Services (based on EF 4.1) to create a restful web service that will persist entities passed as JSON objects.

I've been able to create a method that can accept a GET request with a set of primitive data types as arguments. I don't like that solution, I would prefer to send a POST request with a JSON object in the http request body.

I've found that I can't get the framework to serialize the json into an object for me, but i would be fine with doing it manually.

My problem is that I can't seem to read the body of the POST request - the body should be the JSON payload.

Here's a rough crack at it below. I've tried a few different iterations of this and can't seem to get the raw JSON out of the request body.

Any thoughts? A better way to do this? I just want to POST some JSON data and process it.

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

My DataService is an Entity Framework DataService that extends

System.Data.Services.DataService<T>

If I try adding non-primitive values as parameters to the method, i see the following exception in the trace log:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

若有似无的小暗淡 2024-12-04 10:54:16

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

这是一个例子(从记忆中,所以可能有点偏离)

[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "modifyMyPerson")]
public void Modify(Person 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>

Add parameters to your method. You'll also want some additional attributes on your WebInvoke.

Here's an example (from memory so it might be a little off)

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

With person class something like this:

[DataContract]
public class Person {

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

}

And json sent like this

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

EDIT: This is using "wrapped" approach. Without wrapped approach you would take out the BodyStyle = ... and to stringify the JSON you would just do JSON.stringify(person). I just usually use the wrapped methodology in case I ever need to add additional parameters.

EDIT For full code sample

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)
        {
            // ...
        }
    }
}

And add this to Web.config

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文