首先,对这篇大文章(我尝试先做一些研究)以及针对同一问题的技术组合(ASP.NET MVC 3、Ninject 和 MvcContrib)表示歉意。
我正在使用 ASP.NET MVC 3 开发一个项目来处理一些客户订单。
简而言之:我有一些继承自抽象类的对象Order
当向我的控制器发出 POST 请求时,我需要解析它们。如何解析正确的类型?我需要覆盖DefaultModelBinder
类或者还有其他方法可以做到这一点?有人可以为我提供一些关于如何执行此操作的代码或其他链接吗?任何帮助都会很棒!
如果帖子令人困惑,我可以做任何更改以使其清晰!
因此,我有以下继承树来处理我需要处理的订单:
public abstract partial class Order {
public Int32 OrderTypeId {get; set; }
/* rest of the implementation ommited */
}
public class OrderBottling : Order { /* implementation ommited */ }
public class OrderFinishing : Order { /* implementation ommited */ }
这些类都是由实体框架生成的,所以我不会修改它们,因为我需要更新模型(我知道我可以扩展它们)。另外,还会有更多的订单,但都是源自Order
.
我有一个通用的观点(Create.aspx
)以便创建订单,并且此视图为每个继承的订单调用强类型分部视图(在本例中OrderBottling
and OrderFinishing
)。我定义了一个Create()
GET 请求的方法和 POST 请求的其他方法OrderController
班级。第二个如下:
public class OrderController : Controller
{
/* rest of the implementation ommited */
[HttpPost]
public ActionResult Create(Order order) { /* implementation ommited */ }
}
现在的问题是:当我收到带有表单数据的 POST 请求时,MVC 的默认绑定器尝试实例化一个Order
对象,这是可以的,因为方法的类型就是那个。但是因为Order
是抽象的,它不能被实例化,而这是应该做的。
问题:我怎样才能找到具体的Order
类型是由视图发送的?
我已经在 Stack Overflow 上搜索过,并在 google 上搜索了很多相关内容(我现在正在研究这个问题大约 3 天!),并找到了一些解决一些类似问题的方法,但我找不到像我真实的问题一样的东西问题。解决这个问题的两种选择:
- 覆盖 ASP.NET MVC
DefaultModelBinder
并使用直接注入来发现哪种类型Order
;
- 为每个订单创建一个方法(不美观并且维护起来会有问题)。
我没有尝试第二个选项,因为我认为这不是解决问题的正确方法。对于第一个选项,我尝试使用 Ninject 解析订单类型并实例化它。我的 Ninject 模块如下所示:
private class OrdersService : NinjectModule
{
public override void Load()
{
Bind<Order>().To<OrderBottling>();
Bind<Order>().To<OrderFinishing>();
}
}
我试图通过 Ninject 获得其中一种类型Get<>()
方法,但它告诉我,解析类型的方法不止一种。所以,我知道该模块没有得到很好的实现。我也尝试为这两种类型实现这样的:Bind<Order>().To<OrderBottling>().WithPropertyInject("OrderTypeId", 2);
,但它有同样的问题...实现这个模块的正确方法是什么?
我还尝试过使用 MvcContrib Model Binder。我已经这样做了:
[DerivedTypeBinderAware(typeof(OrderBottling))]
[DerivedTypeBinderAware(typeof(OrderFinishing))]
public abstract partial class Order { }
and on Global.asax.cs
我已经这样做了:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(Order), new DerivedTypeModelBinder());
}
但这会引发异常:System.MissingMethodException:无法创建抽象类。因此,我认为活页夹没有或无法解析为正确的类型。
非常非常感谢!
Edit:首先,感谢 Martin 和 Jason 的回答,对于延迟表示抱歉!我尝试了两种方法并且都有效!我将 Martin 的答案标记为正确,因为它更灵活并且满足了我项目的一些需求。具体来说,每个请求的 ID 都存储在数据库中,如果我仅在一个位置(数据库或类上)更改 ID,则将它们放在类上可能会破坏软件。马丁的方法在这一点上非常灵活。
@Martin:在我的代码中我改变了这一行
var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);
to
var concreteType = Assembly.GetAssembly(typeof(Order)).GetType(concreteTypeValue.AttemptedValue);
因为我的课程在另一个项目上(因此在不同的程序集中)。我分享这个是因为它似乎比仅获取无法解析外部程序集类型的执行程序集更灵活。就我而言,所有订单类都位于同一个程序集中。这不是更好,也不是一个神奇的公式,但我认为分享这个很有趣;)