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