簡體   English   中英

為什么POST參數類型必須是通用的對象類型?

[英]Why does POST parameter type have to be generic Object type?

使用asp.net web api v2,我有一個工作的POST方法,我可以從不同的應用程序POST一個自定義類型,並通過使用JSONConvert我能夠反序列化它並在我的POST方法體中使用它。

但是,我的POST參數必須是“object”類型,否則找不到參數(null)。

為什么會這樣? 我理想情況下將自定義類型作為參數類型,以便我的API文檔可以填充正確的請求信息,因為它會根據所使用的參數類型自動生成API文檔(看不到覆蓋它的方法 - - 如果可能的話會很棒)。

請參閱下面的代碼 - 如果“incomingInformation”的類型為“RemoteFileInfo”而不是類型“object”,則在嘗試.toString()時會拋出null異常。

[Route("api/xx/uploadfiletoalfresco/")]
    [HttpPost()]
    public ResultStruct UploadFileToAlfresco(object incomingInformation)
    {
        JObject deserializedJObject = (JObject)JsonConvert.DeserializeObject(incomingInformation.ToString());
        SA.Services.RemoteFileInfo convertedRemoteFileInfo = deserializedJObject.ToObject<SA.Services.RemoteFileInfo>();
...

這是我在發送應用程序(vb.net)上的示例代碼 - 內容類型設置為application / json並在發送之前被序列化

Dim req As WebRequest = WebRequest.Create(_restEndpointURL & "/uploadfiletoalfresco/")
    req.ContentType = "application/json"
    req.Method = "POST"
    Using sw As New StreamWriter(req.GetRequestStream())
        Dim ser As New JavaScriptSerializer
        Dim serJSON = ser.Serialize(JsonConvert.SerializeObject(remoteFileInfo))
        sw.Write(serJSON)
        sw.Flush()
        sw.Close()
    End Using

下面是我的remoteFileInfo類型,它在接收應用程序和發送應用程序上都以這種方式聲明。 在通過JsonConvert.SerializeObject方法發送之前,它將轉換為JSON字符串

Partial Public Class RemoteFileInfo
    Public CategoryID As Integer
    Public FileName As String
    Public Length As Long
    Public Note As String
    Public SFSubmissionID As String
    Public SourceInstance As String
    Public Subject As String
    Public UserID As Integer
    Public Visibility As Boolean
    Public riskID As Integer
    Public fileByteArray As Byte()
End Class

接收應用定義:

 public class RemoteFileInfo
{

    public int CategoryID;
    public string FileName;
    public long Length;
    public string Note;
    public string SFSubmissionID;
    public string SourceInstance;
    public string Subject;
    public int UserID;
    public bool Visibility;
    public int riskID;
    public Byte[] fileByteArray;
}

來自發送應用程序的示例JSON:

"{"CategoryID":2,"FileName":"Scrum postponed until this afternoon .msg","Length":62976,"Note":"asdf","SFSubmissionID":"006E000000OuYxP","SourceInstance":"Addin","Subject":"Scrum postponed until this afternoon ","UserID":0,"Visibility":true,"riskID":0,"fileByteArray":"VERY LONG STRING"}"

來自fiddler的完整JSON:

POST http://yyyy/api/xxx/uploadfiletoalfresco/ HTTP/1.1
Content-Type: application/json
Host: yyyyy
Content-Length: 84273
Expect: 100-continue
Connection: Keep-Alive

"{\"CategoryID\":2,\"FileName\":\"Scrum postponed until this afternoon .msg\",\"Length\":62976,\"Note\":\"asdf\",\"SFSubmissionID\":\"006E000000OuYxP\",\"SourceInstance\":\"Addin\",\"Subject\":\"Scrum postponed until this afternoon \",\"UserID\":0,\"Visibility\":true,\"riskID\":0,\"fileByteArray\":\"VERY LONG STRING - user edited this is not how it looks in fiddler!\"}"

出現這種行為的原因是您的參數必須通過請求字符串傳輸。 在您的Route屬性中,您說您的方法請求應如下所示: api/xx/uploadfiletoalfresco/ 並且瀏覽器無法在查詢字符串中為對象創建字符串表示形式 - 這只能用於字符串或值類型(如整數)。

因此,您有兩個選擇:讓事物保持原樣或使用WCF服務,您可以在其中為類型提供WSDL。

我剛剛使用您在帖子中提供的數據使用WebAPI 2對此進行了測試,並使用string for fileByteArray並將模型聲明為RemoteFileInfo對我來說效果很好。

 public class RemoteFileInfo
    {

        public int CategoryID;
        public string FileName;
        public long Length;
        public string Note;
        public string SFSubmissionID;
        public string SourceInstance;
        public string Subject;
        public int UserID;
        public bool Visibility;
        public int riskID;
        public string fileByteArray;
    }


    public class ValuesController : ApiController
    {
        [HttpPost]
        public string Test(object incomingInformation)
        {
            JObject deserializedJObject = (JObject)JsonConvert.DeserializeObject(incomingInformation.ToString());
            var convertedRemoteFileInfo = deserializedJObject.ToObject<RemoteFileInfo>();
            return convertedRemoteFileInfo.fileByteArray;
        }
    }

綁定模型不需要手動反序列化

實際上,如果您使用string那么Web API模型綁定器將為您完成所有工作:

 [HttpPost]
 public string Test(RemoteFileInfo incomingInformation)
 {
      return incomingInformation.fileByteArray; //or whatever
 }

但是,如果在處理它之前確實需要fileByteArrayByte[]數組,則需要從RemoteFileInfo (它只是一個DTO,因此應該永遠不會離開API控制器)進行一些轉換。

您可以編寫自定義模型綁定器,但我認為接受更簡單的模型並明確轉換更簡單。

更新

我想我的答案可能會有些混亂,所以我會試着澄清我的想法以及我認為在這種情況下會發生什么。

  1. WebAPI Model Binder正在查看POST數據,然后嘗試查看它是否適合Action方法中聲明的參數類型 如果這是object那么它將起作用,因此允許它以incomingInformation的形式向方法提供非null object實例

  2. 您的代碼是手動處理序列化,顯然JsonConvert能夠處理將string轉換為Byte[]

  3. 在嘗試將incomingInformation聲明為RemoteFileInfo類型時,您看到失敗的原因是因為默認的WebAPI Model Binder 無法處理 string- string->Byte[]的轉換,因此放棄嘗試將傳入的POST數據序列化為實例RemoteFileInfo ,而是將null傳遞給方法的incomingInformation參數。

  4. 在這一點上,任何嘗試引用或執行任何對incomingInformation都將失敗,並且NullReferenceException等等。

  5. 讓Web API模型綁定器成功綁定該模型的唯一方法是a)將fileByteArray更改為字符串(因為它是線上的字符串),在這種情況下,我的第二個代碼示例應該正常工作,或者b)編寫自定義Model Binder(個人而非粉絲)

