簡體   English   中英

在REST服務中反序列化JSON

[英]Deserializing JSON in REST Service

我在我的其他自托管服務中反序列化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,如下圖所示:

在visual studio上調試

這是在fiddler上使用JSON捕獲POST請求的2個圖像:

提琴手第一張圖片 提琴手第二張圖片

你知道為什么我會變空嗎? 而不是像我在javascript中調用那樣的字符串“test”?

非常感謝您提前;)

編輯:

我在Fiddler上激活了HTTPS Decryption,現在按下“Yes”將證書安裝在受信任的ca上,而不是按下“no”,斷點被點擊,fiddler現在捕獲了一個選項請求,如下圖所示

選項請求 選項請求的原始選項卡 選項請求的JSON選項卡

這不應該是一個帖子請求而不是一個選項請求?? 也許那就是為什么我沒有看到json?

非常感謝

我想通了,問題是OPTIONS請求,我需要收到一個POST請求,所以我得到了JSON。

我向我的服務主機添加了一個行為屬性,以便它響應選項請求,允許wcf服務主機接收跨源請求。

所以我從這個問題的答案中添加了代碼( 作為Windows服務托管的c#WCF Restful Web服務的跨源資源共享 )問題,現在我在第一個Options請求之后得到一個POST請求:

如果鏈接不再可用,以下是問題的解決方案:

碼:

創建2個類,如下所示:

  1. MessageInspector實現IDispatchMessageInspector
  2. BehaviorAttribute實現AttributeIEndpointBehaviorIOperationBehavior

具有以下細節:

//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());

謝謝大家的幫助;)

你有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);

附加:

你的json看起來不正確(從屏幕截圖)

我希望有一些簡單的東西:

{
    "ACTPRDX": "test"
}

你可以在對對象進行字符串化后立即進行“提醒”嗎? 並顯示結果?

但是(一般情況下)......如果你的json搞砸了,Wcf服務方法的“自動伏都教”將無效。

.....

這可能是挑剔的,但試試這個:

注意連字符后面的大寫“T”。

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

我剛剛在我的代碼中找到了這個:

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

試試吧。

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

你實際上傳遞原始而不是預期的對象

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 - > order和input。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM