WCF - 从System.SystemModel.Channels.Message中检索JSON正文

时间:2014-03-21 15:26:42

标签: c# json wcf post router

我原来的服务合同:

[ServiceContract(
    Namespace = "http://my.framework/superservices/myservice",
    Name = "IMyServiceContract")]
public interface IMyServiceContract
{
    [OperationContract]
    [FaultContract(typeof(MyFaultContract))]
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
        UriTemplate = "GetMyItemListJSONMC")]
    GetListResponse GetMyItemListJSONMC(GetListRequest request);

    // Other methods like this.
}

我想通过POST发送给我的服务的请求:

[MessageContract]
public class GetListRequest
{
    [MessageBodyMember]
    public int NbItems {get;set;}

    [MessageBodyMember]
    public DateTime? InputDate { get; set; }

    [MessageBodyMember]
    public string AnotherParameter { get; set; }

    [MessageBodyMember]
    public MyItem ACoolItem { get; set; }
}

[DataContract(
    Namespace="http://my.framework/superservices/myservice/types",
    Name="MyItem")]
public class MyItem
{
    [DataMember]
    public int BirthYear { get; set; }

    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }

    [DataMember]
    public DateTime? BirthFullDate { get; set; }
}

我想从我的服务中获得的回复:

[MessageContract]
public class GetListResponse
{
    [MessageBodyMember]
    public List<MyItem> Result { get; set; }

    [MessageBodyMember]
    public string ReceivedUsername { get; set; }

    [MessageBodyMember]
    public string ReceivedPassword { get; set; }
}

客户代码:

private void CallService<TRequest, TResponse>()
{

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestedUri);
        request.Method = "POST";
        request.ContentType = "application/json; charset=utf-8";

            DataContractJsonSerializer serRequest = new DataContractJsonSerializer(typeof(TRequest));
            using (MemoryStream ms = new MemoryStream())
            {
                serRequest.WriteObject(ms, requestObject);
                String json = Encoding.UTF8.GetString(ms.ToArray());
                using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
                {
                    writer.Write(json);
                }
            }


            // Read Response
            WebResponse response = request.GetResponse();
            using (Stream stream = response.GetResponseStream())
            {
                if (stream != null)
                {
                    string temp = new StreamReader(stream).ReadToEnd();
                    return Deserialize<TResponse>(temp);
                }
                return default(TResponse);
            }
}

原始服务配置:

<endpoint address="" binding="webHttpBinding" bindingConfiguration="security"
    name="HttpGetUseEndpoint" behaviorConfiguration="JSONBehavior"
    contract="ServiceContracts.IMyServiceContract"/>

  <endpointBehaviors>

    <behavior name="JSONBehavior">
      <webHttp faultExceptionEnabled="True"/>
      <dataContractSerializer maxItemsInObjectGraph="20000000"/>
    </behavior>

  </endpointBehaviors>


    <behavior name="InternalServiceBehavior">
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <serviceMetadata httpGetEnabled="false"/>
      <serviceThrottling maxConcurrentCalls="1500" maxConcurrentSessions="1500" maxConcurrentInstances="1500"/>
      <dataContractSerializer maxItemsInObjectGraph="20000000"/>
    </behavior>

使用此服务,我可以使用POST发送JSON请求,并在我的服务实现中处理它们,如下所示:

[ServiceBehavior(Name = "MyService",
    Namespace = "http://my.framework/advertiserservices/myservice")]
public class MyService : IMyServiceContract
{
    public GetListResponse GetMyItemListJSONMC(GetListRequest request)
    {
              // Do the Job and return the response.
    }
 }

现在,我想通过一种路由实现替换此服务实现,我可以捕获对合同的任何服务方法的所有请求。为此,我调整了配置:

<service name="ServiceImplementation.RoutingService"
behaviorConfiguration="InternalServiceBehavior">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="security" name="HttpGetUseEndpoint" behaviorConfiguration="JSONBehavior" contract="ServiceContracts.IRouterService"/>
</service>

