Как принять JSON в WCF DataService? - PullRequest
4 голосов
/ 02 августа 2011

Я пытаюсь понять, как использовать WCF Data Services (на основе EF 4.1) для создания полноценного веб-сервиса, который будет сохранять сущности, переданные как объекты JSON.

Мне удалось создать метод, который может принимать запрос GET с набором примитивных типов данных в качестве аргументов. Мне не нравится это решение, я бы предпочел отправить запрос POST с объектом JSON в теле запроса http.

Я обнаружил, что не могу заставить фреймворк сериализовать 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
    }

My DataService - это DataService Entity Framework, расширяющий

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.

1 Ответ

7 голосов
/ 03 августа 2011

Добавьте параметры в ваш метод.Вам также понадобятся некоторые дополнительные атрибуты в вашем 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>
...