web-dev-qa-db-ja.com

Web APIの複雑なパラメータープロパティはすべてnull

ユーザーの設定を更新するWeb APIサービスコールがあります。残念ながら、jQuery ajax呼び出しからこのPOSTメソッドを呼び出すと、リクエストパラメーターオブジェクトのプロパティは、渡されたものではなく、常にnull(またはデフォルト値)になります。 RESTクライアント(私はPostmanを使用))を使用すると、うまく機能します。これで何が間違っているのかわかりませんが、以前に誰かがこれを見たことを期待しています。

これが私のリクエストオブジェクトです。

public class PreferenceRequest
{
    [Required]
    public int UserId;

    public bool usePopups;
    public bool useTheme;
    public int recentCount;
    public string[] detailsSections;
}

UserControllerクラスのコントローラーメソッドは次のとおりです。

    public HttpResponseMessage Post([FromBody]PreferenceRequest request)
    {
        if (request.systemsUserId > 0)
        {
            TheRepository.UpdateUserPreferences(request.UserId, request.usePopups, request.useTheme,
                                         request.recentCount, request.detailsSections);

            return Request.CreateResponse(HttpStatusCode.OK, "Preferences Updated");                
        }
        else
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "You must provide User ID");
        }
    }

これが私のajax呼び出しです。

var request = {
    UserId: userId,
    usePopups: usePopups,
    useTheme: useTheme,
    recentCount: recentCount,
    detailsSections: details
};

$.ajax({
    type: "POST",
    data: request,
    url: "http://localhost:1111/service/User",
    success: function (data) {
        return callback(data);
    },
    error: function (error, statusText) {
        return callback(error);
    }
});

DataTypeとcontentTypeをいくつかの異なるもの(「json」、「application/json」など)に設定しようとしましたが、リクエストオブジェクトのプロパティは常にデフォルトまたはnullです。したがって、たとえば、このオブジェクトを渡すと:

var request = {
  UserId: 58576,
  usePopups: false,
  useTheme: true,
  recentCount: 10,
  detailsSections: ['addresses', 'aliases', 'arrests', 'events', 'classifications', 'custody', 'identifiers', 'phone', 'remarks', 'watches']
}

上記の有効な値を持つ完全に読み込まれたリクエストオブジェクトを見ることができます。ただし、Web APIコントローラーにはリクエストがありますが、プロパティは次のとおりです。

  UserId: 0,
  usePopups: false,
  useTheme: false,
  recentCount: 0,
  detailsSections: null

参考までに、Web APIをサービスとして使用し、jQuery $ .ajaxを使用してすべての呼び出しを行うだけで、このプロジェクトでASP.Net MVCまたはASP.NETページを実行していません。

ここで私が間違っていることは何ですか?ありがとう!

UPDATE:この同じWeb APIプロジェクトには、これを行う他のコントローラーの多くのメソッドがあることに注意してくださいまったく同じこと、そして私はまったく同じ方法と呼んでいます、そしてそれらは完璧に動作します!朝、さまざまな呼び出しを比較しましたが、メソッドやヘッダーに違いはないようですが、この特定のメソッドでは機能しません。

また、Putメソッドへの切り替えも試みましたが、まったく同じ結果が得られました。リクエストオブジェクトは入っていますが、正しい値が入力されていません。とてもイライラするのは、このプロジェクトに約20のコントローラークラスがあり、それらすべてで投稿が機能することです...

36
Eddie

これは、Asp.Net WebAPIに関する一般的な問題のようです。
通常、nullオブジェクトの原因は、jsonオブジェクトのC#オブジェクトへの逆シリアル化です。残念ながら、デバッグするのは非常に難しいため、問題の場所を見つけてください。
json全体をオブジェクトとして送信し、手動で逆シリアル化することをお勧めします。少なくともこの方法では、nullの代わりに実際のエラーが発生します。
オブジェクトを受け入れるようにメソッドシグネチャを変更する場合は、JsonConvertを使用します。

public HttpResponseMessage Post(Object model)
        {
            var jsonString = model.ToString();
            PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
        }
54
blorkfish

多分それは助けになるでしょう、私は同じ問題を抱えていました。

すべてがうまく機能し、突然、すべてのプロパティがデフォルトになりました。

いくつかの簡単なテストの後、私は問題を引き起こしているのは[Serializable]であることがわかった

public IHttpActionResult Post(MyComplexClass myTaskObject)
{
    //MyTaskObject is not null, but every member are (the constructor get called).
}

ここに私のクラスのスニペットがありました:

[Serializable]  <-- have to remove that [if it was added for any reason..]
public class MyComplexClass()
{
     public MyComplexClass ()
     {
        ..initiate my variables..
     }

