Пользовательский связыватель модели для привязки значений вложенных свойств - PullRequest
2 голосов
/ 24 февраля 2012

Причина, по которой мне это нужно: в одном из моих контроллеров я хочу связать все десятичные значения другим способом, чем остальная часть моего приложения.Я не хочу регистрировать связыватель модели в Global.asax (через ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());)

Я пытался наследовать от класса DefaultModelBinder и переопределить его метод BindProperty, но это работает только для моделиНепосредственные (не вложенные) экземпляры. Десятичные свойства.

У меня есть следующий пример, чтобы продемонстрировать мою проблему:

namespace ModelBinderTest.Controllers
{
    public class Model
    {
        public decimal Decimal { get; set; }
        public DecimalContainer DecimalContainer { get; set; }
    }

    public class DecimalContainer
    {
        public decimal DecimalNested { get; set; }
    }

    public class DecimalModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.PropertyType == typeof (decimal))
            {                
                propertyDescriptor.SetValue(bindingContext.Model,  999M);
                return;
            }

            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }

    public class TestController : Controller
    {

        public ActionResult Index()
        {
            Model model = new Model();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(DecimalModelBinder))] Model model)
        {
            return View(model);
        }

    }
}

Это решение только устанавливает свойство Model Decimal на 999, но ничего не делает для свойства DecimalContainer DecimalNested.Я понимаю, что это потому, что base.BindProperty вызывается в моем DecimalModelBinder переопределении BindProperty, но я не знаю, как убедить базовый класс использовать мой связыватель модели при работе с десятичными свойствами.

1 Ответ

1 голос
/ 24 февраля 2012

Вы можете безоговорочно применить связующее для модели в вашем Application_Start:

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());

, а затем иметь настраиваемый фильтр авторизации (да, фильтр авторизации, поскольку он запускается до подшивки модели), который будет вставлять в HttpContext некоторое значение, которое впоследствии может быть использовано подшивателем модели:

[AttributeUsage(AttributeTargets.Method)]
public class MyDecimalBinderAttribute : ActionFilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        filterContext.HttpContext.Items["_apply_decimal_binder_"] = true;
    }
}

и затем в тесте связывания модели, если HttpContext содержит пользовательское значение перед его применением:

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (controllerContext.HttpContext.Items.Contains("_apply_decimal_binder_"))
        {
            // The controller action was decorated with the [MyDecimalBinder]
            // so we can proceed
            return 999M;
        }

        // fallback to the default binder
        return base.BindModel(controllerContext, bindingContext);
    }
}

Теперь все, что осталось, это украсить действие вашего контроллера пользовательским фильтром, чтобы включить десятичную подшивку:

[HttpPost]
[MyDecimalBinder]
public ActionResult Index(Model model)
{
    return View(model);
}
...