214

RC for WebAPI にアップグレードしてから、WebAPI で POST を呼び出すときに奇妙な問題が発生しています。新しいプロジェクトで生成された基本バージョンに戻りました。そう:

public void Post(string value)
{
}

そしてフィドラーからの呼び出し:

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

Body:
{
    "value": "test"
}

デバッグすると、文字列「値」が割り当てられません。それは常にNULLです。この問題を抱えている人はいますか?

(私はより複雑なタイプの問題を最初に見ました)

この問題は ASP.NET MVC 4 に限定されているだけでなく、RC インストール後の新しい ASP.NET MVC 3 プロジェクトでも同じ問題が発生します。

4

41 に答える 41

114

私は今日、これについて頭を悩ませてきました。

私の解決策は、 を に変更し[FromBody]HttpRequestMessage本質的に HTTP スタックを上に移動することです。

私の場合、データをネットワーク経由で送信していますが、これは圧縮された json であり、その後 base64 化されます。これはすべてAndroidアプリからです。

私の Web エンドポイントの元の署名は次のようになりました (を使用[FromBody]):

私の元のエンドポイント

HttpRequestMessageこの問題に対する私の修正は、エンドポイントの署名にを使用するように戻すことでした。

ここに画像の説明を入力

次に、次のコード行を使用して投稿データにアクセスできます。

ここに画像の説明を入力

これは機能し、未加工の未加工の投稿データにアクセスできます。文字列の先頭に = 記号を付けたり、コンテンツ タイプを変更したりする必要はありません。

余談ですが、最初に上記の回答の1つに従って、コンテンツタイプを「Content-Type: application/x-www-form-urlencoded」に変更しようとしました。生データの場合、+ 文字が取り除かれるため、これは悪いアドバイスです。

つまり、「MQ0AAB+LCAAAAAA」のように始まる base64 文字列は、「MQ0AAB LCAAAAAA」のようになります! あなたが望むものではありません。

使用するもう 1 つの利点はHttpRequestMessage、エンドポイント内からすべての http ヘッダーにアクセスできることです。

于 2014-08-05T17:04:06.980 に答える
108

パラメータは 1 つしかないため、[FromBody]属性で装飾するか、プロパティとして値を持つ DTO を受け入れるようにメソッドを変更することができます。

更新: 公式の ASP.NET サイトが本日更新され、優れた説明が追加されました: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part- 1

簡単に言うと、本文で単純な型を 1 つ送信する場合は、等号 (=) を前に付けた値のみを送信します。例: body:

=test

于 2012-06-11T19:05:37.163 に答える
19

データ モデルとして機能するクラスを作成してから、データ モデル クラスのプロパティと一致するプロパティを持つ 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]and[FromUrl]属性がありますが、使用して[FromBody] string valueもうまくいきませんでした。彼らはまだ多くのバグを解決しているように見えるので、これは将来変更されると確信しています.

編集: 本文で動作するように XML を取得しました。デフォルトの XML シリアライザーは、XmlSerializer ではなく DataContractSerializer に変更されました。Global.asax ファイルに次の行を追加すると、この問題が修正されました (参照)

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
于 2012-07-05T07:15:56.733 に答える
11

私と同じようにSwaggerPostmanで同じ問題を抱えている人のために、投稿で単純な属性を文字列として渡すと、「ContentType」が指定されていても、null 値が返されます。

渡すだけ:

マイバリュー

コントローラでは null として取得されます。

しかし、あなたが合格した場合:

「マイバリュー」

値が正しくなります。

ここで引用符が違いを生みました。もちろん、これは Swagger と Postman のみです。たとえば、Angular を使用するフロントエンド アプリでは、これはフレームワークによって自動的に解決される必要があります。

于 2016-11-26T11:48:24.097 に答える
4

Web API メソッドのリクエスト オブジェクトが常に null であるという同様の問題がありました。コントローラーのアクション名に "Get" というプレフィックスが付いているため、Web API はこれを POST ではなく HTTP GET として扱っていることに気付きました。コントローラー アクションの名前を変更した後、意図したとおりに動作するようになりました。

于 2013-08-09T13:32:56.953 に答える
3

Angular を使用すると、次の形式でデータを渡すことができました。

 data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }),
 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }

そして Web API コントローラーで:

    [HttpPost]
    public Hashtable Post([FromBody]string jsonString)
    {
        IDictionary<string, string> data = JsonConvert.DeserializeObject<IDictionary<string, string>>(jsonString);
        string username = data["u"];
        string pwd = data["p"];
   ......

または、次のような JSON データを投稿することもできます。

    data: { PaintingId: 1, Title: "Animal show", Price: 10.50 } 

そして、コントローラでは、次のようなクラス タイプを受け入れます。

    [HttpPost]
    public string POST(Models.PostModel pm)
    {

     ....
    }

どちらの方法でも機能します。API に確立された public クラスがある場合は JSON を投稿し、そうでない場合は '=' + JSON.stringify({..: ..., .. : ... }) を投稿します

于 2015-07-03T00:11:16.317 に答える
2

行を追加する

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

protected void Application_Start()Global.asax.csの関数の最後まで、ASP.NET MVC3 で同様の問題を修正しました。

于 2012-06-11T16:48:51.113 に答える
2

Xml Formatter または JSON Formatter にDataContractSerializerを使用している場合は、それを取り除く必要があります。私は WebApiConfig ファイルにこれを持っていました:

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();
     jsonFormatter.UseDataContractJsonSerializer = true;
}

単純にコメントアウトするjsonFormatter.UseDataContractJsonSerializer = true;と、入力パラメーターが null ではなくなりました。手がかりを与えてくれた「Despertar」に感謝します。

