0

根据用户输入,我想在实体到达控制器的操作之前取消实体的某些属性。在一个粗略的例子中(实际模型要复杂得多),假设我的实体有一个 BillingType 属性,它定义了客户是按月还是每两周计费:

public class BillingMethod
{
    public int Id { get; set; }
    public int BillingTypeValue { get; set; }
    public BillingType BillingType
    {
        get
        {
            return (BillingType)BillingTypeValue;
        } 
        set
        {
            BillingTypeValue = (int)value;
        }
    }

    public int? DayOfMonth { get; set; }
    public int? DayOfFirstFortnight { get; set; }
    public int? DayOfSecondFortnight { get; set; }
}

public enum BillingType
{
    Monthly,
    Fortnightly
}

现在假设用户选择按月收费,然后将 DayOfMonth 属性设置为 15。然后他改变主意,将 Billing Type 设置为每两周一次,并设置两个两周一次的属性,最后提交表单。我需要的是一种在未使用的属性(在此示例中为 DayOfMonth)到达控制器的操作之前将其无效的方法。

我知道当用户从一种计费类型更改为另一种计费类型时,或者通过拦截表单的 onSubmit 事件时,我可以通过 javascript 执行此操作。甚至在动作内部,在将其保存到上下文之前,但我需要一种方法来执行一次并忘记它。

我认为最好的方法是使用自定义模型绑定器,但我没有任何经验。我尝试创建一个新ModelBindingContext对象,但我不知道如何在新对象中获取和解析表单数据,所以我显然需要一些指导。

4

2 回答 2

1

我设法使用自定义活页夹修改了对象。首先我调用 base.BindModel,然后在返回之前修改属性。

public class BillingMethodModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext cContext, ModelBindingContext bContext)
    {
        var newBillingMethod = (BillingMethod)base.BindModel(cContext, bContext);
        var bType = newBillingMethod.BillingTypeValue;
        if (bType == (int)BillingType.Monthly)
        {
            newBillingMethod.DayOfFirstFortnight = null;
            newBillingMethod.DayOfSecondFortnight = null;
        }
        else
        {
            newBillingMethod.DayOfMonth = null;
        }

        return newBillingMethod;
    }
}

当然,在 global.asax 的 Application_Start() 中添加自定义绑定器:

ModelBinders.Binders.Add(typeof(BillingMethod), new BillingMethodModelBinder());

这对我很有用,我会等待一天左右才能接受这个答案,以防万一有人提出更好的解决方案或指出我在使用此方法时可能遇到的任何问题

于 2012-12-04T15:36:15.677 回答
1

我会小心地在自定义模型绑定器中执行此操作。您将遇到的一个问题是每个属性都是单独绑定的,您对顺序没有太多控制权。听起来您需要在绑定完成后根据对象的状态做出一些决定。

在这种情况下,我可能会使用动作过滤器。请参阅:http: //msdn.microsoft.com/en-us/library/system.web.mvc.controller.onactionexecuting (v=vs.98).aspx

public class BillMethodFilterAttribute : ActionFilterAttribute {

     protected override void OnActionExecuting(ActionExecutingContext filterContext) {
        base.OnActionExecuting(filterContext);
           if (filterContext.Controller.ViewData.ModelMetadata.ModelType == typeof(BillingMethod)) {
               var method = filterContext.Controller.ViewData.Model as BillingMethod;
               if (method != null) {
                  //assign appropriately - binding is complete, you have full state of the object
               }
           }
        }        
}

[BillMethodFilter]
public abstract class ProjectController : Controller {


}

public class SomeController : ProjectController {

      public ActionResult SomeAction(BillingMethod method) {
            //before this action runs, the BillMethodFilter should execute and your billing method will be fully initialized correctly
      }
}
于 2012-12-03T17:18:18.957 回答