Параметр привязки к сложному типу - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть панель навигации, с несколькими ссылками, как это:

<a href="MyController/Browse/2">MenuItem1</a>

Этот запрос поразит мой метод действия:

public ActionResult Browse(int departmentId)
{
    var complexVM = MyCache.GetComplexVM(departmentId);
    return View(complexVM);
}

Этоmy ComplexVM:

public class ComplexVM 
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
}

MyCache - это статический список отделов, который я храню в памяти, поэтому, когда пользователь вводит DepartmentId, мне не нужно получать соответствующийDepartmentName из БД.

Это работает нормально ... но было бы неплохо, если бы я мог как-то инициализировать ComplexVM в пользовательском связывателе модели вместо инициализации его в контроллере ... так что я все ещеЯ хочу использовать ссылку (пункт меню), но на этот раз CustomModelBinder привязывает мой параметр 2 к ComplexVM: ему нужно найти название отдела с id = 2 из MyCache и инициализировать ComplexVM, тогда ComplexVM будет передано этому методу действия:

public ActionResult Browse(ComplexVM complexVM)
{
    return View(complexVM);
}

Я хочу нажать на вышеупомянутый контроллер, не выполняя постбэк, так как у меня много ссылок на пункты меню в моей навигационной панели... не уверен, возможно ли это?Или, если это даже хорошая идея?

Я видел эту ссылку , которая описывает, что я хочу ... но я не уверен, как будет работать маршрутизация ...т.е. маршрутизация id:2 => ComplexVM


В качестве альтернативы можно было бы сделать это в RouteConfig, что-то вроде этого:

routes.MapRoute(
    name: "Browse",
    url: "{controller}/Browse/{departmentId}",
    // this does not compile, just want to explain what I want...
    defaults: new { action = "Browse", new ComplexVM(departmentId) });

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

Я могу добиться этого с небольшими изменениями и одним трюком

<a href="MyController/Browse?id=1">MenuItem1</a>

Действие контроллера

public ActionResult Browse(ComplexVM complexVM)
{
return View(complexVM);
}

Посмотреть модель

public class ComplexVM
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public ComplexVM()
    {
        this.DepartmentId = System.Convert.ToInt32(HttpContext.Current.Request("id").ToString);
        this.DepartmentName = "Your name from cache"; // Get name from your cache 
    }
}

Это без использования моделисвязующее.Трюк может помочь.

0 голосов
/ 13 декабря 2018

Это возможно.Это также хорошая идея :) Разгрузка частей общей ответственности за модели / фильтры действий - это здорово.Единственная проблема заключается в том, что они используют некоторые специальные классы для наследования, иногда их тестирование может быть немного сложнее, чем просто тестирование контроллера.Как только вы это освоите, это будет лучше.

Ваша сложная модель должна выглядеть так:

// Your model class
[ModelBinder(typeof(ComplexVMModelBinder)]
public class ComplexVMModel
{
   [Required]
   public int DepartmentId { get; set; }

   public string DepartmentName { get; set; }
}

// Your binder class
public class ComplexVMModelBinder : IModelBinder
{
     // Returns false if you can't bind.
     public bool BindModel(HttpActionContext actionContext, ModelBindingContext modelContext)
     {
         if (modelContext.ModelType != typeof(ComplexVMModel))
         {
             return false;
         }

         // Somehow get the depid from the request - this might not work.
         int depId = HttpContext.Current.Request.Params["DepID"];
         // Create and assign the model.
         bindingContext.Model = new ComplexVMModel() { DepartmentName = CacheLookup(), DepId = depId };

         return true;
     }
}

Затем, в начале вашего метода действия, вы проверяете ModelState, чтобы убедиться, что он действителенили нет.Есть несколько вещей, которые могут сделать состояние модели недействительным (например, отсутствие параметра [Required].)

public ActionResult Browse(ComplexVM complexVM)
{
    if (!ModelState.IsValid)
    {
        //If not valid - return some error view.
    }
}

Теперь вам просто нужно зарегистрировать этот механизм связывания моделей.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    ModelBinders.Binders.Add(typeof(ComplexVMModel), new ComplexVMModelBinder());
}

Вы должны быть в состоянии использовать предоставленную вами конфигурацию маршрута.

...