3

質問全体を編集したので、不思議に思わないでください:)

さて、私は、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 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);
    }
}

コントローラーでの使用法:

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

ご覧のとおり、IMappingServiceが隠されています。IMappingServiceを使用する場合、コントローラーはインターフェースについて何も認識してはなりませんAutoMappedHybridViewResult

は適切ですかMappingActionResultstatic IMappingServerそれとも DI の原則に違反していますか?

4

2 に答える 2

1

より良い設計は、IMappingService に依存する ViewResultFactory を持つことだと思います。その後、それをコントローラーに挿入できます。次に、次のように呼び出します。

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);
}

そうすれば、コントローラーから実装を隠すことができ、コンテナーに依存する必要がなくなります。

于 2010-09-30T22:29:57.553 に答える
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 に入れることができると思いますが、コントローラーの方が私には理にかなっています。コントローラーで IMappingService を使用したくない場合は、いつでも HybridViewResultFactory でラップし、コントローラーでそのオブジェクトにアクセスできます。その場合、ショートカット メソッドは次のようになります。

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 を使用する理由を理解していれば、明確な答えを出すのが簡単になります。

アクションの結果を使用して、常に一緒に使用されるとは限らず、別々に使用できる 2 つの機能を処理しているようです。また、ActionResult に含める必要があるという明確な指示もありません。

おそらく、(a) html (ViewResult) 出力以外の結果に対して Automapper 機能を活用でき、(b) モデルを自動マッピングする必要なく、ajax リクエストを自動検出する機能を活用できます。

ビューモデルの自動マッピングを使用して、ビューモデルをコントローラーアクションに直接挿入できるように思われます。これにより、IMappingService に対するコントローラーの依存関係が削除されます。必要なのは、IMappingService に注入される ModelBinder クラスです (その実装には、リポジトリまたはデータストア タイプの依存関係が含まれていると想定しています)。

モデルバインダーを活用する方法を説明する優れた記事を次に示します。

次に、次のように、Automapped が必要なクラスで DefaultModelBinder を上書きできます。

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

ここで、HybridViewResult に関しては、代わりにアクション フィルターを使用してこれを処理することをお勧めします。したがって、ActionResult または ViewResultBase をアクション メソッドの Result タイプとして使用し、アクション フィルターで装飾することができます。

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

全体として、これはこれら 2 つの機能を ActionResult に結合するよりもはるかに優れたソリューションになると思います。

于 2010-10-03T06:39:11.343 に答える