Описанная архитектура взята из проекта Expresscoin.
1-Контроллеры обращаются к отдельным сервисам AppContext-а:
this.AppContext.OrderService.GetUserOrders()
Базовый контроллер имеет ссылку на AppContext, который живет в web приложении
AppContext создается в базовом контроллере,
причем в конструкторе используется код для предотвращения создания нескольких экземпляров AppContext
protected BaseApiController()
{
this.AppContext = AppContext.Current;
if (this.AppContext == null)
{
this.disposeAppContext = true;
this.AppContext = AppContext.Current = new AppContext();
}
}
2-статическое свойство AppContext.Current сохраняет или достает экземпляр AppContext из/в
HttpContextFactory.Current.Items
public static AppContext Current
{
get { return (AppContext)HttpContextFactory.Current.Items[HttpContextKey]; }
set { HttpContextFactory.Current.Items[HttpContextKey] = value; }
}
т.о. в ситуации, когда в одном и том же запросе будет создаваться несколько контроллеров (хотя я не вижу как так может произойти на практике) один и тот же экземпляр будет браться из HttpContext.Items
3-HttpContextFactory инкапсулирует в себе доступ к HttpContext.Current, но при этом имеет возможность подсунутьфэйковый HttpContext для тестовых целей:
public static class HttpContextFactory
{
private static HttpContextBase _context;
public static HttpContextBase Current
{
get
{
if (_context != null)
return _context;
if (HttpContext.Current == null)
throw new InvalidOperationException("HttpContext not available");
return new HttpContextWrapper(HttpContext.Current);
}
}
public static void SetCurrentContext(HttpContextBase context)
{
_context = context;
}
}
4-AppContext выставляет наружу сервисы
public ICurrencyService CurrencyService { get { return this.service; } }
public IOrderService OrderService { get { return this.service; } }
Все эти сервисы реализует класс MainService
public AppContext()
{
this.service = new MainService();
}
5-Класс MainService живет в business layer и представляет собой partial класс. Каждая отдельная часть реализует отдельный интерфейс: ICurrencyServic, IOrderServic.
6- Внутри класса MainService есть ссылка на DbContext (здесь MainDB), который создается в конструкторе
public MainService()
{
this.dbContext = new MainDB();
}
7-Класс MainService наследует абстрактный класс Disposable (живет в Tools)
public abstract class Disposable : IDisposable
{
~Disposable()
{
// Finalizer calls Dispose(false)
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
это нужно для освобождения DbContex, в MainService:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.dbContext != null)
{
this.dbContext.Dispose();
this.dbContext = null;
}
}
}
В базовом контроллере, также реализуется Dispose:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.AppContext != null)
{
if (this.disposeAppContext)
{
AppContext.Current = null;
this.AppContext.Dispose();
}
this.AppContext = null;
}
}
base.Dispose(disposing);
}
1-Контроллеры обращаются к отдельным сервисам AppContext-а:
this.AppContext.OrderService.GetUserOrders()
Базовый контроллер имеет ссылку на AppContext, который живет в web приложении
AppContext создается в базовом контроллере,
причем в конструкторе используется код для предотвращения создания нескольких экземпляров AppContext
protected BaseApiController()
{
this.AppContext = AppContext.Current;
if (this.AppContext == null)
{
this.disposeAppContext = true;
this.AppContext = AppContext.Current = new AppContext();
}
}
2-статическое свойство AppContext.Current сохраняет или достает экземпляр AppContext из/в
HttpContextFactory.Current.Items
public static AppContext Current
{
get { return (AppContext)HttpContextFactory.Current.Items[HttpContextKey]; }
set { HttpContextFactory.Current.Items[HttpContextKey] = value; }
}
т.о. в ситуации, когда в одном и том же запросе будет создаваться несколько контроллеров (хотя я не вижу как так может произойти на практике) один и тот же экземпляр будет браться из HttpContext.Items
3-HttpContextFactory инкапсулирует в себе доступ к HttpContext.Current, но при этом имеет возможность подсунутьфэйковый HttpContext для тестовых целей:
public static class HttpContextFactory
{
private static HttpContextBase _context;
public static HttpContextBase Current
{
get
{
if (_context != null)
return _context;
if (HttpContext.Current == null)
throw new InvalidOperationException("HttpContext not available");
return new HttpContextWrapper(HttpContext.Current);
}
}
public static void SetCurrentContext(HttpContextBase context)
{
_context = context;
}
}
4-AppContext выставляет наружу сервисы
public ICurrencyService CurrencyService { get { return this.service; } }
public IOrderService OrderService { get { return this.service; } }
Все эти сервисы реализует класс MainService
public AppContext()
{
this.service = new MainService();
}
5-Класс MainService живет в business layer и представляет собой partial класс. Каждая отдельная часть реализует отдельный интерфейс: ICurrencyServic, IOrderServic.
6- Внутри класса MainService есть ссылка на DbContext (здесь MainDB), который создается в конструкторе
public MainService()
{
this.dbContext = new MainDB();
}
7-Класс MainService наследует абстрактный класс Disposable (живет в Tools)
public abstract class Disposable : IDisposable
{
~Disposable()
{
// Finalizer calls Dispose(false)
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
это нужно для освобождения DbContex, в MainService:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.dbContext != null)
{
this.dbContext.Dispose();
this.dbContext = null;
}
}
}
В базовом контроллере, также реализуется Dispose:
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.AppContext != null)
{
if (this.disposeAppContext)
{
AppContext.Current = null;
this.AppContext.Dispose();
}
this.AppContext = null;
}
}
base.Dispose(disposing);
}