简体   繁体   中英

ASP.NET 5 / MVC 6 Ajax post Model to Controller

In my ASP.NET 5 MVC 6 application, I want to post with Ajax some data to my controller. I already done this with ASP.NET MVC 5 and I tested the exact same code in an blank ASP.NET MVC 5 project and it worked, but with the new version I can't and I don't know why. With the Ajax call, I can go to the controller, the model is created but the fields are null (or false for the boolean). Here is my code :

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; }
}

Any ideas ? Thanks

You need to explicit use FromBody on MVC6 if you are using json

public JsonResult Login([FromBody]LoginViewModel model)

EDIT

I think you are mixing different errors. I will try to describe how you should make the request:

content-type must be : application/json

your request body must be in JSON format (as JasonLind suggested):

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

this is what you should see when inspecting the request (via chrome debugger tools F12) or using a request inspector like fiddler.

If you see something in the form of UserName=Test&Password=Test&RememberMe=true then you are doing it wrong, that's form format.

you don't need the model variable. if you see your request with a "wrapper" then you should remove it.

You can implement BindModel yourself! get the json string and deserialize to your entity.

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;
            }
        }
    }
}

and set the JsonBinder to the post method like

[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");
}

the other solution

I found that you could set DataContract to the class of Model, and set DataMember to the Properties of the class.

edit the class like this

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

and you should add library reference "System.Runtime.Serialization"

Hope it can works for u.

Shouldn't it be:

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

    };

Ok I found the solution, but it's still strange for me ... You just have to remove the content-type from the request.

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

I've found the solution thanks to the watcher :) I watched the Request variable, and I found that Request.Form thrown always an exception. It said that I used a wrong content-type, so I just removed the content-type from my ajax post and it worked like a charm. I think that, for every ajax post you will make, you have to be careful that your Request.Form is filled correctly

在此输入图像描述

EDIT : This solution works only when you could post non-json data (very simple data), like connexion data. But if I want post complex data, like a list, it doesn't work anymore ...

Your problem is not MVC6 is jQuery. $.ajax() check the "data" and know its format so sets the content type for your, and also you should use $.ajax in a promise fashion

check promises vantages here

and also select the form and just turn into to object, like

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

    })

and here is serializeObject() method, it is not on jQuery by default.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM