首先,对于大帖子(我试着先做一些研究)以及对同一问题的技术组合(ASP.NET MVC 3,Ninject和MvcContrib)。ASP.NET MVC 3:带继承性/多态性的DefaultModelBinder
我正在开发一个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
和OrderFinishing
)调用强类型的局部视图。我为OrderController
类定义了一个用于GET请求的Create()
方法和用于POST请求的其他方法。第二是这样的:
public class OrderController : Controller
{
/* rest of the implementation ommited */
[HttpPost]
public ActionResult Create(Order order) { /* implementation ommited */ }
}
现在的问题:当我接收与从形式的数据POST请求,MVC的默认粘合剂尝试实例化Order
对象,这是因为该方法的类型确定就是它。但是因为Order
是抽象的,所以它不能实例化,这是应该做的。
问题:怎样才能发现哪个具体的Order
类型是由视图发送的?
我已经在这里搜索了堆栈溢出并搜索了很多关于这个(我正在处理这个问题大约3天了!),并找到了一些方法来解决一些类似的问题,但我找不到像我真正的问题。为解决此有两个选项:
- 覆盖ASP.NET MVC
DefaultModelBinder
,并使用缸内直喷发现哪个类型是Order
; - 为每个订单创建一个方法(不漂亮,并且会有问题维护)。
我还没有尝试第二种方法,因为我不认为这是解决问题的正确方法。对于第一个选项,我尝试过Ninject来解析订单的类型并实例化它。我Ninject模块是这样的:
private class OrdersService : NinjectModule
{
public override void Load()
{
Bind<Order>().To<OrderBottling>();
Bind<Order>().To<OrderFinishing>();
}
}
我试图让各类throught Ninject的Get<>()
方法之一,但它告诉我,该是解决其种类较多,其中一个方法。所以,我明白这个模块并没有很好的实现。我也试图对这两种类型执行:Bind<Order>().To<OrderBottling>().WithPropertyInject("OrderTypeId", 2);
,但它有同样的问题...什么才是实现这个模块的正确方法?
我也尝试使用MvcContrib模型绑定。我已经做到了这一点:
[DerivedTypeBinderAware(typeof(OrderBottling))]
[DerivedTypeBinderAware(typeof(OrderFinishing))]
public abstract partial class Order { }
和Global.asax.cs
我已经做到了这一点:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(Order), new DerivedTypeModelBinder());
}
但是,这将引发异常:system.missingMethodException而:无法创建抽象类。所以,我认为活页夹不是或不能解析为正确的类型。
许多许多在此先感谢!
编辑:首先,感谢Martin和Jason的回答,并为延误感到抱歉!我尝试了两种方法,并且都奏效了!我将马丁的答案标记为正确,因为它更灵活,并满足我项目的一些需求。具体地,对于每个请求的ID被存储在数据库中,如果我只在一个地方(数据库或在类)更改ID把它们的类可以打破软件。马丁的方法在这一点上非常灵活。
@马丁:我的代码我改了行
var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);
到
var concreteType = Assembly.GetAssembly(typeof(Order)).GetType(concreteTypeValue.AttemptedValue);
,因为我所在的班的另一个项目(等,在不同的组件)。我分享这个,因为它看起来像比只获取不能解析外部程序集类型的执行程序集更灵活。在我的情况下,所有的订单类都在同一个程序集上。这不是最好,也不是一个神奇的公式,但我觉得有趣的是,分享这个;)
完整的堆栈跟踪总是可以更容易地诊断问题。 – 2011-03-28 14:20:50
@jmpcm - 只要确定,如果从'Order'中删除'abstract'修饰符,它是否工作? – 2011-03-28 14:32:33
@Sergi:不,它也不起作用。我之前创建模型的时候,我没有把Order作为抽象的,结果是一样的,但有一个不同的错误(不记得它是什么)。 – jmpcm 2011-03-28 14:35:27