ModelState считается недействительным?
Я работаю над приложением MVC5 Code-First.
На одной модели Edit()
посмотреть я включил [Create]
кнопки для добавления новых значений в другие модели из Edit()
просмотреть, а затем снова заполнить новое значение в DropDownFors()
на Edit()
,
Для этой первой попытки я передаю model_description
через AJAX на мой метод контроллера createNewModel()
:
[HttpPost]
public JsonResult createNewModel(INV_Models model)
{
// model.model_description is passed in via AJAX -- Ex. 411
model.created_date = DateTime.Now;
model.created_by = System.Environment.UserName;
model.modified_date = DateTime.Now;
model.modified_by = System.Environment.UserName;
// Set ID
int lastModelId = db.INV_Models.Max(mdl => mdl.Id);
model.Id = lastModelId+1;
//if (ModelState.IsValid == false && model.Id > 0)
//{
// ModelState.Clear();
//}
// Attempt to RE-Validate [model], still comes back "Invalid"
TryValidateModel(model);
// Store all errors relating to the ModelState.
var allErrors = ModelState.Values.SelectMany(x => x.Errors);
// I set a watch on [allErrors] and by drilling down into
// [allErrors]=>[Results View]=>[0]=>[ErrorMessage] I get
// "The created_by filed is required", which I'm setting....?
try
{
if (ModelState.IsValid)
{
db.INV_Models.Add(model);
db.SaveChangesAsync();
}
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
return Json(
new { ID = model.Id, Text = model.model_description },
JsonRequestBehavior.AllowGet);
}
Что я не могу понять, это почему мой ModelState
подходит как Invalid
?
Все свойства указываются до ModelState
проверять; Модель определяется следующим образом:
public class INV_Models
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter a Model Description.")]
public string model_description { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime created_date { get; set; }
[Required]
public string created_by { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime modified_date { get; set; }
public string modified_by { get; set; }
}
РЕДАКТИРОВАТЬ:
Добавлен код просмотра:
Форма ввода:
<span class="control-label col-md-2">Type:</span>
<div class="col-md-4">
@Html.DropDownListFor(model => model.Type_Id, (SelectList)ViewBag.Model_List, "<<< CREATE NEW >>>", htmlAttributes: new { @class = "form-control dropdown" })
@Html.ValidationMessageFor(model => model.Type_Id, "", new { @class = "text-danger" })
</div>
<div class="col-md-1">
<div class="btn-group">
<button type="button" class="btn btn-success" aria-expanded="false">CREATE NEW</button>
</div>
</div>
СЦЕНАРИЙ:
$('#submitNewModel').click(function () {
var form = $(this).closest('form');
var data = { model_description: document.getElementById('textNewModel').value };
$.ajax({
type: "POST",
dataType: "JSON",
url: '@Url.Action("createNewModel", "INV_Assets")',
data: data,
success: function (resp) {
alert("SUCCESS!");
$('#selectModel').append($('<option></option>').val(resp.ID).text(resp.Text));
alert("ID: " + resp.ID + " // New Model: " + resp.Text); // RETURNING 'undefined'...?
form[0].reset();
$('#createModelFormContainer').hide();
},
error: function () {
alert("ERROR!");
}
});
});
3 ответа
Вы не должны использовать взломать как ModelState.Clear()
ни есть TryValidateModel(model);
требуется. Ваша проблема связана с тем, что у вас есть [Required]
атрибут на обоих ваших created_date
а также created_by
свойства, но вы не публикуете значение, поэтому они null
и проверка не пройдена. Если бы вы опубликовали более сложную модель, вы бы использовали модель представления, у которой даже не было свойств для created_date
а также created_by
(это метод Create, поэтому их не следует устанавливать, пока вы не отправите ответ).
В вашем случае модель представления не нужна, поскольку вы отправляете только одно значение (для model-description
) используется для создания нового INV_Models
модель.
Измените 2-ую строку в скрипте на
var data = { description: $('#textNewModel').val() };
Измените свой метод сообщения на
[HttpPost]
public JsonResult createNewModel(string description)
{
// Initialize a new model and set its properties
INV_Models model = new INV_Models()
{
model_description = description,
created_date = DateTime.Now,
created_by = System.Environment.UserName
};
// the model is valid (all 3 required properties have been set)
try
{
db.INV_Models.Add(model);
db.SaveChangesAsync();
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
return Json( new { ID = model.Id, Text = model.model_description }, JsonRequestBehavior.AllowGet);
}
Примечания стороны:
- Я предлагаю
modified_date
бытьDateTime?
(обнуляется в базе данных также). Вы создаете новый объект и устанавливаетеcreated_date
а такжеcreated_by
свойства, но настройкаmodified_date
а такжеmodified_by
свойства не кажутся подходящими (они еще не были изменены). - Я подозреваю, что вы не хотите устанавливать
created_by
вSystem.Environment.UserName
(было бы бессмысленно устанавливать каждую запись вadministrator
или что угодноUserName
сервера возвращает. Вместо этого вам нужно получить имя пользователя отIdentity
или жеMembership
какую бы систему авторизации вы не использовали.
Если вы не можете быстро определить причину сбоя проверки ModelState, часто бывает полезно быстро перебрать ошибки.
foreach (ModelState state in ModelState.Values.Where(x => x.Errors.Count > 0)) { }
В качестве альтернативы вы можете вытащить ошибки напрямую.
var allErrors = ModelState.Values.SelectMany(x => x.Errors);
Имейте в виду, что ModelState создается ДО выполнения тела вашего действия. В результате IsValid уже будет установлен, независимо от того, как вы устанавливаете свойства своей модели, когда находитесь внутри действия контроллера.
Если вы хотите гибко задавать свойства вручную, а затем заново оценивать валидность объекта, вы можете вручную повторно запустить проверку в вашем действии после установки свойств. Как отмечено в комментариях, вы должны очистить свой ModelState перед попыткой повторной проверки.
ModelState.Clear();
ValidateModel(model);
try
{
if (ModelState.IsValid)
{
db.INV_Models.Add(model);
db.SaveChangesAsync();
}
}
...
Кроме того, если модель все еще недействительна, ValidateModel (модель) сгенерирует исключение. Если вы хотите предотвратить это, используйте TryValidateMode l, который вместо этого возвращает true/false:
protected internal bool TryValidateModel(Object model)
Состояние модели рассчитывается, когда привязка данных публикации к модели завершена. Свойство ModelState.IsValid сообщает только о наличии ошибок в ModelState.Errors.
Когда вы устанавливаете дату создания, вам нужно будет удалить связанную с ней ошибку из ModelState.Errors