ASP.Net MVC 3 JSON Model Binding and server side model validation mixed with client side validation
I've been playin开发者_Python百科g with the new MVC3 Json Model Binding and it's quite nice.
Currently, I can post JSON to controller and bind it. Model Validation occurs nicely too.
But what happens if the model is invalid?
I'd like to return JSON and have the client side notify the user (like how you'd perform normal client side validation in mvc)
Does anyone know of some tutorials on how to perform this?
Is this even possible?
Or are there frameworks I can leverage to do this?
The following example works for me when using unobtrusive JavaScript in MVC3. I'm doing something very similar. Given the following JsonResponse
class:
public enum Status
{
Ok,
Error
}
public class JsonResponse
{
public Status Status { get; set; }
public string Message { get; set; }
public List<string> Errors { get; set; }
}
My controller can have a method thus:
[HttpPost]
public ActionResult Login(UserLoginModel model)
{
JsonResponse res = new JsonResponse();
if (!ModelState.IsValid)
{
res.Status = Status.Error;
res.Errors = GetModelStateErrorsAsString(this.ModelState);
res.Message = "Oh dear, what have you done. Check the list of errors dude!";
}
else
{
// Save it here...
// Return success
res.Status = Status.Ok;
res.Message = "Everything was hunky dory";
}
return Json(res);
}
And the ModelStateDictionary can be enumerated for the errors as so:
private List<string> GetModelStateErrorsAsString(ModelStateDictionary state)
{
List<string> errors = new List<string>();
foreach (var key in ModelState.Keys)
{
var error = ModelState[key].Errors.FirstOrDefault();
if (error != null)
{
errors.Add(error.ErrorMessage);
}
}
return errors;
}
Then in my view I can have the following JSON POST:
<script type="text/javascript">
$("form").submit(function (evt) {
// validate
$('form').valid();
// extract values to submit
var form = $(this),
username = form.find("[name=Username]").val(),
password = form.find("[name=Password]").val(),
json = JSON.stringify({
Username: username,
Password: password
});
$.ajax({
url: form.attr("action"),
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: json,
success: function (result) {
alert(result.Message);
}
});
// stop form submitting
evt.preventDefault();
});
</script>
I'm using jQuery.tmpl
to display the errors. I have excluded that from this example though.
Thanks for this solution. I improved on it a bit by passing a dictionary so that you can use the unobtrusive javascript to put the validation on the individual fields instead of a summary by referencing the key of the dictionary.
private Dictionary<string, string> GetModelStateErrorsAsString(ModelStateDictionary state)
{
Dictionary<string, string> errors = new Dictionary<string, string>();
foreach (var key in ModelState.Keys)
{
var error = ModelState[key].Errors.FirstOrDefault();
if (error != null)
{
errors.Add(key, error.ErrorMessage);
}
}
return errors;
}
@Junto and @Jamey777, you both pass the ModelState to your error function but then you use the global variable instead of the parameter.
and why dont you just use a little linq like
private Dictionary<string, string> GetModelStateErrorsAsString()
{
return ModelState.Where(x=> x.Value.Errors.Any())
.ToDictionary(x => x.Key, x => x.Value.Errors.First().ErrorMessage);
}
精彩评论