У меня есть веб-приложение MVC 3, в котором я использую Entity Framework для доступа к данным. Кроме того, я просто использовал шаблон репозитория, где, например, все, что связано с продуктом, обрабатывается в "ProductRepository" и все, что связано с пользователем, обрабатывается в "UserRepository".
Таким образом, я использую контейнер UNITY, чтобы создать одноэлементный экземпляр DataContext, который я вставляю в каждый из репозиториев. Быстрый поиск в Google, и все рекомендуют НЕ использовать одноэлементный экземпляр DataContext, так как это может привести к некоторым утечкам памяти в будущем.
Итак, вдохновленный этим сообщением, создание одноэлементного экземпляра DataContext для каждого веб-запроса является ответом (пожалуйста, поправьте меня, если я ошибаюсь!)
Однако UNITY не поддерживает диспетчер времени жизни «для веб-запросов». Но можно реализовать свой собственный диспетчер времени жизни, который сделает это за вас. Фактически, это обсуждается в этой публикации:
Контекст синглтона на вызов (веб-запрос) в Unity
Вопрос в том, что теперь я реализовал настраиваемый менеджер времени жизни, как описано в вышеупомянутом сообщении, но я не уверен, что это способ сделать это. Мне также интересно, где находится экземпляр datacontext в предоставленном решении? Я что-то упускаю?
Есть ли на самом деле лучший способ решить мою «проблему»?
Спасибо!
Ниже приведены фрагменты из моего Global. asax, Контроллер и Репозиторий. Это дает четкое представление о моей реализации.
Global.asax
var container = new UnityContainer();
container
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new PerResolveLifetimeManager(), dbConnectionString)
Контроллер
private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;
public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
_productsRepository = productsRepository;
_categoryRepository = categoryRepository;
}
public ActionResult Index()
{
ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
.
.
.
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_productsRepository.Dispose();
_categoryRepository.Dispose();
}
Репозиторий продукта
public class ProductsRepository : IDisposable
{
private MyEntities _db;
public ProductsRepository(MyEntities db)
{
_db = db;
}
public Product GetProduct(Guid productId)
{
return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}
public void Dispose()
{
this._db.Dispose();
}
Завод контроллера
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
"or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
return _container.Resolve(controllerType) as IController;
}
}
Дополнительная информация Я реализовал собственный менеджер времени жизни, как описано в сообщении выше, но я не уверен, что это способ сделать это. Мне также интересно, где находится экземпляр datacontext в предоставленном решении? Я что-то упускаю?
Есть ли на самом деле лучший способ решить мою «проблему»?
Спасибо!
Ниже приведены фрагменты из моего Global. asax, Контроллер и Репозиторий. Это дает четкое представление о моей реализации.
Global.asax
var container = new UnityContainer();
container
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new PerResolveLifetimeManager(), dbConnectionString)
Контроллер
private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;
public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
_productsRepository = productsRepository;
_categoryRepository = categoryRepository;
}
public ActionResult Index()
{
ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
.
.
.
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_productsRepository.Dispose();
_categoryRepository.Dispose();
}
Репозиторий продукта
public class ProductsRepository : IDisposable
{
private MyEntities _db;
public ProductsRepository(MyEntities db)
{
_db = db;
}
public Product GetProduct(Guid productId)
{
return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}
public void Dispose()
{
this._db.Dispose();
}
Завод контроллера
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
"or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
return _container.Resolve(controllerType) as IController;
}
}
Дополнительная информация Я реализовал собственный менеджер времени жизни, как описано в сообщении выше, но я не уверен, что это способ сделать это. Мне также интересно, где находится экземпляр datacontext в предоставленном решении? Я что-то упускаю?
Есть ли на самом деле лучший способ решить мою «проблему»?
Спасибо!
Ниже приведены фрагменты из моего Global. asax, Контроллер и Репозиторий. Это дает четкое представление о моей реализации.
Global.asax
var container = new UnityContainer();
container
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new PerResolveLifetimeManager(), dbConnectionString)
Контроллер
private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;
public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
_productsRepository = productsRepository;
_categoryRepository = categoryRepository;
}
public ActionResult Index()
{
ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
.
.
.
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_productsRepository.Dispose();
_categoryRepository.Dispose();
}
Репозиторий продукта
public class ProductsRepository : IDisposable
{
private MyEntities _db;
public ProductsRepository(MyEntities db)
{
_db = db;
}
public Product GetProduct(Guid productId)
{
return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}
public void Dispose()
{
this._db.Dispose();
}
Завод контроллера
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
"or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
return _container.Resolve(controllerType) as IController;
}
}
Дополнительная информация Мне также интересно, где находится экземпляр datacontext в предоставленном решении? Я что-то упускаю?
Есть ли на самом деле лучший способ решить мою «проблему»?
Спасибо!
Ниже приведены фрагменты из моего Global. asax, Контроллер и Репозиторий. Это дает четкое представление о моей реализации.
Global.asax
var container = new UnityContainer();
container
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new PerResolveLifetimeManager(), dbConnectionString)
Контроллер
private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;
public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
_productsRepository = productsRepository;
_categoryRepository = categoryRepository;
}
public ActionResult Index()
{
ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
.
.
.
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_productsRepository.Dispose();
_categoryRepository.Dispose();
}
Репозиторий продукта
public class ProductsRepository : IDisposable
{
private MyEntities _db;
public ProductsRepository(MyEntities db)
{
_db = db;
}
public Product GetProduct(Guid productId)
{
return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}
public void Dispose()
{
this._db.Dispose();
}
Завод контроллера
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
"or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
return _container.Resolve(controllerType) as IController;
}
}
Дополнительная информация Мне также интересно, где находится экземпляр datacontext в предоставленном решении? Я что-то упускаю?
Есть ли на самом деле лучший способ решить мою «проблему»?
Спасибо!
Ниже приведены фрагменты из моего Global. asax, Контроллер и Репозиторий. Это дает четкое представление о моей реализации.
Global.asax
var container = new UnityContainer();
container
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new ContainerControlledLifetimeManager())
.RegisterType(new PerResolveLifetimeManager(), dbConnectionString)
Контроллер
private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;
public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
_productsRepository = productsRepository;
_categoryRepository = categoryRepository;
}
public ActionResult Index()
{
ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
.
.
.
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_productsRepository.Dispose();
_categoryRepository.Dispose();
}
Репозиторий продукта
public class ProductsRepository : IDisposable
{
private MyEntities _db;
public ProductsRepository(MyEntities db)
{
_db = db;
}
public Product GetProduct(Guid productId)
{
return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}
public void Dispose()
{
this._db.Dispose();
}
Завод контроллера
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
"or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
return _container.Resolve(controllerType) as IController;
}
}
Дополнительная информация Я думаю, что это проблема Rails 3, но это может быть проблема Flex / AIR. Приложение Rails использует ...
У меня есть REST API в Rails 3, к которому иногда обращаются из приложения AIR, а иногда из браузера.
Я думаю , что это проблема Rails 3, но она может быть проблемой Flex / AIR.
Приложение Rails использует omniauth для аутентификации, cancan для авторизации и active_record_store. Я использую модель сеанса для хранения идентификаторов пользователя.
(Я не использую сеансы файлов cookie по той причине, что они связаны с AIR для Android, OAuth и StageWebView.)
Я использую Чарльз для мониторинга HTTP-трафика.
Большинство запросов работают нормально. Браузер (или клиент AIR) отправляет идентификатор сеанса на сервер, используя HTTP-заголовок Cookie, например:
_session_id=950dee7eca6732aa62b5f91876f66d15
И Rails находит сеанс, выясняет, кто пользователь, и делает свое дело.
Но при определенных обстоятельствах Rails генерирует новый сеанс перед отправкой ответа. Он добавляет сеанс в таблицу сеансов и возвращает клиенту заголовок Set-Cookie с новым идентификатором сеанса. Примерно так:
_session_id=e1489a6b610c0a1d13cec1454228ae47; path=/; HttpOnly
Обстоятельства, при которых это происходит:
Это, очевидно, проблема, потому что на последующем запросов, Rails не может найти информацию о пользователе. Он создал новый сеанс без этой информации.
Итак, я смотрю на заголовки HTTP для запроса POST. Вот копия / вставка от Чарльза; Я вставил двоеточие после имени заголовка, чтобы его можно было прочитать.
Host: localhost.seti.hg94.com:3000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/531.9 (KHTML, like Gecko) AdobeAIR/2.6
Referer: app:/AndroidApplication.swf
X-Flash-Version: 10,2,152,22
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Cookie: _session_id=950dee7eca6732aa62b5f91876f66d15
Content-Length: 84
Connection: keep-alive
Есть ли у кого-нибудь какое-нибудь представление о том, почему Rails генерирует новый сеанс в таких обстоятельствах? Похоже, что это происходит после моего кода контроллера, поскольку у меня есть правильная информация о сеансе в контроллере.
Я занят, пытаясь изолировать проблему дальше, контролирую заголовки из AIR и скоро. Работаю над этим багом почти неделю. Поэтому мы будем очень благодарны за любую информацию или предложения от сообщества.