根据查询字符串/派生控制器注入不同的存储库,并根据控制器类型/ ASP.NET MVC注入存储库

Sté*_*ane 4 asp.net-mvc design-patterns dependency-injection

我有一个搜索表单,可以在不同的提供商搜索.我开始时有一个基本控制器

public SearchController : Controller
{

    protected readonly ISearchService _searchService

    public SearchController(ISearchService searchService)
    {
        _searchService= searchService;
    }

    public ActionResult Search(...)
    {
        // Use searchService to query and return a view.
    }

}
Run Code Online (Sandbox Code Playgroud)

和儿童控制器

TwitterController : SearchController
{
    ...
}

NewsController : SearchController
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我使用StructureMap在控制器中插入所有依赖项.通过此设置,我可以根据正在实例化的控制器的类型更改SearchService.

x.For<ISearchService>().ConditionallyUse(o =>
      {
            o.TheDefault.Is.OfConcreteType<NewsSearchService>();

            o.If(c => c.ParentType == typeof(TwitterController))
             .ThenIt.Is.OfConcreteType<TwitterSearchService>();

             ...

      });
Run Code Online (Sandbox Code Playgroud)

这甚至允许我为每个控制器设置不同的视图,(只是放置相应的文件夹(Twitter,新闻......),而父控制器仍在处理所有搜索,只需简单

return View(results) 
Run Code Online (Sandbox Code Playgroud)

它显示特定于推特,新闻或其他的正确视图

现在这很酷,看起来很棒,我只有一个表单,不同的视图显示在同一页面的选项卡中.这就是这种方法开始变得复杂的地方.表单必须发布到/ Twitter以在Twitter中搜索,到/新闻搜索新闻...这意味着我应该根据我的标签更改表单的操作参数,并在表单返回时显示正确的选项卡取决于..网址?疯狂随之而来.

如果你已经建立了这样的东西或知道什么是最好的方法,欢迎提出建议.

现在我认为使用表单中的参数并发布到单个控制器会减少痛苦.我正在考虑根据此参数注入正确的SearchService.什么是最好的方法?我想过使用模型活页夹,

所以我的ActionMethod看起来像这样:

public ActionResult Search(ISearchService service, Query query)
{
    var results = service.Find(query);
}
Run Code Online (Sandbox Code Playgroud)

但我认为需要在ModelBinder中进行这样的调用

ObjectFactory.GetInstance(...);
Run Code Online (Sandbox Code Playgroud)

基于querystring参数来描述要使用的提供程序,这对我来说似乎并不优雅.我感到卡住,帮助:(.

Mar*_*ann 6

每当您需要根据运行时值更改依赖关系时,Abstract Factory就是一般解决方案.

而不是将ISearchService注入到控制器中,而是注入一个ISearchServiceFactory:

public SearchController : Controller 
{ 
    private readonly ISearchServiceFactory searchServiceFactory;

    public SearchController(ISearchServiceFactory searchServiceFactory) 
    { 
        if (searchServiceFactory == null)
        {
            throw new ArgumentNullException("searchServiceFactory");
        }

        this.searchServiceFactory = searchServiceFactory; 
    } 

    public ActionResult Search(...) 
    { 
        // Use searchServiceFactory to create an ISearchService based on
        // run-time values, and use it to query and return a view. 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

我不清楚你需要改变哪个运行时值,但假设它是Query,ISearchServiceFactory可能定义如下:

public interface ISearchServiceFactory
{
    ISearchService Create(Query query);
}
Run Code Online (Sandbox Code Playgroud)