Я столкнулся с проблемой, которая показалась мне интересной.
Возьмите форму ввода с полем ввода для целочисленного значения (в моем случае это стоимость). Я не хочу, чтобы "100 долларов" или "двадцать долларов" отправлялись в базу данных, так как они, скорее всего, будут жаловаться. Я хочу добавить ошибку в модель и отправить ее обратно пользователю. Казалось, просто;).
Я использую привязку пользовательской модели, потому что я использую наследование в моей доменной модели. У меня есть несколько типов событий, каждый из которых реализует IEvent, поэтому мне потребовался пользовательский механизм связывания моделей.
Проблема, с которой я сталкиваюсь, заключается в том, что, когда я пытаюсь связать поле стоимости и преобразование из строки в int завершается неудачно, я действительно не уверен, как лучше всего справиться с этим. *
Моя пользовательская модель Binder
открытый класс EventModelBinder: IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Trivial code ... binding other fields...
_event.ProjectedCost = GetA<int>(bindingContext, "ProjectedCost").GetValueOrDefault(-1);
return _event;
}
#endregion
// From Scott Hanselman's blog :)
private Nullable<T> GetA<T>(ModelBindingContext bindingContext, string key) where T : struct
{
if (String.IsNullOrEmpty(key)) return null;
ValueProviderResult valueResult;
Nullable<T> ret;
//Try it with the prefix...
bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName + "." + key, out valueResult);
//Didn't work? Try without the prefix if needed...
if (valueResult == null && bindingContext.FallbackToEmptyPrefix == true)
{
bindingContext.ValueProvider.TryGetValue(key, out valueResult);
}
if (valueResult == null)
{
return null;
}
try
{
ret = (Nullable<T>)valueResult.ConvertTo(typeof(T));
}
catch
{
return null;
}
return ret;
}
Это работает очень хорошо - если Enums равны нулю или не выбраны, я могу проверить их и сообщить пользователю, что это необходимо. Для поля стоимости я получаю -1, если конверсия не удалась. Но когда я проверяю данные на сервере и возвращаюсь к пользовательскому интерфейсу, поле Model.Event.ProjectedCost имеет значение null
Мой EventService
// ...
protected bool ValidateEvent(IEvent eventToValidate)
{
if (eventToValidate.ProjectedCost < 0)
_validationDictionary.AddError("ProjectedCost", "Incorrect format");
return _validationDictionary.IsValid;
}
public bool SaveEvent(IEvent _event)
{
if (!ValidateEvent(_event))
return false;
try
{
_repository.SaveEvent(_event);
return true;
}
catch
{
return false;
}
My Edit.aspx View
<h2>Edit</h2>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="ProjectedCost">ProjectedCost:</label>
<%= Html.TextBox("ProjectedCost", Model.Event.ProjectedCost) %>
<%= Html.ValidationMessage("ProjectedCost", "*") %>
</p>
<% Html.RenderPartial(String.Format("~/Views/Shared/{0}Form.ascx", Model.Event.Type), Model.Event, ViewData); %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
На мой взгляд, Model.Event.ProjectedCost имеет значение null, если не проверяется, что дает мне это (строка 54 является виновником):
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 52: <p>
Line 53: <label for="ProjectedCost">ProjectedCost:</label>
Line 54: <%= Html.TextBox("ProjectedCost", (Model.Event.ProjectedCost == null ? 0 : Model.Event.ProjectedCost)) %>
Line 55: <%= Html.ValidationMessage("ProjectedCost", "*") %>
Line 56: </p>
Что бы я хотел сделать, это отправить значение, которое пользователь ввел обратно пользователю, но моя привязка пользовательской модели и / или логика проверки, похоже, устанавливают что-то в null?
Я понимаю, что это может быть не самый простой вопрос для чтения, поэтому дайте мне знать, если я смогу уточнить каким-либо образом!