我正在构建一个简单的网站,我希望能够轻松地将新闻和事件等模块插入其中,以便将来重用这些模块。经过一番挖掘后,我发现最好的方法是MEF。使用Kenny Tordeur's walkthrough我使网站处于半工作状态。 然后,我根据Long Le's Blog进行了一些更改和扩展。仍然没有快乐。我当前的问题是我的MefDependencyResolver应该提供System.Web.Http.Hosting.IHostBufferPolicySelector的一个实例,但它唯一想做的是CompositionContainer上的GetExports(),以及这个接口的实现还没有出口,这根本不起作用。
我现在感觉我完全错了。
我的网站是使用ASP.Net MVC 5构建的,此时它相当简单。我的NewsModule,我试图插入"插入"使用MEF也在MVC 5中,它使用WebAPI 2来处理一组AngularJS请求(例如获取新闻)。
更糟糕的是,模块的体系结构基于this blog - 我发现它非常有用但现在意味着模块中的API控制器具有需要以某种方式注入的依赖关系。
所以,有点代码: 我的 Global.asax 如下所示:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
MefConfig.RegisterMef(null);
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ViewEngines.Engines.Add(new MefViewEngine(MefConfig.GetPlugins()));
}
MefConfig.cs
public static void RegisterMef(TypeCatalog typeCatalog)
{
var compositionContainer = ConfigureContainer(typeCatalog);
ServiceLocator
.SetLocatorProvider(() => new MefServiceLocator(compositionContainer));
ControllerBuilder
.Current.SetControllerFactory(
new MefControllerFactory(compositionContainer));
GlobalConfiguration
.Configuration
.DependencyResolver =
new MefDependencyResolver(compositionContainer);
//compositionContainer.ComposeParts(); IS this not needed??
}
private static CompositionContainer ConfigureContainer(ComposablePartCatalog composablePartCatalog)
{
var catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
foreach (var plugin in GetPlugins())
{
var directoryCatalog = new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules", plugin));
catalog.Catalogs.Add(directoryCatalog);
}
if (composablePartCatalog != null)
catalog.Catalogs.Add(composablePartCatalog);
return new CompositionContainer(
catalog,
new MefNameValueCollectionExportProvider(
ConfigurationManager.AppSettings));
}
public static List<string> GetPlugins()
{
var pluginFolders = new List<string>();
var plugins = Directory.GetDirectories(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules")).ToList();
plugins.ForEach(s =>
{
var di = new DirectoryInfo(s);
pluginFolders.Add(di.Name);
});
return pluginFolders;
}
MefControllerFactory.cs
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer m_CompositionContainer;
public MefControllerFactory(CompositionContainer container)
{
m_CompositionContainer = container;
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = GetInstance<IController>(controllerName) ??
GetControllerInstance(requestContext, typeof(Controller));
return controller;
}
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
var name = AttributedModelServices.GetContractName(controllerType);
var export = m_CompositionContainer
.GetExports(controllerType, null, name).SingleOrDefault();
IController result;
if (null != export)
result = export.Value as IController;
else
{
result = base.GetControllerInstance(requestContext, controllerType);
m_CompositionContainer.ComposeParts(result);
}
return result;
}
public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
}
public override void ReleaseController(IController controller)
{
var disposableController = controller as IDisposable;
disposableController?.Dispose();
}
private T GetInstance<T>(string contractName = null)
{
var type = default(T);
if (m_CompositionContainer == null) return type;
if (string.IsNullOrEmpty(contractName) || string.IsNullOrWhiteSpace(contractName))
{
return m_CompositionContainer.GetExportedValue<T>();
}
var export = m_CompositionContainer.GetExports(typeof(T), null, contractName).SingleOrDefault();
if (export != null)
{
return (T)export.Value;
}
return type;
}
}
和 MefDependencyResolver.cs
public class MefDependencyResolver : IDependencyResolver
{
private readonly CompositionContainer m_Container;
public MefDependencyResolver(CompositionContainer container)
{
m_Container = container;
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
var name = AttributedModelServices.GetContractName(serviceType);
var export = m_Container.GetExports(serviceType, null, name).SingleOrDefault();
return export?.Value;
}
public IEnumerable<object> GetServices(Type serviceType)
{
var name = AttributedModelServices.GetContractName(serviceType);
var exports = m_Container.GetExports(serviceType, null, name);
var createdObjects = new List<object>();
var enumerable = exports as Lazy<object, object>[] ?? exports.ToArray();
if (enumerable.Any()) createdObjects.AddRange(enumerable.Select(export => export.Value));
return createdObjects;
}
public void Dispose()
{
;
}
}
新闻模块中 ArticleController 的一部分:
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
[System.Web.Http.RoutePrefix("api/article")]
public class ArticleController : ApiController
{
private IArticleService ArticleService { get; }
private IAttachmentService AttachmentService { get; }
public ArticleController(IArticleService articleService, IAttachmentService attachmentService)
{
ArticleService = articleService;
AttachmentService = attachmentService;
}
[ResponseType(typeof(IEnumerable<ArticleListView>))]
[System.Web.Http.HttpGet]
public IHttpActionResult Get()
{
var articles = ArticleService.GetArticles();
if (articles == null)
{
return NotFound();
}
return Ok(articles.OrderByDescending(a => a.Created).Select(a => new ArticleListView(a)));
}
仍然在新闻模块中,我有以下文章的资源:
var ArticleService = function ($resource) {
return $resource('/api/article/:id',{id:'@id'}, {
update:{method:'PUT'}
});
然后从Controller Article.query($ scope.articles,function(resp){...}
查询我的问题是?
提前多多感谢