     public string blabla {get;set;}
     public int intTest {get;set;
}
11
Simon

@blorkfishが投稿したこの手法を使用すると、うまくいきました。

public HttpResponseMessage Post(Object model)
    {
        var jsonString = model.ToString();
        PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
    }

いくつかのネイティブ型といくつかのオブジェクトをプロパティとして持つパラメーターオブジェクトがありました。オブジェクトには内部としてマークされたコンストラクターがあり、jsonStringのJsonConvert.DeserializedObject呼び出しでエラーが発生しました。

タイプChildObjectBに使用するコンストラクターが見つかりません。クラスには、デフォルトのコンストラクター、引数を持つコンストラクター、またはJsonConstructor属性でマークされたコンストラクターのいずれかが必要です。

コンストラクターをパブリックに変更し、オブジェクトモデルパラメーターを実際のオブジェクトに置き換えると、パラメーターオブジェクトが設定されるようになりました。ありがとう!

4
Russell D

問題は、コントローラーが[FromBody]のコンテンツタイプを想定しているため、コントローラーを

public HttpResponseMessage Post(PreferenceRequest request)

とajaxへ

$.ajax({
    type: "POST",
    data: JSON.stringify(request);,
    dataType: 'json',
    contentType: "application/json",
    url: "http://localhost:1111/service/User",

ところで、JavaScriptでモデルを作成することはベストプラクティスではない場合があります。

4
Anshul Nigam

つまり、値がバインドされない場所を知っている3つの問題があります:

  1. no パブリックパラメータレス ctor
  2. プロパティはpublic settableではありません
  3. ModelState.Valid == falseとなるバインディングエラーがあります-一般的な問題は次のとおりです:互換性のない値型(文字列に対するJSONオブジェクト、GUID以外など)

したがって、バインディングの結果がエラーになった場合にエラーを返すフィルターをAPI呼び出しに適用する必要があるかどうかを検討しています。

3
baHI

私もこの問題に直面していますが、debbugと研究から何時間も問題がContent-TypeまたはType $ Ajax属性によって引き起こされたのではなく、JSONオブジェクトのNULL値によって引き起こされた問題であることに気付くことができますPOSTは作成せず、一度NULL値を修正すると、POSTは問題なく、ここでコードを私のrespuestaComparacionクラスにネイティブにキャストします。

JSON

 respuestaComparacion: {
                            anioRegistro: NULL, --> cannot cast to BOOL
                            claveElector: NULL, --> cannot cast to BOOL
                            apellidoPaterno: true,
                            numeroEmisionCredencial: false,
                            nombre: true,
                            curp: NULL, --> cannot cast to BOOL
                            apellidoMaterno: true,
                            ocr: true
                        }

コントローラ

[Route("Similitud")]
[HttpPost]
[AllowAnonymous]

public IHttpActionResult SimilitudResult([FromBody] RespuestaComparacion req)
{
   var nombre = req.nombre;
}

クラス

public class RespuestaComparacion
    {
        public bool anioRegistro { get; set; }
        public bool claveElector { get; set; }
        public bool apellidoPaterno { get; set; }
        public bool numeroEmisionCredencial { get; set; }
        public bool nombre { get; set; }
        public bool curp { get; set; }
        public bool apellidoMaterno { get; set; }
        public bool ocr { get; set; }
    }

この助けを願っています。

2
Jorge Solano

パーティーに少し遅れましたが、この同じ問題があり、修正はajax呼び出しでcontentTypeを宣言していました:

    var settings = {
        HelpText: $('#help-text').val(),
        BranchId: $("#branch-select").val(),
        Department: $('input[name=departmentRadios]:checked').val()

    };

$.ajax({
        url: 'http://localhost:25131/api/test/updatesettings',
        type: 'POST',
        data: JSON.stringify(settings),
        contentType: "application/json;charset=utf-8",
        success: function (data) {
            alert('Success');
        },
        error: function (x, y, z) {
            alert(x + '\n' + y + '\n' + z);
        }
    });

APIコントローラーは次のように設定できます。

    [System.Web.Http.HttpPost]
    public IHttpActionResult UpdateSettings([FromBody()] UserSettings settings)
    {
//do stuff with your UserSettings object now
        return Ok("Successfully updated settings");
    }
2
Dan

私は知っている、これは少し遅いですが、私はちょうど同じ問題に遭遇しました。 @blorkfishの答えも私にとってはうまくいきましたが、別の解決策に導かれました。複雑なオブジェクトの一部の1つに、パラメーターなしのコンストラクターがありませんでした。このコンストラクターを追加すると、Put要求とPost要求の両方が期待どおりに機能し始めました。

2
Storm

私は同じ問題に出くわしました。必要な修正は、JSONからパラメータークラスへのすべてのシリアル化可能なプロパティがgetを持つようにすることでした。セット;明示的に定義されたメソッド。 C#の自動プロパティ構文に依存しないでください!これがasp.netの以降のバージョンで修正されることを願っています。

1
Rams Ramanathan

私の場合、追加すると問題は解決しました

get {} set {}

パラメータクラス定義へ:

public class PreferenceRequest
{
    public int UserId;
    public bool usePopups {get; set;}
    public bool useTheme {get; set;}
    public int recentCount {get; set;}
    public string[] detailsSections {get;set;}
}

代わりに:

   public class PreferenceRequest
    {
        [Required]
        public int UserId;
        public bool usePopups;
        public bool useTheme;
        public int recentCount;
        public string[] detailsSections;
    }
0
alexey

私は同じ問題に遭遇しました、私のための解決策は、クラス属性のタイプをjson属性に一致させることでした

Json: "attribute": "true"

ブール値ではなく文字列として扱う必要があります。このような問題がある場合、障害のある属性の下にあるすべての属性はデフォルトでnullになります

0
Igor Vargas

私の問題は他のどの回答でも解決されなかったため、この解決策は検討する価値があります。

次のDTOとコントローラーメソッドがありました。

public class ProjectDetailedOverviewDto
{
    public int PropertyPlanId { get; set; }

    public int ProjectId { get; set; }

    public string DetailedOverview { get; set; }
}

public JsonNetResult SaveDetailedOverview(ProjectDetailedOverviewDto detailedOverview) { ... }

DTOにはパラメーター(detailedOverview)と同じ名前のプロパティがあるため、デシリアライザーは混乱し、複雑なオブジェクト全体ではなく文字列をパラメーターに設定しようとしました。解決策は、コントローラーメソッドパラメーターの名前を'overview'に変更して、デシリアライザーがプロパティにアクセスしようとしていないことを認識させることでした。

0
Delorian

私はこの問題に直面し、これは私にそれを修正します

  1. モデルで属性[JsonProperty( "json requestのプロパティ名")]を使用します。
  2. オブジェクトをシリアル化する場合は、PostAsyncのみを呼び出します

そのように

var json = JsonConvert.SerializeObject(yourobject);
var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
var response = await client.PostAsync ("apiURL", stringContent);
  1. 動作しない場合は、[ボディから] APIから削除します
0
Mostafa Elzaref

今日も同じ問題に遭遇しました。これらすべてを試した後、AzureからAPIをデバッグし、Xamarin Androidアプリをデバッグすると、参照更新の問題であることがわかりました。APIにNewtonsoft.JSON NUGETがあることを確認してくださいパッケージが更新されました(使用している場合)。

0
SHOTdeJAGER

HttpGet

public object Get([FromBody]object requestModel)
{
    var jsonstring = JsonConvert.SerializeObject(requestModel);
    RequestModel model = JsonConvert.DeserializeObject<RequestModel>(jsonstring);
}
0
Tarrah Arshad

今日、私はあなたと同じ問題を抱えています。 POSTからajaxリクエストを送信すると、コントローラーはNullおよびデフォルトのプロパティ値を持つ空のオブジェクトを受け取ります。メソッドは次のとおりです。

_[HttpPost]
public async Task<IActionResult> SaveDrawing([FromBody]DrawingModel drawing)
{


    try
    {

        await Task.Factory.StartNew(() =>
        {
            //Logic
        });
        return Ok();
    }
    catch(Exception e)
    {
        return BadRequest();
    }
}
_

私の_Content-Type_は正しかったし、他のすべても正しかった。多くのことを試した後、次のようにオブジェクトを送信することがわかりました。

_$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: dataToPost
}).done((response) => { }); 
_

動作しませんが、代わりに次のように送信しました:

_$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(dataToPost)
}).done((response) => { }); 
_

はい、欠落しているJSON.stringify()が問題全体を引き起こし、_=_を接頭辞または接尾辞として_JSON.stringify_に置く必要はありません。少し掘った後。リクエストペイロードの形式が2つのリクエスト間で完全に異なることがわかりました
これは_JSON.stringify_を含むリクエストペイロードです

Request payload with JSON.stringify

そして、これは_JSON.stringify_なしのリクエストペイロードです

Request payload without JSON.stringify

そして、物事が魔法のようになり、_Google Chrome_を使用してWebアプリケーションをテストするときを忘れないでください。 キャッシュを空にしてハードリロードを行う 時々。

0
Mahmoud

昨日、この問題がほぼ一日中私を悩ませていたので、同じ状況で他の人を助けるかもしれない何かを追加したいと思います。

Xamarin Studioを使用してangularおよびweb apiプロジェクトを作成しました。デバッグ中にオブジェクトがnullを通過する場合があります。ポストリクエストごとにオブジェクトが入力されたVisual Studioこれは、Xamarin Studioでデバッグするときに問題になるようです。

別のIDEでこのnullパラメータの問題が発生している場合は、Visual Studioでデバッグしてみてください。

0
tno2007