ASP.NET 5 / MVC 6 Ajax post 模型到控制器
ASP.NET 5 / MVC 6 Ajax post Model to Controller
在我的 ASP.NET 5 MVC 6 应用程序中,我想 post 和 Ajax 一些数据到我的控制器。我已经用 ASP.NET MVC 5 完成了这个,我在一个空白的 ASP.NET MVC 5 项目中测试了完全相同的代码并且它有效,但是对于新版本我不能而且我不知道为什么.
通过 Ajax 调用,我可以转到控制器,创建模型但字段为空(或布尔值为 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; }
}
有什么想法吗?
谢谢
不应该是:
var data = {
UserName: 'Test',
Password: 'Test',
RememberMe: true
};
好的,我找到了解决方案,但对我来说还是很奇怪......
您只需从请求中删除 content-type
。
$.ajax({
type: "POST",
url: "Account/Login",
data: data,
success: function (msg) {
// Do something interesting here.
}
});
感谢观察者,我找到了解决方案 :) 我观察了 Request 变量,发现 Request.Form 总是抛出异常。它说我使用了错误的内容类型,所以我只是从我的 ajax post 中删除了 content-type
,它就像一个魅力。我认为,对于每一个 ajax post,你必须小心你的 Request.Form 被正确填写
编辑:
此解决方案仅在您可以 post 非 json 数据(非常简单的数据)时有效,例如连接数据。但是如果我想要 post 复杂的数据,比如列表,它就不再起作用了...
如果您使用 json
,则需要在 MVC6 上显式使用 FromBody
public JsonResult Login([FromBody]LoginViewModel model)
编辑
我认为你混合了不同的错误。我将尝试描述您应该如何提出请求:
内容类型必须是:application/json
您的请求正文必须 JSON 格式(如 JasonLind 所建议):
{
UserName: 'Test',
Password: 'Test',
RememberMe: true
};
这是您在检查请求(通过 chrome 调试器工具 F12)或使用像 fiddler 这样的请求检查器时应该看到的内容。
如果您看到 UserName=Test&Password=Test&RememberMe=true
形式的内容,那么您做错了,那是表单格式。
您不需要 model
变量。如果您看到带有 "wrapper" 的请求,则应将其删除。
你的问题不是 MVC6,而是 jQuery。 $.ajax() 检查 "data" 并了解其格式,以便为您设置内容类型,并且您应该以承诺的方式使用 $.ajax
检查承诺优势here
还有select表格,只是变成对象,比如
$('.anyForm').on('submit', fucntion(){
//you have the form in JSON format
var data = $(this).serializeObject()
})
和here是serializeObject()方法,默认不在jQuery上。
你可以自己实现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的class,将DataMember设置为class的Properties。
像这样编辑 class
[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"
希望对你有用
在我的 ASP.NET 5 MVC 6 应用程序中,我想 post 和 Ajax 一些数据到我的控制器。我已经用 ASP.NET MVC 5 完成了这个,我在一个空白的 ASP.NET MVC 5 项目中测试了完全相同的代码并且它有效,但是对于新版本我不能而且我不知道为什么. 通过 Ajax 调用,我可以转到控制器,创建模型但字段为空(或布尔值为 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; }
}
有什么想法吗? 谢谢
不应该是:
var data = {
UserName: 'Test',
Password: 'Test',
RememberMe: true
};
好的,我找到了解决方案,但对我来说还是很奇怪......
您只需从请求中删除 content-type
。
$.ajax({
type: "POST",
url: "Account/Login",
data: data,
success: function (msg) {
// Do something interesting here.
}
});
感谢观察者,我找到了解决方案 :) 我观察了 Request 变量,发现 Request.Form 总是抛出异常。它说我使用了错误的内容类型,所以我只是从我的 ajax post 中删除了 content-type
,它就像一个魅力。我认为,对于每一个 ajax post,你必须小心你的 Request.Form 被正确填写
编辑: 此解决方案仅在您可以 post 非 json 数据(非常简单的数据)时有效,例如连接数据。但是如果我想要 post 复杂的数据,比如列表,它就不再起作用了...
如果您使用 json
,则需要在 MVC6 上显式使用 FromBodypublic JsonResult Login([FromBody]LoginViewModel model)
编辑
我认为你混合了不同的错误。我将尝试描述您应该如何提出请求:
内容类型必须是:application/json
您的请求正文必须 JSON 格式(如 JasonLind 所建议):
{
UserName: 'Test',
Password: 'Test',
RememberMe: true
};
这是您在检查请求(通过 chrome 调试器工具 F12)或使用像 fiddler 这样的请求检查器时应该看到的内容。
如果您看到 UserName=Test&Password=Test&RememberMe=true
形式的内容,那么您做错了,那是表单格式。
您不需要 model
变量。如果您看到带有 "wrapper" 的请求,则应将其删除。
你的问题不是 MVC6,而是 jQuery。 $.ajax() 检查 "data" 并了解其格式,以便为您设置内容类型,并且您应该以承诺的方式使用 $.ajax
检查承诺优势here
还有select表格,只是变成对象,比如
$('.anyForm').on('submit', fucntion(){
//you have the form in JSON format
var data = $(this).serializeObject()
})
和here是serializeObject()方法,默认不在jQuery上。
你可以自己实现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的class,将DataMember设置为class的Properties。
像这样编辑 class
[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"
希望对你有用