在REST服务中反序列化JSON

时间:2016-02-08 17:53:21

标签: c# json wcf rest null

我在我的其他自托管服务中反序列化json时遇到了问题。

我有一个测试页面,它使用JSON调用自托管的REST,这里是代码:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <script type="text/javascript">
        function doFunction() {

            xhr = new XMLHttpRequest();
            var url = "https://localhost:1234/business/test/testing2/endpoint";
            xhr.open("POST", url, true);
            xhr.setRequestHeader("Content-type", "application/json");
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    var json = JSON.parse(xhr.responseText);
                    alert(json);
                }
            }                            
            var data = JSON.stringify({ testing : "test" });
            xhr.send(data);
        }

    </script>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input id="clickMe" type="button" value="clickme" onclick="doFunction();" />
    </div>
    </form>

</body>
</html>

以下是我自托管服务的界面和合同:

[DataContract]
    public class OperationInput
    {
        [DataMember]
        public string testing { get; set; }

    }

    [DataContract]
    public class OperationOutput
    {
        [DataMember]
        public int Status { get; set; }

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

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

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

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

    [ServiceContract]
    interface IRegisterOperation
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "/endpoint",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json, Method = "*")]
        OperationOutput Operation(OperationInput order);
    }

以下是界面的实现:

public class RegisterOperation : IRegisterOperation
    {

        public OperationOutput Operation(OperationInput input)
        {
            System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\testing.txt", false);
            file.WriteLine(input.testing);
            file.Close(); 

            OperationOutput output = new OperationOutput();
            output.Status = 200;
            output.Message = "The action has been successfully recorded on NAVe";
            output.AddInfo = "";


            return output;
        }
    }

我正在使用以下代码创建自托管:

host = new ServiceHost(implementationType, baseAddress);

                ServiceEndpoint se = host.AddServiceEndpoint(endpointType, new WebHttpBinding(WebHttpSecurityMode.Transport), "");
                se.Behaviors.Add(new WebHttpBehavior());

                host.Open();

使用调试我注意到它命中了我的服务中的断点,因此对localhost的调用正在工作,但输入参数为null,如下图所示:

debugging on visual studio

这是在fiddler上使用JSON捕获POST请求的2个图像:

fiddler first image fiddler second image

你知道为什么我会变空吗?而不是字符串&#34; test&#34;就像我在javascript中调用一样?

非常感谢您提前;)

编辑:

我在Fiddler上激活了HTTPS Decryption,现在已经按下&#34;是&#34;在受信任的ca上安装证书而不是按下&#34; no&#34;,并且断点被命中,fiddler现在捕获了一个选项请求,如下图所示

Options request Raw tab of Options request JSON tab of Options request

这不是一个帖子请求而不是一个选项请求吗?也许这就是为什么我没有看到json?

非常感谢

3 个答案:

答案 0 :(得分:2)

我明白了,问题是OPTIONS请求,我需要收到一个POST请求,所以我得到了JSON。

我向服务主机添加了一个行为属性,以便它响应选项请求,允许wcf服务主机接收跨源请求。

