3

我編輯我的整個問題注入依賴,所以不知道:)Bestpractice DI與ASP.NET MVC和StructureMap - 如何在一個ActionResult

嗯,我想有一個ActionResult這需要域模型數據和一些額外的參數,即用於分頁列表的頁面索引和頁面大小。它根據Web請求的種類(不管是否是ajax請求)返回PartialViewResult或ViewResult來決定它自己。

通過使用IMappingService自動映射所緩存的數據,IMappingService負責將任何域模型數據轉換爲視圖模型。 爲簡單起見,MappingService使用AutoMapper。

MappingActionResult:

public abstract class MappingActionResult : ActionResult 
{ 
    public static IMappingService MappingService; 
} 

BaseHybridViewResult:

public abstract class BaseHybridViewResult : MappingActionResult 
{ 
    public const string defaultViewName = "Grid"; 

    public string ViewNameForAjaxRequest { get; set; } 
    public object ViewModel { get; set; } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     if (context == null) throw new ArgumentNullException("context"); 
     var usePartial = ShouldUsePartial(context); 
     ActionResult res = GetInnerViewResult(usePartial); 

     res.ExecuteResult(context); 
    } 

    private ActionResult GetInnerViewResult(bool usePartial) 
    { 
     ViewDataDictionary viewDataDictionary = new ViewDataDictionary(ViewModel); 
     if (String.IsNullOrEmpty(ViewNameForAjaxRequest)) 
     { 
      ViewNameForAjaxRequest = defaultViewName; 
     } 

     if (usePartial) 
     { 
      return new PartialViewResult { ViewData = viewDataDictionary, ViewName = ViewNameForAjaxRequest }; 
     } 

     return new ViewResult { ViewData = viewDataDictionary }; 
    } 

    private static bool ShouldUsePartial(ControllerContext context) 
    { 
     return context.HttpContext.Request.IsAjaxRequest(); 
    } 
} 

AutoMappedHybridViewResult:

public ActionResult Index(int page = 1) 
{ 
    return new AutoMappedHybridViewResult<TeamEmployee, TeamEmployeeForm>(_teamEmployeeRepository.GetPagedEmployees(page, PageSize)); 
} 
:在控制器

public class AutoMappedHybridViewResult<TSourceElement, TDestinationElement> : BaseHybridViewResult 
{ 
    public AutoMappedHybridViewResult(PagedList<TSourceElement> pagedList) 
    { 
     ViewModel = MappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList); 
    } 

    public AutoMappedHybridViewResult(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest) 
    { 
     ViewNameForAjaxRequest = viewNameForAjaxRequest; 
     ViewModel = MappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList); 
    } 

    public AutoMappedHybridViewResult(TSourceElement model) 
    { 
     ViewModel = MappingService.Map<TSourceElement, TDestinationElement>(model); 
    } 

    public AutoMappedHybridViewResult(TSourceElement model, string viewNameForAjaxRequest) 
    { 
     ViewNameForAjaxRequest = viewNameForAjaxRequest; 
     ViewModel = MappingService.Map<TSourceElement, TDestinationElement>(model); 
    } 
} 

用法

因此,您可以看到隱藏了IMappingService。當使用AutoMappedHybridViewResult時,控制器不應該知道有關IMappingService接口的任何信息。

MappingActionResultstatic IMappingServer適當還是我違反DI原則?

回答

1

我認爲更好的設計是有一個ViewResultFactory取決於IMappingService,然後你可以注入到你的控制器。然後調用它像這樣:

public class MyController : Controller 
{ 
    IViewResultFactory _viewResultFactory; 
    ITeamEmployeeRepository _teamEmployeeRepository; 

    public MyController(IViewResultFactory viewResultFactory) 
    { 
     _viewResultFactory = viewResultFactory; 
    } 

    public ActionResult MyAction(int page, int pageSize) 
    { 
     return 
      _viewResultFactory.GetResult<TeamEmployee, TeamEmployeeForm>(
       _teamEmployeeRepository.GetPagedEmployees(page, pageSize)); 
    } 
} 

