5

WebAPI では、バリデーション プラクティスを台無しにしている矛盾に気付きました。xml で POST を使用して不適切なボディ/ペイロードを送信すると、逆シリアル化が失敗し、null ポインターが返されます。JSON で不正なボディ/ペイロードを送信すると、代わりに空のオブジェクトが返されます。それは誤解を招くものであり、私はそれが好きではありません。失敗したjsonのデシリアライズでヌルポインタを強制する方法はありますか??

更新: 逆シリアル化の問題はありません。DataContractSerializer と Json.net シリアライザーの違いと思われる動作の問題があります。xml が逆シリアル化に失敗すると、ペイロードは null になります。ただし、Json がデシリアライズに失敗すると、予想されるペイロードのデフォルト インスタンスをインスタンス化しているように見えます。

不適切な xml ペイロードの例: ここに画像の説明を入力

不正な json ペイロードを使用した同じ呼び出しの例 (ペイロードは null ではなく、ペイロード クラスの既定のインスタンスです)

ここに画像の説明を入力

4

2 に答える 2

4

デフォルトでは、Web.API は のMissingMemberHandling.Ignore設定を使用しましたJsonMediaTypeFormatter

次のように設定する必要がありますMissingMemberHandling.Error

GlobalConfiguration.Configuration
   .Formatters.JsonFormatter
   .SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;

nullJSONを送信すると、次のようになります。

{
   "somenotexistingprop": ""
}

ただし、完全に空の JSON オブジェクトを送信する{}と、 ではなく空のプロパティを持つオブジェクトが取得されますnull。空の JSON を逆シリアル化すると、空のオブジェクトが返されるためです (このgithubJsonConvert.DeserializeObjectの単体テストを参照してください)。

于 2013-04-23T21:25:15.747 に答える
1

私のチーム メンバーの 1 人が、この状況が当てはまる理由を理解するのを手伝ってくれた後、このシナリオに関するいくつかのメモを以下に示します。

  1. デフォルトでは、Json フォーマッタに「MissingMemberHandling.Error」はありません。これは、新しいバージョンのクライアントが余分なメンバーを含むデータを古いバージョンのサービスに送信するシナリオで役立つ可能性があるためです。サービスの古いバージョンは、この要求を受け入れ、余分なプロパティを無視できるはずです。この動作は、Xml フォーマッタの動作とも一致しています。

  2. @Sinaesthetic: 「MissingMemberHandling.Error」を設定していて、「ModelState.IsValid」チェックのみに依存したくない場合は、常に ModelState の Keys プロパティをチェックして、メンバーが見つからないためにリクエストが実際に無効かどうかを確認できます。または、他の何か。

以下の例:

public class Customer
{
    public int Id { get; set; }

    [MaxLength(5)]
    public string Name { get; set; }

    public Address Address { get; set; }
}

public class Address
{
    public string Line1 { get;set;}
}

//action
public void Post([FromBody]Customer customer)
    {
        if (!ModelState.IsValid)
        {
            ModelStateDictionary msd = new ModelStateDictionary();

            foreach (string key in ModelState.Keys)
            {
                if (ModelState[key].Errors.Count > 0)
                {
                    foreach (ModelError error in ModelState[key].Errors)
                    {
                        Exception ex = error.Exception;

                        if (ex != null 
                            && typeof(JsonSerializationException).IsAssignableFrom(ex.GetType()) 
                            && ex.Message.StartsWith("Could not find member"))
                        {
                            msd.AddModelError(key, ex);
                        }
                    }
                }
            }

            if (msd.Count > 0)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, msd));
            }
        }

        //process the supplied customer
    }
于 2013-05-02T06:01:37.373 に答える