我实现了我的路由器接口:

[ServiceContract]
public interface IRouterService
{
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json, UriTemplate = "*")]
    Message ProcessMessage(Message message);
}

和服务实现本身:

    public Message ProcessMessage(Message message)
    {
        UriTemplateMatch uriTemplate = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
        string methodName = uriTemplate.RelativePathSegments.First();

        // Routing)
        switch (methodName.ToUpper())
        {
            case "GETMYITEMLISTJSONMC":

               // 1st try to retrieve the JSON from Message:
                 TypedMessageConverter converter = TypedMessageConverter.Create(typeof(GetListRequest), string.Empty, string.Empty);
                 GetListRequest typedMessage = (GetListRequest)converter.FromMessage(message);

               // 2nd Try to retreive JSON from Message
               GetListRequest request = message.GetBody<GetListRequest>();

        return WebOperationContext.Current.CreateJsonResponse(new GetListResponse());
           break;

          }
    }

现在终于来了我的问题和我的问题:

运行此代码和调试,我希望输入中的传入System.ServiceModel.Channels.Message包含纯JSON结构,但是看看QuickWatch,我看到某种带有JSON括号的纯XML:

{<root type="object">
  <ACoolItem type="object">
    <BirthFullDate type="null">
    </BirthFullDate>
    <BirthYear type="number">1981</BirthYear>
    <FirstName type="string">Cool First Name</FirstName>
    <LastName type="null">
    </LastName>
  </ACoolItem>
  <AnotherParameter type="string">jsonPost</AnotherParameter>
  <InputDate type="string">/Date(1395414903106+0100)/</InputDate>
  <NbItems type="number">5</NbItems>
</root>}

这使我无法在服务端反序列化请求,因为代码中的两种技术都需要JSON。

如何让输入Message包含纯JSON而不是JSON和XML这种奇怪的混合?

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我做了类似的事情,在这种情况下我确实使用了message.GetBody,它运行良好。对于.net的较新版本,请考虑使用message.GetReaderAtBodyContents。我没有在服务器端设置任何特殊的序列化。

尝试将主体作为流读取,然后将其读入字符串。您可以将该字符串传递给json反序列化器。请注意,我没有指定任何特殊的RequestFormat。这是服务器端的一些示例代码(使用行为webhttp&amp; webhttpbinding:)

[ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        [WebInvoke(Method = "POST", 
            UriTemplate = TestService.ROUTER_URL, 
            ResponseFormat = WebMessageFormat.Json
            BodyStyle = WebMessageBodyStyle.Wrapped)]
        Message Router(Message message);
    }

public class TestClass
{
    public string test { get; set; }
}

public class TestService : ITestService
{
    public const string ROUTER_URL = "/Router/*";

    public Message Router(Message message)
    {

        TestClass testClassInstance;
        /*
        (See further down for .net 4 solution)
        using (var reader = new StreamReader(message.GetBody<Stream>()))
        {
            testClassInstance = Newtonsoft.Json.JsonConvert.DeserializeObject<TestClass>(reader.ReadToEnd());
        }*/

        return WebOperationContext.Current.CreateJsonResponse(new { Whatever = "yes"});
    }
}

在客户端,我只是喜欢:

var webClient = new WebClient();

using (var upstream = webClient.OpenWrite(url, "POST"))
{
    using (var writer = new StreamWriter(upstream))
    {
        writer.Write("{ \"test\" : \"json\" }");
    }
}

修改:

使用小于.net4.5的版本时,message.GetBody方法似乎工作得很糟糕。这是另一个与.net4一起使用的解决方案。在您的服务方法中,请改为:

using (var reader = message.GetReaderAtBodyContents())
{
    reader.Read();

    var whatever = System.Text.Encoding.UTF8.GetString(reader.ReadContentAsBase64());
    testClassInstance = Newtonsoft.Json.JsonConvert.DeserializeObject<TestClass>(whatever);
    Console.WriteLine("Server: testClassInstance.test = {0}", testClassInstance.test);
}