首先,很抱歉这篇大文章(我已经尝试过先做一些研究)以及针对同一问题的技术组合(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
为 OrderFinishing
我Create()
为 GET 请求定义了一个方法,为OrderController
类上的 POST 请求定义了另一个方法。第二个是这样的:
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
并使用 Direct Injection 来发现哪个类型是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 { }
Global.asax.cs
我已经这样做了:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(Order), new DerivedTypeModelBinder());
}
但这会引发异常:System.MissingMethodException: Cannot create an abstract class。所以,我认为活页夹不是或无法解析为正确的类型。
非常感谢提前!
编辑:首先,感谢 Martin 和 Jason 的回答,并对延误表示歉意!我尝试了这两种方法,都奏效了!我将 Martin 的答案标记为正确,因为它更灵活并且可以满足我项目的一些需求。具体来说,每个请求的 ID 都存储在数据库中,如果我只在一个地方(数据库或班级)更改 ID,将它们放在班级上可能会破坏软件。在这一点上,马丁的方法非常灵活。
@Martin:在我的代码中,我更改了行
var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);
至
var concreteType = Assembly.GetAssembly(typeof(Order)).GetType(concreteTypeValue.AttemptedValue);
因为我的课程在另一个项目上(因此,在不同的程序集上)。我之所以分享这个,是因为它似乎比只获取无法解析外部程序集类型的执行程序集更灵活。在我的情况下,所有订单类都在同一个程序集中。这不是更好也不是一个神奇的公式,但我认为分享这个很有趣;)