Я должен признать, что я новичок в ASP.Net MVC, и в настоящее время я изучаю все лучшие практики о том, как начать свой новый проект. До сих пор я понимал концепции шаблона репозитория и единицы работы и перешел к внедрению зависимостей и инверсии контроля (IoC). Я изучал это в течение последних 2 дней и пришел к выводу, что мне нравятся 2 контейнера IoC, и они StructureMap и NInject, хотя ни один из них не идеален, и мне пока не удалось заставить StructureMap работать, хотя мне нравится свет синтаксис веса.
Вот как устроено мое приложение. Сначала у меня есть следующие интерфейсы для моего контекста данных и хранилища:
public interface IDataContext : IDisposable
{
IRepository<T> Repository<T>() where T : class;
void Commit();
}
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> where);
T Single(Expression<Func<T, bool>> where);
void Insert(T entity);
void Delete(T entity);
}
Тогда у меня есть реализация LinqToSql, например, так:
public class LinqToSqlDataContext : IDataContext
{
private readonly DataContext _context;
public LinqToSqlDataContext(DataContext context)
{
_context = context;
}
public IRepository<T> Repository<T>() where T : class
{
return new LinqToSqlRepository<T>(_context);
}
public void Commit()
{
_context.SubmitChanges();
}
public void Dispose()
{
}
}
public class LinqToSqlRepository<T> : IRepository<T> where T : class
{
private readonly DataContext _context;
public LinqToSqlRepository(DataContext context)
{
_context = context;
}
public IEnumerable<T> GetAll()
{
return _context.GetTable<T>();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> where)
{
return _context.GetTable<T>().Where(where);
}
public T Single(Expression<Func<T, bool>> where)
{
return _context.GetTable<T>().SingleOrDefault(where);
}
public void Insert(T entity)
{
_context.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
_context.GetTable<T>().DeleteOnSubmit(entity);
}
}
В настоящее время я нашел 2 места, где мне нужно использовать мой контекст данных.
- В конструкторе контроллера
- В атрибуте аннотации данных (который не может иметь конструктора)
Я пытался удалить любые зависимости в меру своих способностей. Скажите, пожалуйста, если у вас есть какие-либо рекомендации.
Теперь о моих реализациях контейнера IoC. Первый NInject Мне удалось изменить мой файл Global.asax.cs следующим образом:
public class MvcApplication : NinjectHttpApplication
{
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel(new ServiceModule());
// Gives my wrapper class access to the kernel instance
IoCContainer.Initialize(kernel);
return kernel;
}
public static void RegisterRoutes(RouteCollection routes)
{
...
}
}
internal class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IDataContext>().To<LinqToSqlDataContext>().InRequestScope();
Bind<DataContext>().To<MyDataContext>().InRequestScope();
}
}
public static class IoCContainer
{
private static IKernel _kernel;
public static void Initialize(IKernel kernel)
{
_kernel = kernel;
}
public static T Get<T>()
{
return _kernel.Get<T>();
}
public static object Get(Type type)
{
return _kernel.Get(type);
}
}
Это хорошо работает. Конструкторам контроллеров теперь автоматически устанавливаются зависимости, и в моем атрибуте аннотации данных я могу сказать:
var context = IoCContainer.Get<IDataContext>();
Мне нравится NInject, но даже с файлом Global.asax.cs, унаследованным от NinjectHttpApplication (который обрабатывает большую часть сантехники), я все еще чувствую, что я хочу удалить довольно много.
Затем я посмотрел на StructureMap. StructureMap не поставляется со своим собственным встроенным в ControllerFactory, но его довольно просто сгенерировать. Я временно поместил его в свой файл Global.asax.cs во время тестирования. Вот окончательное содержимое файла:
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
// Configure structure map
ObjectFactory.Initialize(x =>
{
x.For<IDataContext>()
.HttpContextScoped()
.Use<LinqToSqlDataContext>();
x.For<DataContext>()
.HttpContextScoped()
.Use<MyDataContext>();
});
}
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
public static void RegisterRoutes(RouteCollection routes)
{
...
}
}
public class StructureMapControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
try
{
var controllerType = base.GetControllerType(requestContext, controllerName);
return ObjectFactory.GetInstance(controllerType) as IController;
}
catch (Exception e)
{
return base.CreateController(requestContext, controllerName);
}
}
}
Я также должен иметь возможность получить экземпляр в контексте данных в моем атрибуте аннотации данных, сказав:
var context = ObjectFactory.GetInstance<IDataContext>();
Мне определенно кажется, что в синтаксисе это выглядит намного легче. Однако, когда я запускаю свое приложение, оно не работает.
Мне было интересно следующее:
- Является ли мой шаблон правильным.
- Какой контейнер IoC является лучшим и простым в использовании. Если NInject, то я делаю это правильно, а если StructureMap, то как я могу исправить полученную ошибку.
Я знаю, что это много, но я был бы очень признателен, если бы кто-то мог помочь. Спасибо.