web-dev-qa-db-ja.com

ASP.NET 5 / MVC 6 Ajaxポストモデルからコントローラー

ASP.NET 5 MVC 6アプリケーションで、Ajaxを使用して一部のデータをコントローラーに投稿します。私はすでにASP.NET MVC 5でこれを行っており、空のASP.NET MVC 5プロジェクトでまったく同じコードをテストして動作しましたが、新しいバージョンではできませんし、理由もわかりません。 Ajax呼び出しを使用すると、コントローラーにアクセスできます。モデルは作成されますが、フィールドはnull(またはブール値の場合はfalse)です。ここに私のコードがあります:

script.js:

var data = {
            model: {
                UserName: 'Test',
                Password: 'Test',
                RememberMe: true
            }
        };

        $.ajax({
            type: "POST",
            url: "/Account/Login/",
            data: JSON.stringify(data),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (msg) {
                // Do something interesting here.
            }
        });

AccountController.cs:

[HttpPost]
    public JsonResult Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            //var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
            //if (result.Succeeded)
            //{
            //     //return RedirectToLocal(returnUrl);
            //}

            ModelState.AddModelError("", "Identifiant ou mot de passe invalide");
            return Json("error-model-wrong");
        }

        // If we got this far, something failed, redisplay form
        return Json("error-mode-not-valid");
    }

LoginViewModel.cs:

public class LoginViewModel
{
    [Required]
    [Display(Name = "UserName")]
    [EmailAddress]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

何か案は ?ありがとう

26

JSONを使用している場合は、MVC6でFromBodyを明示的に使用する必要があります

public JsonResult Login([FromBody]LoginViewModel model)

[〜#〜] edit [〜#〜]

さまざまなエラーが混在していると思います。リクエストの作成方法を説明します。

content-type 必須:application/json

リクエスト本文must be JSON形式(JasonLindが提案したとおり):

{
    UserName: 'Test',
    Password: 'Test',
    RememberMe: true
};

これは、リクエストを検査するとき(chromeデバッガーツールF12)またはフィドラーのようなリクエストインスペクターを使用するときに表示されるものです。

UserName=Test&Password=Test&RememberMe=trueの形式で何かが表示された場合、それは間違っていることになります。それがフォーム形式です。

model変数は必要ありません。 「ラッパー」でリクエストが表示された場合は、削除する必要があります。

30
Bart Calixto

自分でBindModelを実装できます! JSON文字列を取得し、エンティティに逆シリアル化します。

public class JsonBinder<T> : System.Web.Mvc.IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        using (var reader = new System.IO.StreamReader(controllerContext.HttpContext.Request.InputStream))
        {
            //set stream position 0, maybe previous action already read the stream.
            controllerContext.HttpContext.Request.InputStream.Position = 0;
            string json = reader.ReadToEnd();
            if (string.IsNullOrEmpty(json) == false)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                object jsonData = serializer.DeserializeObject(json);
                return serializer.Deserialize<T>(json);
            }
            else
            {
                return null;
            }
        }
    }
}

jsonBinderを次のようなpostメソッドに設定します

[HttpPost]
public JsonResult Login([ModelBinder(typeof(JsonBinder<LoginViewModel>))] LoginViewModel model)
{
    if (ModelState.IsValid)
    {
        //var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
        //if (result.Succeeded)
        //{
        //     //return RedirectToLocal(returnUrl);
        //}

        ModelState.AddModelError("", "Identifiant ou mot de passe invalide");
        return Json("error-model-wrong");
    }

    // If we got this far, something failed, redisplay form
    return Json("error-mode-not-valid");
}

他の解決策

DataContractをModelのクラスに設定し、DataMemberをクラスのプロパティに設定できることがわかりました。

このようにクラスを編集します

[DataContract]
public class LoginViewModel
{
    [DataMember]
    public string UserName { get; set; }
    [DataMember]
    public string Password { get; set; }
    [DataMember]
    public bool RememberMe { get; set; }
}

ライブラリ参照「System.Runtime.Serialization」を追加する必要があります

それがうまくいくことを願っています。

1
oudi

わかりました。解決策は見つかりましたが、それでも私にとっては奇妙なことです... content-typeリクエストから。

$.ajax({
            type: "POST",
            url: "Account/Login",
            data: data,
            success: function (msg) {
                // Do something interesting here.
            }
        });

ウォッチャーのおかげで解決策を見つけました:) Request変数を見て、Request.Formが常に例外をスローすることを発見しました。間違ったcontent-typeを使用したと言ったので、content-type私のajaxの投稿から、それは魅力のように働いた。私は、あなたが作るすべてのajax投稿について、あなたのRequest.Formが正しく記入されることに注意する必要があると思います

enter image description here

[〜#〜] edit [〜#〜]:このソリューションは、接続データのような非JSONデータ(非常に単純なデータ)を投稿できる場合にのみ機能します。しかし、リストのような複雑なデータを投稿したい場合、それはもう機能しません...

0

あなたの問題はMVC6がjQueryではないということです。 $ .ajax()は "data"をチェックし、その形式を知っているため、コンテンツタイプを設定します。また、約束の方法で$ .ajaxを使用する必要があります。

約束の有利な点を確認してください ここ

また、フォームを選択し、次のようにオブジェクトに変換します

 $('.anyForm').on('submit', fucntion(){
        //you have the form in JSON format
        var data = $(this).serializeObject()

    })

here はserializeObject()メソッドであり、デフォルトではjQueryにはありません。

すべきではない:

 var data = {
            UserName: 'Test',
            Password: 'Test',
            RememberMe: true

    };
0
JasonLind