Я сделал небольшое приложение с, как мне кажется, нормальной многослойной архитектурой. https://github.com/mirypoko/Astoms Подскажите пожалуйста, может я что-то делаю не так? Может есть какие-то более хорошие подходы.
Есть несколько вопросов:
В данный момент существует множество подходов к созданию архитектуры MVC приложений (Domain Driven Design, 3d-layered architecture, onion structure, etc).
Мой любимый подход это 3х уровневая архитектура и вот почему:
Приложение ASP.NET MVC с этим подходом выглядело бы так:
Благодаря такой архитектуре изменения в одном уровне не повлекут за собой огромных изменений (а при правильном построении SOLID вообще не изменят другие слои).
Теперь по поводу реализации и вопросов:
PS. Под Generic Repository хорошо подходит реализация Generic UoW:
public interface IUnitOfWork : IDisposable
{
T GetRepository<T>() where T : class;
int Save();
}
public class UnitOfWork : IUnitOfWork
{
private Dictionary<string, object> _repositories;
private IDbContext _dbContext;
public UnitOfWork() : this(new AppContext())
{
}
public UnitOfWork(IDbContext dbContext)
{
_dbContext = dbContext;
_repositories = new Dictionary<string, object>();
}
/// <summary>
/// Search for repository in dictionary and if not exists creating new.
/// </summary>
/// <typeparam name="T">Type of repository to create.</typeparam>
/// <returns>Returns repository with DbContext provided by UoW.</returns>
public T GetRepository<T>() where T : class
{
if (!_repositories.ContainsKey(nameof(T)))
{
var repository = (T)Activator.CreateInstance(typeof(T), _dbContext);
_repositories.Add(nameof(T), repository);
}
return (T)_repositories[nameof(T)];
}
/// <summary>
/// Saves all pending changes.
/// </summary>
/// <returns>The number of objects in an Added, Modified, or Deleted state</returns>
public int Save()
{
return _dbContext.SaveChanges();
}
/// <summary>
/// Disposes current object.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
2.
Во-первых, DbContext сам по себе является и репозиторием и единицей работы. Поэтому делать обёртки поверх него нет смысла. Имхо.
Статический UnitOfWork? Это как вообще? Смысл этого паттерна в том, что создаётся юнит, выполняется какая-то работа, закрывается юнит, что приводит к сохранению (или откату) данных, освобождению занятых ресурсов и т. п. То есть он никак не должен быть статическим.
3.
Как уже сказано выше, единица работы должна создаваться и удаляться по ходу работы. Реализовав интерфейс IDisposable, можно использовать удобную конструкцию using, что приведёт к закрытию юнита даже в случае исключений.
Но, как я уже сказал, DbContext не нуждается в обёртках.
5. Их может быть сколько угодно. Например, один контекст может быть для работы с данными пользователей сайта, другой - для админов. Однако, чем их больше, тем тяжелее писать, а главное - поддерживать код.
Сделав несколько контекстов, намного сложнее осуществлять миграции! Спасибо tym32167 за напоминание.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей