MEF 和 ASP.NET MVC
我想将 MEF 与 asp.net mvc 一起使用。 我编写了以下控制器工厂:
public class MefControllerFactory : DefaultControllerFactory
{
private CompositionContainer _Container;
public MefControllerFactory(Assembly assembly)
{
_Container = new CompositionContainer(new AssemblyCatalog(assembly));
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
var controllers = _Container.GetExports<IController>();
var controllerExport = controllers.Where(x => x.Value.GetType() == controllerType).FirstOrDefault();
if (controllerExport == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
return controllerExport.Value;
}
else
{
throw new HttpException((Int32)HttpStatusCode.NotFound,
String.Format(
"The controller for path '{0}' could not be found or it does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
}
}
在 Global.asax.cs 中,我正在设置我的控制器工厂:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory.MefControllerFactory(Assembly.GetExecutingAssembly()));
}
我有一个区域:
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller
{
private readonly IArticleService _articleService;
[ImportingConstructor]
public HomeController(IArticleService articleService)
{
_articleService = articleService;
}
//
// GET: /Articles/Home/
public ActionResult Index()
{
Article article = _articleService.GetById(55);
return View(article);
}
}
IArticleService
是一个接口。
有一个类实现 IArticleService 并导出它。
有用。
这就是我使用 MEF 所需的一切吗?
如何跳过控制器的 PartCreationPolicy
和 ImportingConstructor
设置?
我想使用构造函数设置我的依赖项。
当 PartCreationPolicy
丢失时,我收到以下异常:
控制器“MvcApplication4.Areas.Articles.Controllers.HomeController”的单个实例不能用于处理多个请求。如果正在使用自定义控制器工厂,请确保它为每个请求创建一个新的控制器实例。
I want to use MEF with asp.net mvc.
I wrote following controller factory:
public class MefControllerFactory : DefaultControllerFactory
{
private CompositionContainer _Container;
public MefControllerFactory(Assembly assembly)
{
_Container = new CompositionContainer(new AssemblyCatalog(assembly));
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
var controllers = _Container.GetExports<IController>();
var controllerExport = controllers.Where(x => x.Value.GetType() == controllerType).FirstOrDefault();
if (controllerExport == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
return controllerExport.Value;
}
else
{
throw new HttpException((Int32)HttpStatusCode.NotFound,
String.Format(
"The controller for path '{0}' could not be found or it does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
}
}
In Global.asax.cs I'm setting my controller factory:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory.MefControllerFactory(Assembly.GetExecutingAssembly()));
}
I have an area:
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller
{
private readonly IArticleService _articleService;
[ImportingConstructor]
public HomeController(IArticleService articleService)
{
_articleService = articleService;
}
//
// GET: /Articles/Home/
public ActionResult Index()
{
Article article = _articleService.GetById(55);
return View(article);
}
}
IArticleService
is an interface.
There is a class which implements IArticleService
and Exports it.
It works.
Is this everything what I need for working with MEF?
How can I skip setting PartCreationPolicy
and ImportingConstructor
for controller?
I want to set my dependencies using constructor.
When PartCreationPolicy
is missing, I get following exception:
A single instance of controller 'MvcApplication4.Areas.Articles.Controllers.HomeController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你的技术非常可靠,即使在部分信任的情况下也能发挥作用。 书呆子晚餐 MEF 示例具有扩展,允许您按照约定处理发现控制器并自动将它们制作为 MEF 导出,而不用 MEF 属性标记它们。但是直接管理零件目录在部分信任中不起作用,因此书呆子晚餐 MEF 技术在部分信任中不起作用。
如果您完全信任地工作,并且希望控制器进行基于约定的发现,请从 Nerddinner MEF 示例开始,但您可能还应该阅读 nerddinner MEF 示例的几个主要问题,如果您自己的应用程序模型会出现这些问题是一个单独的类库项目。我 在博客中介绍了这些案例并提出了一些修复建议。
如果您对基于惯例的发现内容不太感兴趣,那么书呆子晚餐样本就有点过度设计了。您的解决方案可能就这样......并且也可以在部分信任的情况下工作,这始终是一个好处。
[更新]
我确实发现了您的技术的一个潜在问题:
在此处的 where 子句中,您在零件集合中的每个导出上调用 .Value...这实际上会导致每个导出都被组合并实例化,以便进行评估。这可能是一个令人讨厌的性能问题。
您可能会考虑使用命名导出合同来装饰您的控制器,如下所示:
然后使用如下所示的控制器工厂:
Your technique here is pretty solid, and will work even in partial trust. The nerd dinner MEF example has extensions that will allow you to deal with discovering controllers by convention and making them into MEF exports automatically, without flagging them with MEF attributes. But managing part catalogs directly doesn't work in partial trust, so the nerd dinner MEF techniques don't work in partial trust.
If you are working in full trust, and want convention based discovery with your controllers start with the Nerd Dinner MEF example, but you should probably also read about a couple major issues with the nerd dinner MEF example that will come up if your own application's model is in a separate class a library project. I blogged about those cases and suggested some fixes.
If you aren't all that interested in the convention based discovery stuff, then nerd dinner sample is a tad over-engineered. Your solution is probably fine as is... and works in partial trust too, which is always a bonus.
[update]
I did spot one potential problem with your technique:
In the where clause here, you are calling .Value on each export in the collection of parts... that is actually going to cause each of those exports to be composed and instantiated in order to be evaluated. That could be a nasty performance issue.
You might consider decorating your controllers with named export contracts like this:
Then using a controler factory like this instead:
我决定回到Unity。
我创建了一个自定义属性而不是 MEF 的 ExportAttribute
示例:
和一个自定义控制器工厂:对
我来说,解决 MEF 控制器工厂的所有问题太困难了:(
I decided to return to Unity.
I've create a custom attribute instead of MEF's ExportAttribute
Example:
And a custom controller factory:
It was too difficult for me to fix all problems for MEF's controller factory :(
我最近经常使用 MEF/MVC,并且一直在博客中介绍我修改后的 MEF+MVC 设计。我希望尽快将其推到 CodePlex 上,但现在看看这些是否对您有帮助:
I've been working with MEF/MVC a lot recently and have been blogging about my revised MEF+MVC design. I'm hoping to push it onto CodePlex soon, but for now, see if any of this helps you out:
谢谢。
是的,确实如此。
读完这篇文章(http://codepaste.net/yadusn)后,我明白了 NerdDinner 与 MEF 是如何完成的。
我使用 MEF 的常规目录并创建了 MEFed 控制器工厂(控制器上没有 Export 属性)。
ExportMetadataContainsGuid 方法:
我使用元数据来存储类型的 GUID 并使用它来查找正确的控制器。
Thanks.
Yes, it is true.
After reading this (http://codepaste.net/yadusn) I understood how NerdDinner with MEF was done.
I used the conventional catalog for MEF and created my MEFed controller factory (without Export attribute on controllers).
ExportMetadataContainsGuid method:
I use metadata to store type's GUID and use it to find right controller.