2

今日、私のコードを DRY しようとして、次のことをしたいと思います。(それが最善の方法かどうかはわかりませんが、サイト全体で何かを変更したい場合、複数のメソッドを継続的に更新する必要があるコードベースが増え続けるよりは良いようです)

継承について私が知っていることは恐ろしいことです。私が使用するコード/ライブラリのいずれにも疑問を呈したことはなく、これまでにこのようなものを実際に書き込もうとしたことはありませんが、学びたいです...これが私の悟りの日になることを願っています:P

私の質問に:

次のような add メソッドを (すべてのコントローラーで) 持っているとします。

public ActionResult Add(VM_Down_Time_Capture viewModel)
        {
            using (Down_Time_CaptureRepository repository = new Down_Time_CaptureRepository())
            {
                if (!ModelState.IsValid)
                    return ReturnValidationFailure(ViewData.ModelState.Values);

                Down_Time_Capture model = new Down_Time_Capture();
                model.InjectFrom(viewModel);

                string mserMsg = repository.Add(model, User.Identity.Name);

                if (!string.IsNullOrEmpty(mserMsg))
                    return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));

                repository.Save();

                return Json("Added successfully.", JsonRequestBehavior.AllowGet);
            }
        }

そして現時点では、次のものも持っています。

T4 Templates/EF によって生成されます。

    ViewModels, Repositories, (Standard) EF Models

基本的な CRUD 機能を含むカスタム ControllerBase クラスから継承する、ページごとに ModelSpecfic ベース コントローラー (T4 を使用して実行可能) が必要だと考えています。そうすれば、コントローラーごとにカスタムコードを作成でき、コードベースはよりクリーンで小さくなり、ベースファイルを再生成する必要がある場合でも影響を受けません

必要なものの行に何かを実装する方法がよくわかりません。私がこれまでに理解しているのは、リポジトリを持つ必要がなく、ビューモデルもベースから継承し、[B]で使用しているものを何らかの形で指定する必要があるということです...しかし、それを行う方法については私は知りません知る

たとえば(これは私の実際のコードではなく、私の最善の試みであり、驚くほど混乱しているため、非常にハックです:S)

    public class Down_Time_CaptureController : Down_Time_CaptureBase
    {
     //[A]
    }

    //Generated by T4
    public class Down_Time_CaptureBase: ControllerBase
    {
      //[B]
       public override EntityObject CreateNewModel()
       {
          return new Down_Time_Capture();
       }

       public override Base_Repository CreateNewRepository()
       {
          return new Down_Time_CaptureRepository();
       }

       public override Base_ViewModel CreateNewViewModel()
       {
          return new VM_Down_Time_Capture();
       }

      //how would i go about specifying which repository & model & view model to use
      //although i expect it to be something to what i did here above
      //and how would i go about calling the new generic add method (but in context of this controller)?

    }

    //coded once
    public abstract class ControllerBase: Controller
    {
        //[C]
        //make abstract so i have to override it
        public abstract Base_Controller CreateNewModel();
        public abstract Base_Controller CreateNewRepository();
        public abstract Base_Controller CreateNewViewModel();

        //I'm assuming my generified add method would go in here  
        public virtual ActionResult Add(Base_ViewModel viewModel)
        {
           using (Base_Repository repository = CreateRepository())
           {
                   if (!ModelState.IsValid)
                       return ReturnValidationFailure(ViewData.ModelState.Values);

                   EntityObject model = CreateNewModel();
                   model.InjectFrom(viewModel);

                   string mserMsg = repository.Add(model, User.Identity.Name);

                   if (!string.IsNullOrEmpty(mserMsg))
                       return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));

                   repository.Save();

                   return Json("Added successfully.", JsonRequestBehavior.AllowGet);
            }       
        }
    }
4

1 に答える 1

3

これがあなたが求めているものの簡単な一般的な解釈です:

// concrete controller implementation
public class Down_Time_CaptureController: ControllerBase<Down_Time_Capture, VM_Down_Time_Capture, Down_Time_CaptureRepository>
{
}

// generic controller base
public abstract class ControllerBase<TModel, TViewModel, TRepository>: Controller
        where TModel : Base_Model, new()
        where TViewModel : Base_ViewModel, new()
        where TRepository : Base_Repository, new()
{
    protected virtual TModel CreateNewModel()
    {
           return (TModel)Activator.CreateInstance<TModel>();

    }

    protected virtual TRepository CreateNewRepository()
    {
           return (TRepository)Activator.CreateInstance<TRepository>();
    }

    protected virtual TViewModel CreateNewViewModel()
    {
            return (TViewModel)Activator.CreateInstance<TViewModel>();
    }

    //I'm assuming my generified add method would go in here  
    public virtual ActionResult Add(TViewModel viewModel)
    {
       using (var repository = CreateRepository())
       {
               if (!ModelState.IsValid)
                   return ReturnValidationFailure(ViewData.ModelState.Values);

               var model = CreateNewModel();
               model.InjectFrom(viewModel);

               string mserMsg = repository.Add(model, User.Identity.Name);

               if (!string.IsNullOrEmpty(mserMsg))
                   return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));

               repository.Save();

               return Json("Added successfully.", JsonRequestBehavior.AllowGet);
        }       
    }
}

いくつかの注意:

  1. おそらく、3つのタイプ(Model、ViewModel、Repository)のインターフェイスを作成し、それらを一般的な制約として使用することをお勧めします。
  2. おそらく、汎用のリポジトリインターフェイスと基本実装が必要になります(したがって、各リポジトリを個別にコーディングし、同様のロジックを一方から他方にコピーする必要はありません)。
  3. 制御の反転コンテナと依存性注入の使用を検討してください。たとえば、コントローラーにリポジトリのインスタンスの作成を処理させるのではなく、それをプロパティにして、コンストラクターから設定します。次に、選択したIoC(NinjectやAutofacなど)を使用して具体的な実装を登録できます。これにより、依存関係とコントローラー自体の両方の作成と存続期間が管理されます。
于 2012-05-10T08:57:32.290 に答える