自从升级到RC的WebAPI,我有一些真正奇怪的问题时调用POST在我的WebAPI。 我甚至回到了在新项目上生成的基本版本。所以:

public void Post(string value)
{
}

提琴手喊道:

Header:
User-Agent: Fiddler
Host: localhost:60725
Content-Type: application/json
Content-Length: 29

Body:
{
    "value": "test"
}

当我调试时,字符串“value”永远不会被赋值。它总是NULL。 有人有这个问题吗?

(我第一次看到这个问题是在一个更复杂的类型上)

这个问题不仅仅局限于ASP。在asp.net MVC 4中,同样的问题出现在一个新的ASP。NET MVC 3项目后RC安装


当前回答

尝试创建一个类作为数据模型,然后发送一个具有与数据模型类属性匹配的属性的JSON对象。(注:我已经测试了这个,它与我今天刚刚下载的最新的MVC 4 RC 2012一起工作)。

public HttpResponseMessage Post(ValueModel model)
{
    return Request.CreateResponse<string>(HttpStatusCode.OK, "Value Recieved: " + model.Value);
}

public class ValueModel
{
    public string Value { get; set; }
}

下面的JSON对象以HTTP-POST正文形式发送,内容类型为application/ JSON

{ "value": "In MVC4 Beta you could map to simple types like string, but testing with RC 2012 I have only been able to map to DataModels and only JSON (application/json) and url-encoded (application/x-www-form-urlencoded body formats have worked. XML is not working for some reason" }

我认为必须创建数据模型类的原因是假定简单值来自url参数,而假定单个复杂值来自主体。它们确实有[FromBody]和[FromUrl]属性,但使用[FromBody]字符串值仍然不适合我。看起来他们还在解决很多bug,所以我相信这在未来会改变。

编辑: 让XML在主体中工作。默认的XML序列化器被更改为DataContractSerializer而不是XmlSerializer。在我的全局中放入以下一行。Asax文件修复了这个问题(参考)

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

其他回答

添加一行

        ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

到function protected void Application_Start()在Global.asax.cs中为我修复了类似的问题。净MVC3。

因为你只有一个参数,你可以尝试用[FromBody]属性来修饰它,或者改变方法来接受一个带值的DTO作为属性,就像我在这里建议的:MVC4 RC WebApi参数绑定

更新:官方ASP。NET网站今天更新了一个很好的解释:https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1

简而言之,当在body中发送单个简单类型时,只发送带有等号(=)前缀的值,例如body:

=测试

尝试创建一个类作为数据模型,然后发送一个具有与数据模型类属性匹配的属性的JSON对象。(注:我已经测试了这个,它与我今天刚刚下载的最新的MVC 4 RC 2012一起工作)。

public HttpResponseMessage Post(ValueModel model)
{
    return Request.CreateResponse<string>(HttpStatusCode.OK, "Value Recieved: " + model.Value);
}

public class ValueModel
{
    public string Value { get; set; }
}

下面的JSON对象以HTTP-POST正文形式发送,内容类型为application/ JSON

{ "value": "In MVC4 Beta you could map to simple types like string, but testing with RC 2012 I have only been able to map to DataModels and only JSON (application/json) and url-encoded (application/x-www-form-urlencoded body formats have worked. XML is not working for some reason" }

我认为必须创建数据模型类的原因是假定简单值来自url参数,而假定单个复杂值来自主体。它们确实有[FromBody]和[FromUrl]属性,但使用[FromBody]字符串值仍然不适合我。看起来他们还在解决很多bug,所以我相信这在未来会改变。

编辑: 让XML在主体中工作。默认的XML序列化器被更改为DataContractSerializer而不是XmlSerializer。在我的全局中放入以下一行。Asax文件修复了这个问题(参考)

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

希望这能有所帮助。

在不同的评论和其他论坛中,我混合了一些片段,对我来说,这段代码是有效的…

... 在控制器中

public HttpResponseMessage Post([FromBody] string jsonData)
    {
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, jsonData);            

        try 
        {
            string jsonString = jsonData.ToString();
            JArray jsonVal = JArray.Parse(jsonString) as JArray;
            dynamic mylist= jsonVal;
            foreach (dynamic myitem in mylist)
            {
                string strClave=string.Empty;
                string strNum=string.Empty;
                string strStatus=string.Empty;

                strClave = myitem.clave;
                strNum=myitem.num;
                strStatus = myitem.status; 
            }

... 在WebApiConfig.cs中包含这一行,以避免[FromBody]变量var jsonFormatter = config.Formatters.OfType().First()中的空值;

public static void Register(HttpConfiguration config)
    { 
            config.Routes.MapHttpRoute(
                            name: "DefaultApi",
                            routeTemplate: "api/{controller}/{id}",
                            defaults: new { id = RouteParameter.Optional }
                        );
            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();  /*this line makes no more null when use [FromBody]*/
}

.... 在客户端,最重要的是在序列化数据之前连接等号(string json =" =" + SerialData;)

我正在使用的seralize

System.Web.Script.Serialization.JavaScriptSerializer serializer = new 
System.Web.Script.Serialization.JavaScriptSerializer();

        List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
        Dictionary<string, object> row;
        foreach (DataRow dr in DsCnx.Tables[0].Rows)
        {
            row = new Dictionary<string, object>();
            foreach (DataColumn col in DsCnx.Tables[0].Columns)
            {
                row.Add(col.ColumnName, dr[col]);
            }
            rows.Add(row);
        }
        SerialData= serializer.Serialize(rows);
       PostRequest("http://localhost:53922/api/Demo", SerialData);

这是我的PostRequest函数,这里的内容类型我使用的是httpWebRequest。ContentType = "application/x-www-form-urlencoded; "charset = utf - 8”;:

private static string PostRequest(string url, string SerialData)
    {         
        string result = String.Empty;
        HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
        httpWebRequest.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
        httpWebRequest.Method = "POST";

        using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
        {
            string json = "=" + SerialData;  
            streamWriter.Write(json);
            streamWriter.Flush();
            streamWriter.Close();
        }
        try
        {
            using (var response = httpWebRequest.GetResponse() as HttpWebResponse)
            {
                if (httpWebRequest.HaveResponse && response != null)
                {
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                        result = reader.ReadToEnd();
                    }
                }
            }
        }
        catch (WebException e)
        {
            if (e.Response != null)
            {
                using (var errorResponse = (HttpWebResponse)e.Response)
                {
                    using (var reader = new StreamReader(errorResponse.GetResponseStream()))
                    {
                        string error = reader.ReadToEnd();
                        result = error;
                    }
                }

            }
        }

        return result.ToString();

    }

以下是我找到的一个代码示例的链接:

https://weblog.west-wind.com/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing#jobject-and-jarray-in-aspnet-web-api

https://blog.codenamed.nl/2015/05/12/why-your-frombody-parameter-is-always-null/

对于那些与Swagger或Postman有相同问题的人,如果你在post中传递一个简单的属性作为字符串,即使指定了“ContentType”,你仍然会得到一个空值。

仅仅通过:

我的价值

将在控制器中获取为null。

但如果你通过了:

“我的价值”

这个值是正确的。

这里的名言起了作用。当然,这只是给斯威格和波兹曼的。例如,在使用Angular的Frontend应用中,这个问题应该由框架自动解决。