2010-03-03 78 views
1

我遇到了一个我认为很有趣的问题。使用ASP.NET MVC中的自定义模型绑定器验证整数字段

取一个输入表单,它有一个整数值的输入字段(在我的情况下为成本)。我不希望将“$ 100”或“20美元”发送到数据库,因为它可能会投诉。我想向模型添加一个错误并将其发回给用户。看似简单;)。

我正在使用自定义模型绑定器,因为我在我的域模型中使用了一些继承。我有多种类型的事件,每种类型实现IEvent - 因此,我需要一个自定义模型绑定器。

我遇到的问题是,当我试图绑定成本字段,并从字符串转换为int失败时,我真的不知道如何最好地处理此问题。

我的自定义模型绑定 公共类EventModelBinder:IModelBinder { #地区IModelBinder成员

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

这个作品真的很好 - 如果枚举为空或不选择,我可以验证对他们,让用户知道它是必需的。对于成本字段,如果转换失败,我会得到-1。但是,当我去验证服务器上的数据并返回到用户界面,该Model.Event.ProjectedCost字段为空

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

我Edit.aspx查看

<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为空,如果它不验证,给我这个(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?

我意识到这可能不是最简单的问题阅读,所以让我知道,如果我能以任何方式澄清!

+0

你肯定你不能使用默认的模型绑定?因为我怀疑活页夹没有做默认的东西,这就是为什么你的值没有被验证返回 – 2010-03-03 14:38:15

+0

我试过了,但我的视图继承自IEvent - 所以默认模型联编程序试图创建一个IEvent实例,它是不可能的,因为它是一个接口。 – Dan 2010-03-03 15:44:50

回答

1

您可以使用javascript来限制文本框的输入为整数。

+1

+1非常真实 - 但我不想依赖JS。如果用户禁用JS – Dan 2010-03-03 14:28:19

+1

是的,我想要坚实的回退。我永远不会只有前端验证,因为你永远不知道用户是如何设置的 – 2010-03-03 20:45:33

相关问题