Unité de travail + dépôt + couche de service avec l'injection de dépendance

Je suis en train de concevoir une application web et un service windows et que vous voulez utiliser à l'unité de travail + dépôt de la couche en conjonction avec une couche de service, et je vais avoir quelques difficultés à mettre tous ensemble pour que le client les applications de contrôle de la transaction de données avec l'unité de travail.

L'unité de travail est une collection de tous les référentiels inscrits dans la transaction avec la validation et les opérations de restauration

public interface IUnitOfWork : IDisposable
{
    IRepository<T> Repository<T>() where T : class;
    void Commit();
    void Rollback();
}

Le générique référentiel a des opérations qui seront effectuées sur la couche de données pour un modèle en particulier (tableau)

public interface IRepository<T> where T : class 
{
    IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, IList<ISortCriteria<T>> sortCriterias = null);
    PaginatedList<T> GetPaged(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, PagingOptions<T> pagingOptions = null);
    T Find(Expression<Func<T, bool>> filter, IList<Expression<Func<T, object>>> includedProperties = null);
    void Add(T t);
    void Remove(T t);
    void Remove(Expression<Func<T, bool>> filter);
}

La mise en œuvre concrète de l'unité de travail utilise entity framework sous le capot (DbContext) pour enregistrer les modifications apportées à la base de données, et une nouvelle instance de la classe DbContext est créé par unité de travail

public class UnitOfWork : IUnitOfWork
{
    private IDictionary<Type, object> _repositories;
    private DataContext _dbContext;
    private bool _disposed;

    public UnitOfWork()
    {
        _repositories = new Dictionary<Type, object>();
        _dbContext = new DataContext();
        _disposed = false;
    }

Les référentiels dans l'unité de travail sont créés lors de l'accès si elles n'existent pas dans l'unité de travail de l'instance. Le référentiel prend la DbContext comme un paramètre de constructeur de sorte qu'il peut travailler efficacement dans le courant de l'unité de travail

public class Repository<T> : IRepository<T> where T : class
{
    private readonly DataContext _dbContext;
    private readonly DbSet<T> _dbSet;

    #region Ctor
    public Repository(DataContext dbContext)
    {
        _dbContext = dbContext;
        _dbSet = _dbContext.Set<T>();
    }
    #endregion

J'ai également un service de classes qui encapsulent les flux de travail d'entreprise de la logique et de prendre leurs dépendances dans le constructeur.

public class PortfolioRequestService : IPortfolioRequestService
{
    private IUnitOfWork _unitOfWork;
    private IPortfolioRequestFileParser _fileParser;
    private IConfigurationService _configurationService;
    private IDocumentStorageService _documentStorageService;

    #region Private Constants
    private const string PORTFOLIO_REQUEST_VALID_FILE_TYPES = "PortfolioRequestValidFileTypes";
    #endregion

