У меня есть следующие классы в моем ASP.NET приложения MVC5:ASP.NET MVC Cast ViewModel в общий тип интерфейса в фильтре действия
public abstract class BaseItem
{ }
public class DerivedItem1 : BaseItem
{ }
public class DerivedItem2 : BaseItem
{ }
public interface IItemViewModel<T>
where T : BaseItem
{
T Item { get; set; }
}
public class ItemViewModel<T> : IItemViewModel<T>
where T : BaseItem
{
public T Item { get; set; }
}
Мои контроллеры похожи на эти:
[AutoAssignItem]
public class DerivedItem1Controller : ItemControllerBase<DerivedItem1>
{
public ActionResult Index()
{
var model = new ItemViewModel<DerivedItem1>();
// I'd like to avoid setting the Item property here
// and instead delegate that task to my filter
// itemService.GetCurrentItems returns an instance
// of type DerivedItem1.
// model.Item = itemService.GetCurrentItem();
return View(model);
}
}
[AutoAssignItem]
public class DerivedItem2Controller : ItemControllerBase<DerivedItem2>
{
public ActionResult Index()
{
var model = new ItemViewModel<DerivedItem2>();
// I'd like to avoid setting the Item property here
// and instead delegate that task to my filter
// itemService.GetCurrentItems returns an instance
// of type DerivedItem2.
// model.Item = itemService.GetCurrentItem();
return View(model);
}
}
I есть фильтр действий AutoAssignItem, где я хотел бы установить свойство Item на моей модели представления, которая может быть типа ItemViewModel <DerivedItem1> или ItemViewModel <DerivedItem2>:
public class AutoAssignItem : ActionFilterAttribute, IActionFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
var viewModel = filterContext.Controller.ViewData.Model;
// The viewModel type here could either be
// ItemViewModel<DerivedItem1> or ItemViewModel<DerivedItem2>
// So I try passing in BaseItem as the type parameter and cast
var model = viewModel as IItemViewModel<BaseItem>;
// But model is always null :(
if (model == null)
{
return;
}
// Here I can also try and get the implemented interface type
// var interfaceType = viewModel.GetType().GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IItemViewModel<>)).SingleOrDefault();
// And try converting it but this would require the viewModel
// to implement the IConvertible interface which I want to avoid
// var model = Convert.ChangeType(viewModel, interfaceType);
// If model is not null, then set the Item property
// through a service based on contextual information
// Here itemService.GetCurrentItem() would return an Item
// with the correct type such as DerivedItem1 if the action
// on the DerivedItem1Controller had run
model.Item = itemService.GetCurrentItem();
}
}
Обратите внимание, что BaseItem будет иметь несколько производных классов, а не только два, как в приведенном выше примере. Мой вопрос заключается в том, как мне настроить viewmodel таким образом, чтобы я мог получить доступ и установить свойство Item?
Если я делаю T в IItemViewModel , чтобы быть ковариантным, тогда я не могу установить свойство Item в фильтре действия, поскольку он будет только для getter-only.
Как в стороне, я пытаюсь реплицировать общий контроллер и структуру viewmodel, как это обычно реализуется при использовании Epyser CMS API. Разница заключается в том, что в CMS все это касается страниц. Таким образом, контроллер будет выглядеть так:
public class HomePageController : PageControllerBase<HomePage>
{
public ActionResult Index(HomePage currentPage)
{
var model = new PageViewModel<HomePage>();
model.CurrentPage = currentPage;
return View(model);
}
}
Любая помощь приветствуется.
Чего вы надеетесь достичь? Мне просто интересно. – Win
Win - Я добавил комментарии, чтобы уточнить мои намерения. – Khan
Если вы просто пытались * получить * 'model.Item' в фильтре, я бы предложил разделить геттер на ковариантный интерфейс, но концепция дисперсии существует именно для защиты от логически недействительной вещи, которую вы пытаетесь сделать - присвойте 'BaseItem' (предположительно возвращаемый тип' GetCurrentItem') переменной переменной T: BaseItem. Трудно точно узнать, чего вы пытаетесь достичь здесь, но похоже, что вы ищете обходной путь, когда вам нужен совсем другой подход. –