簡體   English   中英

根據查詢字符串/派生控制器注入不同的存儲庫,並根據控制器類型/ ASP.NET MVC注入存儲庫

[英]Inject different repository depending on a querystring / derive controller and inject the repository depending on the controller type / ASP.NET MVC

我有一個搜索表單,可以在不同的提供商搜索。 我開始時有一個基本控制器

public SearchController : Controller
{

    protected readonly ISearchService _searchService

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

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

}

和兒童控制器

TwitterController : SearchController
{
    ...
}

NewsController : SearchController
{
    ...
}

我使用StructureMap在控制器中插入所有依賴項。 通過此設置,我可以根據正在實例化的控制器的類型更改SearchService。

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

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

             ...

      });

這甚至允許我為每個控制器設置不同的視圖,(只需放置相應的文件夾(Twitter,新聞......),而父控制器仍在處理所有搜索,只需簡單

return View(results) 

它顯示特定於推特,新聞或其他的正確視圖

現在這很酷,看起來很棒,我只有一個表單,不同的視圖顯示在同一頁面的選項卡中。 這就是這種方法開始變得復雜的地方。 表單必須發布到/ Twitter以在Twitter中搜索,/新聞以搜索新聞...這意味着我應該根據我的哪個選項卡更改表單的操作參數,並在表單返回時顯示正確的選項卡取決於..網址? 瘋狂隨之而來。

如果你已經建立了這樣的東西或知道什么是最好的方法,歡迎提出建議。

現在我認為使用表單中的參數並發布到單個控制器會減少痛苦。 我正在考慮根據此參數注入正確的SearchService。 什么是最好的方法? 我想過使用模型活頁夾,

所以我的ActionMethod看起來像這樣:

public ActionResult Search(ISearchService service, Query query)
{
    var results = service.Find(query);
}

但我認為需要在ModelBinder中進行這樣的調用

ObjectFactory.GetInstance(...);

基於querystring參數來描述要使用的提供程序,這對我來說似乎並不優雅。 我感到卡住,幫助:(。

每當您需要根據運行時值更改依賴關系時, 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. 
    } 
} 

我不清楚你需要改變哪個運行時值,但假設它是Query,ISearchServiceFactory可能是這樣定義的:

public interface ISearchServiceFactory
{
    ISearchService Create(Query query);
}

我試圖弄清楚如何使用抽象工廠模式,仍然讓structmap解決我的組件的所有依賴項。

我相信這是我要實現它的方式,但是我在這里提交這個以獲得一些反饋,如果有人會讀到這個。

正如在前面的答案中解釋的那樣,我不想構建整個對象圖,具體取決於我在Abstract工廠中需要哪個提供程序。

即:

class StatServiceFactory : IStatServiceFactory
{
    public IStatService Create(string provider)
    {
        switch(provider)
        {
            case "blog":
                return new  StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder);
                       //How to resolve the Config, the SearchManager, and BooleanQueryBuilder?   
                       //Add more abstract factories? It starts to get messy in my opinion...
         }
    }

}

我可以做的是讓抽象工廠使用我的容器來創建我的搜索管理器的實例,具體取決於參數(在我的情況下來自查詢字符串)

Structuremap允許以這種方式創建命名實例:

x.For<ISearchManager>().Use<AbcSearchManager>().Named("Abc");
x.For<ISearchManager>().Use<DefSearchManager>().Named("Def");

我需要一種方法來在我的抽象工廠中注入容器。 我可能會將容器包裝在這樣定義的包裝器中。 那樣可以防止我將Structuremap泄漏到我的項目中。 無論如何,我不需要抽象工廠中的那兩個功能,但是沒有必要:

public interface IContainerWrapper
{
    object GetInstance<T>();
    object GetNamedInstance<T>(string key);
}

和實施:

public class ContainerImpl : IContainerWrapper
{
     private readonly Container _container
     public ContainerImpl(Container container)
     {
          _container = container;
     }

     ...
}

並設置StructureMap來解析我的抽象工廠的依賴關系:

x.For<IContainer>.Use(new ContainerImpl(this));
x.For<IFactory>.Use<Factory>()

我的工廠會更簡單,並會創建我的實例:

public class SearchmanagerFactory
{
    private readonly IContainerWrapper _container;

    public SearchmanagerFactory(IContainerProvider containerProvider)
    {
        _container = containerProvider;
    }

    public ISearchManager Create(string provider)
    {
       //eed to handle the bad input for provider.
        return (ISearchManager)
            _container.Resolve<ISearchManager>(provider);
    }
}

這樣看起來很干凈:)。 思考?

這是一個廣泛的評論,而不是解釋為什么AbstractFactory看起來很復雜的答案。 這是一個看起來更接近現實的東西:

class StatServiceFactory : IStatServiceFactory
{
    public IStatService Create(string provider)
    {
        switch(provider)
        {
            case "blog":
                return new  StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder);
                           //How to resolve the Config, the SearchManager, and BooleanQueryBuilder?   
                           //Add more abstract factories? It starts to get messy in my opinion...
        }
    }
}

FacetRepository對於任何提供者都是相同的,但是SearchManager更改,ConfigManager更改,而BooleanQueryBuilder是一個抽象類,具有針對不同提供者的不同實現(因為每個API對於他們的查詢不使用相同的關鍵字)所有這些依賴關系當前都已解析通過structuremap,基於控制器的類型。

我真的希望在這里保留StructureMap的好處,而不是一直使用工廠,每個不同的部分。

請在我的問題的最后看到我的編輯,以獲得對我的問題的另一個建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM