Frage

My original Service Contract:

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

The request I want to send with POST to my service:

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

The response I want to get from my service:

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

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

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

Client Code:

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);
            }
}

The original Service Config:

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

With this service, I can send JSON Request using POST and handle them in my service implementation like this:

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

Now, I want to replace this service implementation by a kind of routing implementation where I could catch all the requests to any service method of my contract. To do this, I adapt the configuration:

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

I implement my router interface:

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

and the service implementation itself:

    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;

          }
    }

Now finally comes my problem and my question:

Running this code and debugging, I am expecting the incoming System.ServiceModel.Channels.Message in input to contain a pure JSON structure but looking with QuickWatch, I see some kind of plain-XML mixed with JSON brackets:

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

This makes that I cannot deserialize the request on service side, because both techniques exposed in the code abover expects JSON.

How can I get the input Message to contain pure JSON instead of this curious mix of JSON and XML?

Thanks for your help.

War es hilfreich?

Lösung

I have done something similar, and in this case I did use message.GetBody, and it worked fine. For younger versions of .net, consider using message.GetReaderAtBodyContents instead. I did not setup any special serialization on server side.

Try reading the body as a stream, and read that into a string. You can pass that string to a json deserializer. Notice that I have not specified any special RequestFormat. Here's some example code on the server side (using behaviour webhttp & 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"});
    }
}

On client side I just do like:

var webClient = new WebClient();

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

Edit:

The message.GetBody method seems to work badly when using a version younger than .net4.5. Here's another solution that works with .net4. In your service method, do this instead:

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top