2011-08-02 52 views
4

我想了解如何使用WCF数据服务(基于EF 4.1)来创建一个宁静的Web服务,它将持久实体作为JSON对象传递。如何在WCF DataService中接受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. 

回答

8

将参数添加到您的方法中。您还需要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)。我通常使用包装的方法,以防我需要添加其他参数。

EDIT对于完整的代码示例

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> 
+0

我的服务似乎不允许非基元类型作为参数。我正在使用实体框架DataService(扩展System.Data.Services.DataService )。如果我在参数中有任何非原始类型,我会得到一个异常:'code' ...具有不受服务操作支持的类型为“MyNamespace.MyObj”的参数“MyNamespace.MyObj bv”。只有原始类型支持参数.'code' – codemonkey

+1

这是一个不幸的缺点...如果我是你,我会放弃'DataService ',除非你从中获得某种其他好处。我将编辑我的帖子,查看我使用的完整代码示例,这对我来说非常合适。 –

+0

好的建议,不确定是否是DataService 的限制。据我所知,我使用该DataService获得了自动REST CRUD操作(仅限GET请求)。在这种情况下,我不希望自动CRUD,因为我需要在持续之前执行一些验证和业务逻辑。我会尝试你的方法并在此后更新。 – codemonkey