的實施將是這樣的(你需要爲每個HybridViewResult構造函數創建重載):

public HybridViewResult<TSourceElement, TDestinationElement> GetResult<TSourceElement, TDestinationElement>(PagedList<TSourceElement> pagedList) 
{ 
    return new HybridViewResult<TSourceElement, TDestinationElement>(_mappingService, pagedList); 
} 

這樣,你隱藏你的控制器的實現,而且你不必依靠容器。

+0

我已經更新了我的問題 – Rookian 2010-10-02 19:51:32

+0

那麼你的工廠返回? PagedList 或(Partial-)ViewResult? – Rookian 2010-10-06 20:11:20

+0

我更新了我的答案,它會返回查看結果 – 2010-10-06 22:38:50

0

有幾點不同,你可以注入IMappingService。 http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx是一個很好的網站,可以幫助您爲.NET MVC選擇合適的擴展點。

如果你想堅持讓這個功能成爲一個派生的ActionResult,那麼我認爲你可以把這個依賴項放在ActionInvoker中,如果你願意的話,但是Controller對我更有意義。如果您不想在控制器中使用IMappingService,則始終可以將其包裝在HybridViewResultFactory中,並在Controller中訪問該對象。在這種情況下,你的快捷方法看起來像:

public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest) 
{ 
    HybridViewResultFactory.Create<TSourceElement, TDestinationElement>(pagedList, viewNameForAjaxRequest); 
} 

我不知道爲什麼你需要使用一個ActionResult,但如果沒有原因,使得它明確有必要,你可以創建一個HybridViewModel類和一個注入了映射服務依賴項的HybridViewModelBinder類。

我假設你想使用構造器注入,但如果你在你的UI組件StructureMap的依賴,你可以訪問一個靜態的依賴解析器類(如Clowers說)。

這個問題會更容易給出一個明確的答案,如果我爲什麼你使用一個ActionResult理解。

看起來好像你正在使用動作結果來處理兩個不一定總是在一起的功能,這可以單獨使用。另外,沒有明確的跡象表明它需要在ActionResult中。 (a)您可以(a)將Automapper功能用於非HTML(ViewResult)輸出的結果,並且(b)您可以利用自動檢測ajax請求的功能,而無需自動映射模型。

在我看來,像視圖模型的自動映射可用於直接注射視圖模型到控制器動作,從而消除了控制器上IMappingService依賴。你需要的是一個ModelBinder類,用你的IMappingService注入(我假設它的實現包含一個存儲庫或數據存儲類型依賴)。

這裏是一個很好的文章,解釋瞭如何利用模型聯:http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx

然後你就可以覆蓋DefaultModelBinder在需要被Automapped如下類別:

public ActionResult DoItLikeThis([AutoMap(typeof(MyDomainModelClass))]MyViewModelClass viewModel){ 
       //controller action logic 
    } 

現在,關於HybridViewResult,我建議你用行爲過濾器處理這個代替。所以,你可以只使用的ActionResult或ViewResultBase的結果類型的操作方法,並用行爲過濾裝飾它,即:

[AutoSelectViewResult] 
    public ViewResultBase AndDoThisLikeSo(){ 
       //controller action logic 
    } 

我認爲總體而言,這將是比這兩個功能結合到一個更好的解決方案一個ActionResult。

+0

「HybridViewResult」類中的「混合」表示自動檢測是否存在ajax請求。如果它是ajax請求,「HybridViewResult」返回PartialViewResult,否則返回ViewResult。我希望這是有道理:) – Rookian 2010-10-03 09:50:56

+0

在這種情況下,我會建議開溝「AutoMappedHybridView」一起,並要求每個功能方法使用AutoMapActionFilter和AutoSelectResultTypeActionFilter。 我的推理? ...這是越來越長我要追加上面的實際文章,所以閱讀... – smartcaveman 2010-10-03 21:59:14

+0

我害怕有我的控制器操作這麼多的ActionFilters。 – Rookian 2010-10-11 08:13:17