所以我在这个(Cross Origin Resource Sharing for c# WCF Restful web service hosted as Windows service)问题的答案中添加了代码,现在我在第一个选项请求后收到了POST请求:

如果该链接不再可用,则以下是问题的解决方案:

<强> CODE:

按如下方式创建2个类:

  1. MessageInspector正在实施IDispatchMessageInspector
  2. BehaviorAttribute实施AttributeIEndpointBehaviorIOperationBehavior
  3. 具有以下细节:

    //MessageInspector Class
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Description;
    namespace myCorsService
    {
      public class MessageInspector  : IDispatchMessageInspector
      {
        private ServiceEndpoint _serviceEndpoint;
    
        public MessageInspector(ServiceEndpoint serviceEndpoint)
        {
          _serviceEndpoint = serviceEndpoint;
        }
    
        /// <summary>
        /// Called when an inbound message been received
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="channel">The incoming channel.</param>
        /// <param name="instanceContext">The current service instance.</param>
        /// <returns>
        /// The object used to correlate stateMsg. 
        /// This object is passed back in the method.
        /// </returns>
        public object AfterReceiveRequest(ref Message request, 
                                              IClientChannel channel, 
                                              InstanceContext instanceContext)
        {
          StateMessage stateMsg = null;
          HttpRequestMessageProperty requestProperty = null;
          if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
          {
            requestProperty = request.Properties[HttpRequestMessageProperty.Name]
                              as HttpRequestMessageProperty;
          }
    
          if (requestProperty != null)
          {
            var origin = requestProperty.Headers["Origin"];
            if (!string.IsNullOrEmpty(origin))
            {
              stateMsg = new StateMessage();
              // if a cors options request (preflight) is detected, 
              // we create our own reply message and don't invoke any 
              // operation at all.
              if (requestProperty.Method == "OPTIONS")
              {
                stateMsg.Message = Message.CreateMessage(request.Version, null);
              }
              request.Properties.Add("CrossOriginResourceSharingState", stateMsg);
            }
          }
    
          return stateMsg;
        }
    
        /// <summary>
        /// Called after the operation has returned but before the reply message
        /// is sent.
        /// </summary>
        /// <param name="reply">The reply message. This value is null if the 
        /// operation is one way.</param>
        /// <param name="correlationState">The correlation object returned from
        ///  the method.</param>
        public void BeforeSendReply(ref  Message reply, object correlationState)
        {
          var stateMsg = correlationState as StateMessage;
    
          if (stateMsg != null)
          {
            if (stateMsg.Message != null)
            {
              reply = stateMsg.Message;
            }
    
            HttpResponseMessageProperty responseProperty = null;
    
            if (reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
            {
              responseProperty = reply.Properties[HttpResponseMessageProperty.Name]
                                 as HttpResponseMessageProperty;
            }
    
            if (responseProperty == null)
            {
              responseProperty = new HttpResponseMessageProperty();
              reply.Properties.Add(HttpResponseMessageProperty.Name,
                                   responseProperty);
            }
    
            // Access-Control-Allow-Origin should be added for all cors responses
            responseProperty.Headers.Set("Access-Control-Allow-Origin", "*");
    
            if (stateMsg.Message != null)
            {
              // the following headers should only be added for OPTIONS requests
              responseProperty.Headers.Set("Access-Control-Allow-Methods",
                                           "POST, OPTIONS, GET");
              responseProperty.Headers.Set("Access-Control-Allow-Headers",
                        "Content-Type, Accept, Authorization, x-requested-with");
            }
          }
        }
      }
    
      class StateMessage
      {
        public Message Message;
      }
    }
    
    //BehaviorAttribute Class
    using System;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace OpenBetRetail.NFCReaderService
    {
      public class BehaviorAttribute : Attribute, IEndpointBehavior,
                                     IOperationBehavior
      {        
        public void Validate(ServiceEndpoint endpoint) { }
    
        public void AddBindingParameters(ServiceEndpoint endpoint,
                                 BindingParameterCollection bindingParameters) { }
    
        /// <summary>
        /// This service modify or extend the service across an endpoint.
        /// </summary>
        /// <param name="endpoint">The endpoint that exposes the contract.</param>
        /// <param name="endpointDispatcher">The endpoint dispatcher to be
        /// modified or extended.</param>
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
                                          EndpointDispatcher endpointDispatcher)
        {
          // add inspector which detects cross origin requests
          endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
                                                 new MessageInspector(endpoint));
        }
    
       public void ApplyClientBehavior(ServiceEndpoint endpoint,
                                       ClientRuntime clientRuntime) { }
    
       public void Validate(OperationDescription operationDescription) { }
    
       public void ApplyDispatchBehavior(OperationDescription operationDescription,
                                         DispatchOperation dispatchOperation) { }
    
       public void ApplyClientBehavior(OperationDescription operationDescription,
                                       ClientOperation clientOperation) { }
    
       public void AddBindingParameters(OperationDescription operationDescription,
                                 BindingParameterCollection bindingParameters) { }
    
      }
    }
    

    在此之后,您需要做的就是将此消息检查器添加到服务端点行为。

    ServiceHost host = new ServiceHost(typeof(myService), _baseAddress);
    foreach (ServiceEndpoint EP in host.Description.Endpoints)
                EP.Behaviors.Add(new BehaviorAttribute());
    

    感谢大家的帮助;)

答案 1 :(得分:1)

您有Method = "*"

我会试验:

Method = "POST" ....

[ServiceContract]
interface IRegisterOperation
{
    OperationOutput Operation(OperationInput order);
像这样:

[OperationContract]
[WebInvoke(UriTemplate = "/registeroperation",
       Method = "POST",
       ResponseFormat = WebMessageFormat.Json,
       BodyStyle = WebMessageBodyStyle.Bare)]
OperationOutput Operation(OperationInput order);

APPEND:

你的json看起来不正确(从屏幕截图中)

我希望有一些简单的东西:

{
    "ACTPRDX": "test"
}

你能做一个&#34;警报&#34;在你对对象进行字符串化之后? 并显示结果?

但是(一般情况下)......如果你的json搞砸了,那么&#34;自动伏都教&#34; Wcf Service Method的工作没有成功。

.....

这可能是挑剔的,但试试这个:

注意资本&#34; T&#34;在连字符之后。

xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

我刚刚在我的代码中找到了这个:

        var jsonObject = { ACTPRDX : "test" };
        var whatToSendOverTheWire = JSON.stringify(jsonObject);

试试。

如上所述,你的json错了。修复是弄清楚它是如何搞砸的。

答案 2 :(得分:0)

您实际上是传递原语而不是预期的对象

var data = JSON.stringify({ ACTPRDX : "test" });

以上数据适用于方法:

   public XYZ Something(string ACTPRDX)

您应该将对象发送到您的方法

var obj= new Object();
obj.ACTPRDX = "test";
var data = JSON.stringify({ order: obj});

接口和实现也有不同的名称参数OperationInput - &gt;订单和输入。

相关问题