3

asp.Net Mvc 4 アプリをセットアップし、Onion Architectureパターンを使用して構成しようとしています。過去に、このような作業単位パターンを使用しました

public class UnitOfWork : IUnitOfWork, IDisposable
{

private IRepository<CallModel> _callRepo;
private IRepository<UserModel> _userRepo;

    public IRepository<CallModel> CallRepo
    {
        get
        {
            if (_callRepo == null)
            {
                _callRepo = new Repository<CallModel>();
            }
            return _callRepo;
        }
    }

    public IRepository<UserModel> UserRepo
    {
        get
        {
            if (_userRepo == null)
            {
                _userRepo = new Repository<UserModel>();
            }
            return _userRepo;
        }
    }
}

次に、UnitOfWork クラスのインスタンスをコントローラーに渡して、このような単純な CRUD を実行します。

    public class QuestionsController : Controller
{
    private IUnitOfWork _unitOfWork;

    [Inject]
    public QuestionsController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

アプリを 3 つのプロジェクトに分けました。

  1. インフラストラクチャー
  2. ウェブ

Core プロジェクトにすべてのインターフェイスがあり、Infrastructure プロジェクトに IRepository インターフェイスの実装があります。UnitOfWork クラスをコア プロジェクトに配置すると、インフラストラクチャ プロジェクトで新しいリポジトリが必要になるため、コアからインフラストラクチャへの依存関係を作成します。これをインフラストラクチャに含めると、(コントローラを含む) Web プロジェクトはインフラストラクチャに依存し、ソリューション全体がオニオンではなくスパゲッティのように見えます。

4

4 に答える 4

1

インターフェースはすべてコアプロジェクトにあり、インフラストラクチャプロジェクトにはIRepositoryインターフェースが実装されています。UnitOfWorkクラスをコアプロジェクトに配置すると、インフラストラクチャプロジェクトに新しいリポジトリが必要になるため、コアからインフラストラクチャへの依存関係を作成しています。

うーん、そうではありません。作業クラスのユニットは、リポジトリの実装自体ではなく、IRepositoryに依存している必要があります。依存性注入を使用している場合は、適切なタイプを見つけて実行時に提供する必要があるため、これで問題が発生することはありません。DIを使わなくてもOnionアーキテクチャが可能かどうかはわかりません。

david.sの回答も参照してください。これは、まさに私が設定した方法です。依存関係を配線することのみを目的としたプロジェクトがあります。

于 2013-02-13T16:54:40.703 に答える
0

david.sがDependencyResolutionという名前のプロジェクトを作成したいのですが、Web、コア、インフラストラクチャを参照させます。

そのプロジェクトでは、次のことができます。

[assembly: PreApplicationStartMethod(typeof(Start), "Register")]

namespace DependencyResolution
{
    public static class Start
    {
        public static void Register()
        {
            UnityConfig.Register();
        }
    }
}

とDIを登録します。

namespace DependencyResolution
{    
    public static class UnityConfig
    {
        public static void Register()
        {
            DependencyResolver.SetResolver(new UnityDependencyResolver());
        }
    }
}

したがって、Webとインフラストラクチャ間の参照は必要ありません。

よろしくお願いします

于 2013-02-26T13:20:17.523 に答える
0

私がしていることは、IoC コンテナーを構成する場所へのDependencyResolution参照と名前をCore持つ別のプロジェクトを作成することです。その後、プロジェクトからInfrastructureのみ参照できます。DependencyResolutionWeb

于 2013-02-13T16:50:14.993 に答える
0

まだ価値があることについては、UnitOfWork パターンを適用する独自のライブラリを以前のコード サンプルとは少し異なる方法で実装しましたが、実際には非常にうまく機能することがわかりました。要するに、スコープを作成し、必要に応じてアンビエント作業単位 (-manager) にリソースを登録することで、.NET トランザクションの動作方法をコピーしました。基本的に何が起こるかというと、新しいメッセージ/リクエストが処理されると、次のコードが実行されます:

public void Handle<TMessage>(TMessage message)
{
    using (var scope = CreateMessageProcessorContextScope())
    {
        HandleMessage(message);
        scope.Complete();
    }
}

トランザクションと同様に、スレッドがまだスコープ内にあるとすぐに、要求中に使用および変更されるすべてのリソースが動的に参加できるアンビエント UnitOfWork コントローラーが存在します。これを行うには、次の 2 つのメソッドを持つ IUnitOfWork インターフェイスを実装します。

public interface IUnitOfWork
{
    bool RequiresFlush();

    void Flush();
}

このインターフェイスを実装するインスタンスは、次のように自分自身を登録できます。

MessageProcessorContext.Current.Enlist(this);

通常、Repository クラスはこのインターフェイスを実装し、管理された集計が変更/追加/削除されたことを検出すると、それ自体を登録できます (二重登録は無視されます)。

私の場合、フレームワークは、すべてのメッセージ ハンドラーとリポジトリを解決する IOC フレームワークを使用していると想定しているため、現在の IUnitOfWorkManager のインスタンスを挿入できるようにすることで、アンビエント作業単位コントローラーへの登録を容易にしました。必要に応じてコンストラクター。このようにして、作業単位マネージャーと、フラッシュする必要がある実際の部分 (リポジトリ、サービスなど) の依存関係が逆になります。

internal sealed class OrderRepository : IOrderRepository, IUnitOfWork
{
    private readonly IUnitOfWorkManager _manager;
    private readonly Dictionary<Guid, Order> _orders;

    public OrderRepository(IUnitOfWorkManager manager)
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        _manager = manager;
    }

    bool IUnitOfWork.RequiresFlush()
    {
        return _orders.Values.Any(order => order.HasChanges());
    }

    void IUnitOfWork.Flush()
    {
        // Flush here...
    }

    public void Add(Order order)
    {
        _orders.Add(order.Id, order);
        _manager.Enlist(this);
    }
}

リクエストが正常に処理されるとすぐに (例外がスローされない)、scope.Complete() が呼び出されます。これにより、コントローラーはすべての登録済みアイテムを (まだ) フラッシュする必要があるかどうかをチェックします (RequiresFlush() を呼び出すことにより)。そうであれば、(Flush() を呼び出して) それらをフラッシュします。

全体として、これにより、(私の観点では) 非常に保守しやすいソリューションが可能になり、新しいリポジトリやその他の依存関係を、マスターの作業単位クラスを変更せずにオンザフライで追加できるようになります。任意のトランザクションに参加します。

于 2013-06-13T12:24:28.807 に答える