于 2015-07-31T00:42:55.530 に答える
2

パラメータとして null を取得するという同じ問題がありましたが、それは大きなオブジェクトに関連していました。問題は IIS の最大長に関連していることが判明しました。これは web.config で構成できます。

  <system.web>
    <httpRuntime targetFramework="4.7" maxRequestLength="1073741824" />
  </system.web>

Web API がエラーを抑制し、null オブジェクトを API に送信するのはなぜだろうか。Microsoft.AspNet.WebApi.Tracing を使用してエラーを見つけました。

于 2017-11-22T22:57:21.227 に答える
1

これがこの質問に対する答えではないことはわかっていますが、問題の解決策を探しているときに見つけました。

私の場合、複合型はバインドされていませんでしたが、POST を実行していませんでした。クエリ文字列パラメーターを使用して GET を実行していました。解決策は、引数に [FromUri] を追加することでした。

public class MyController : ApiController
{
    public IEnumerable<MyModel> Get([FromUri] MyComplexType input)
    {
        // input is not null as long as [FromUri] is present in the method arg
    }
}
于 2012-09-08T14:03:30.717 に答える
1

MVC 6 に渡す単純な JSON オブジェクトを処理するために私が見つけた最も簡単な方法は、NewtonSoft jObject のような post パラメーターの型を取得することです。

public ActionResult Test2([FromBody] jObject str)
{
        return Json(new { message = "Test1 Returned: "+ str }); ;
}
于 2016-09-07T13:48:30.980 に答える
1

私はフィドラーでも同じ問題を抱えていました。私はすでにリクエストヘッダーにContent-Type: application/json; charset=utf-8orを持っていました。Content-Type: application/json

リクエストの本文もプレーンな文字列で、Fiddler では次のように記述していました{'controller':'ctrl'}。これにより、私の POST メソッドの文字列パラメーターが になりnullました。

修正: 引用符を使用して、文字列を示すことを忘れないでください。つまり、書いて修正しました"{'controller':'ctrl'}"。(注: JSON を記述するときは、必ずアポストロフィを使用するか、次のように引用符をエスケープしてください: "{\"controller\":\"ctrl\"}")。

于 2015-04-13T19:45:01.253 に答える
1

JSON.stringify(...) が私の問題を解決しました

于 2019-05-22T15:35:32.723 に答える
1

少し遅れてしまいましたが、コントローラーの使用時に渡された NULL 値に出くわした人は、単に "=" を POST リクエストの前に追加してください。

application/json Content-Typeを使用すると、コントローラも NULL 値を渡しました。以下の「application/x-www-form-urlencoded」Content-Type に注意してください。ただし、API からの戻り値の型は「application/json」です。

 public static string HttpPostRequest(string url, Dictionary<string, string> postParameters)
    {
        string postData = "=";

        foreach (string key in postParameters.Keys)
        {
            postData += HttpUtility.UrlEncode(key) + "="
                  + HttpUtility.UrlEncode(postParameters[key]) + ",";
        }

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        myHttpWebRequest.Method = "POST";

        byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);

        myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
        myHttpWebRequest.ContentLength = data.Length;

        Stream requestStream = myHttpWebRequest.GetRequestStream();
        requestStream.Write(data, 0, data.Length);
        requestStream.Close();

        HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

        Stream responseStream = myHttpWebResponse.GetResponseStream();

        StreamReader myStreamReader = new StreamReader(responseStream, System.Text.Encoding.Default);

        string pageContent = myStreamReader.ReadToEnd();

        myStreamReader.Close();
        responseStream.Close();

        myHttpWebResponse.Close();

        return pageContent;
    }
于 2017-01-23T07:14:28.520 に答える
1

ASP.NET Core で同様の問題が発生しました。別の考えられる原因は、null を非 null プロパティにバインドするように送信するなど、さまざまな理由による ASP.NET バインディング (サイレント) の失敗です。

{
    "prop1":1139357,
    "prop2":1139356,

    "items":[
        {"key":"15","someprop":34,"notnullprop":null},
        {"key":"16","someprop":34,"notnullprop":null},
        {"key":"22","someprop":34,"notnullprop":null}]
}

このような場合、例外はスローされず、オブジェクト階層の奥深くで発生した場合でも、モデル全体が null になります。

于 2019-01-22T12:54:35.907 に答える
0

本文の単一パラメーターを WebAPI に正しく渡すと、このコードが機能します$.post(url, { '': productId }

そしてそれを行動で捉える[HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)

重要なのは、魔法の言葉「値」を使用することです。int または何らかのプリミティブ型の場合もあります。コンテンツ タイプやヘッダーの修正に関係なく、このコードは mvc ポスト アクションでは機能しません。

于 2015-08-04T08:08:35.730 に答える
0

OP が最初に単一の文字列を送信していたことは知っていますが、今後の参考のために、不正な形式の JSON もnullpost メソッドに到達することに注意してください。私の場合、2 つのプロパティの間にコンマがないと、正常に機能していたものが壊れてしまいました。

于 2020-02-12T11:18:52.370 に答える
0

お役に立てれば。

さまざまなコメントや他のフォーラムを見て、いくつかのスニペットを混ぜて、私にとって、このコードは機能します...

... コントローラーで

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] 変数の null 値を回避するためにこの行を含めます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/

于 2019-01-04T16:52:45.167 に答える
-3

このリンクは私を助けました: http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/

基本的に、パラメーターには空の名前を使用する必要があると書かれています。

public string Post([FromBody]string myParameter){ 
...
}  

$.post("/api/dosomething", { '' : "myvalue" });
于 2015-12-09T16:26:02.420 に答える