    #region Ctors
    public PortfolioRequestService(IUnitOfWork unitOfWork, IPortfolioRequestFileParser fileParser, IConfigurationService configurationService, IDocumentStorageService documentStorageService)
    {
        if (unitOfWork == null)
        {
            throw new ArgumentNullException("unitOfWork");
        }

        if (fileParser == null)
        {
            throw new ArgumentNullException("fileParser");
        }

        if (configurationService == null)
        {
            throw new ArgumentNullException("configurationService");
        }

        if (documentStorageService == null)
        {
            throw new ArgumentNullException("configurationService");
        }

        _unitOfWork = unitOfWork;
        _fileParser = fileParser;
        _configurationService = configurationService;
        _documentStorageService = documentStorageService;
    }
    #endregion

L'application web est une ASP.NET MVC application, le contrôleur reçoit ses dépendances injecté
dans le constructeur. Dans ce cas, l'unité de service et de travail de la classe sont injectés. L'action effectue une opération exposées par le service, comme la création d'un enregistrement dans le dépôt et l'enregistrement d'un fichier à un serveur de fichiers à l'aide d'un DocumentStorageService, puis à l'unité de travail s'est engagé dans l'action du controller.

public class PortfolioRequestCollectionController : BaseController
{
IUnitOfWork _unitOfWork;
IPortfolioRequestService _portfolioRequestService;
IUserService _userService;
#region Ctors
public PortfolioRequestCollectionController(IUnitOfWork unitOfWork, IPortfolioRequestService portfolioRequestService, IUserService userService)
{
_unitOfWork = unitOfWork;
_portfolioRequestService = portfolioRequestService;
_userService = userService;
}
#endregion
[HttpPost]
[ValidateAntiForgeryToken]
[HasPermissionAttribute(PermissionId.ManagePortfolioRequest)]
public ActionResult Create(CreateViewModel viewModel)
{
if (ModelState.IsValid)
{
//validate file exists
if (viewModel.File != null && viewModel.File.ContentLength > 0)
{
//TODO: ggomez - also add to CreatePortfolioRequestCollection method
//see if file upload input control can be restricted to excel and csv
//add additional info below control
if (_portfolioRequestService.ValidatePortfolioRequestFileType(viewModel.File.FileName))
{
try
{
//create new PortfolioRequestCollection instance
_portfolioRequestService.CreatePortfolioRequestCollection(viewModel.File.FileName, viewModel.File.InputStream, viewModel.ReasonId, PortfolioRequestCollectionSourceId.InternalWebsiteUpload, viewModel.ReviewAllRequestsBeforeRelease, _userService.GetUserName());
_unitOfWork.Commit();                            
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
return View(viewModel);
}
return RedirectToAction("Index", null, null, "The portfolio construction request was successfully submitted!", null);
}
else
{
ModelState.AddModelError("File", "Only Excel and CSV formats are allowed");
}
}
else
{
ModelState.AddModelError("File", "A file with portfolio construction requests is required");
}
}
IEnumerable<PortfolioRequestCollectionReason> portfolioRequestCollectionReasons = _unitOfWork.Repository<PortfolioRequestCollectionReason>().Get();
viewModel.Init(portfolioRequestCollectionReasons);
return View(viewModel);
}

Sur l'application web, je suis à l'aide de l'Unité DI conteneur d'injection de la même instance de l'unité de travail par requête http pour tous les appelants, de sorte que le contrôleur de classe devient une nouvelle instance, puis la classe de service qui utilise l'unité de travail est la même instance que le contrôleur. De cette façon, le service ajoute quelques enregistrements pour le dépôt qui s'est enrôlé dans une unité de travail et peuvent être commises par le client code du contrôleur.

Une question concernant le code et l'architecture décrite ci-dessus. Comment puis-je me débarrasser de l'unité de travail de dépendance au service des classes? Idéalement, je ne veux pas la classe de service d'avoir une instance de l'unité de travail parce que je ne veux pas le service pour valider la transaction, j'aimerais juste le service de référence au référentiel, il a besoin de travailler avec, et de laisser le contrôleur (code client) s'engager à l'opération quand il voir s'adapte.

Sur l'application du service windows, je voudrais être en mesure d'obtenir un ensemble de documents, avec une seule unité de travail, dire que tous les dossiers en attente de statut. Ensuite je voudrais faire une boucle par tous les dossiers de requête et de la base de données pour obtenir de chacun d'eux individuellement et ensuite vérifier l'état de chacun à chaque tour de boucle parce que l'état a peut-être changé depuis le temps que j'ai interrogé tout à l'heure je veux faire fonctionner sur un seul. Le problème que j'ai maintenant c'est que mon architecture actuelle ne me permet pas d'avoir plusieurs unités d'œuvres pour la même instance du service.

public class ProcessPortfolioRequestsJob : JobBase
{
IPortfolioRequestService _portfolioRequestService;
public ProcessPortfolioRequestsJob(IPortfolioRequestService portfolioRequestService)
{
_portfolioRequestService = portfolioRequestService;
}

La classe d'Emploi ci-dessus prend un service dans le constructeur comme une dépendance et, de nouveau, est résolu par l'Unité. L'instance de service qui est résolu et injecté dépend de l'unité de travail. Je voudrais effectuer deux opérations get sur la classe de service, mais parce que je suis d'exploitation en vertu de la même instance de l'unité de travail, je ne peux pas l'atteindre.

Pour vous tous les gourous de là-bas, avez-vous des suggestions sur comment je peux re-architecte de ma demande, de l'unité de travail + dépôt + les classes de service pour atteindre les objectifs ci-dessus?

J'ai l'intention d'utiliser l'unité de travail + référentiel de modèles pour permettre la testabilité sur mes classes de service, mais je suis ouvert à d'autres modèles de conception qui permettra de rendre mon code plus facile à maintenir et testable en même temps tout en maintenant la séparation des préoccupations.

Mise à jour de 1
Ajout de la classe DataContext que inheris de EF est DbContext où j'ai déclaré mon EF DbSets et des configurations.

public class DataContext : DbContext
{
public DataContext()
: base("name=ArchSample")
{
Database.SetInitializer<DataContext>(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
base.Configuration.ProxyCreationEnabled = false;
}
public DbSet<PortfolioRequestCollection> PortfolioRequestCollections { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new PortfolioRequestCollectionConfiguration());
base.OnModelCreating(modelBuilder);
}
}

OriginalL'auteur Guillermo Gomez | 2014-09-20