我當然可能完全錯了,但由於你的代碼對我使用Fiddler和我提到的chanes很好,我懷疑上面的觀點是這種情況還是你還沒有包含其他一些因素。

感謝所有評論的人。 事實證明這個問題與使用JsonConvert.SerializeObject有關。 雖然在Fiddler中,json字符串看起來很完美,但我突然想到將序列化方法切換到JavaScriptSerializer()。Serialize,RemoteFileInfo對象成功傳遞和接收(完整的字節數組!)

這是我的請求的最終代碼,它將允許接收應用程序將RemoteFileInfo作為參數類型。 仍然不確定為什么JsonConvert.Serialize不起作用; Newstonsoft軟件包安裝在客戶端和接收應用程序上。

var httpWebRequest = (HttpWebRequest)WebRequest.Create(@"http://yyyy/api/xxx/uploadfiletoalfresco/");
            httpWebRequest.ContentType = "application/json";
            httpWebRequest.Method = "POST";

            using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
            {
                string json = new JavaScriptSerializer().Serialize(remoteFileInfo);
                streamWriter.Write(json);
            }

            var response = (HttpWebResponse)httpWebRequest.GetResponse();
            using (var streamReader = new StreamReader(response.GetResponseStream()))
            {
                var result = streamReader.ReadToEnd();
            }

暫無
暫無

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

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