IoC and dataContext disposing in asp.net mvc 2 application - asp.net

I have the Global.asax like the code below:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
// ....
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(typeof(IOCControllerFactory));
}
}
public class IOCControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public IOCControllerFactory()
{
kernel = new StandardKernel(new NanocrmContainer());
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
var controller = kernel.TryGet(controllerType) as IController;
if (controller == null)
return base.GetControllerInstance(requestContext, controllerType);
var standartController = controller as Controller;
if (standartController is IIoCController)
((IIoCController)standartController).SetIoc(kernel);
return standartController;
}
class NanocrmContainer : Ninject.Modules.NinjectModule
{
public override void Load()
{
// ...
Bind<DomainModel.Entities.db>().ToSelf().InRequestScope().WithConstructorArgument("connection", "Data Source=lims;Initial Catalog=nanocrm;Persist Security Info=True;User ID=***;Password=***");
}
}
}
In this case if somewhere it is the class, defined like:
public class UserRepository : IUserRepository
{
private db dataContext;
private IUserGroupRepository userGroupRepository;
public UserRepository(db dataContext, IUserGroupRepository userGroupRepository)
{
this.dataContext = dataContext;
this.userGroupRepository = userGroupRepository;
}
}
then the dataContext instance is created (if no one was created in this request scope) by Ninject.
So the trouble now is - where to invoke dataContext method .Dispose()?
UPD:
so i followed the advice from KeeperOfTheSoul and solved the issue in such way:
public override void ReleaseController(IController controller)
{
base.ReleaseController(controller);
var db = kernel.Get<DomainModel.Entities.db>();
db.Dispose();
}

A good place to handle this is in IControllerFactory.ReleaseController, eg
public override void ReleaseController() {
base.ReleaseController();
//Do whatever you need to clean up the IoC container here
}
In NInject this could be handled by scoping using an activation block, at the start of the request when creating the controller you can store the activation block in the HttpContext's current items, during ReleaseController you can retrieve the previously created activation block and dispose it.
You could also consider using InScope and having the custom scope implement INotifyWhenDisposed. After that the usage is the same as with an activation block, except now you store the scope in the HttpContext's current items.

A pattern that is sometimes used to dispose db connections is to call Dispose from the finaliser.
public class db : IDisposable {
//called by the garbage collector
~db() {
//Call dispose to make sure the resources are cleaned up
Dispose(false);
}
//IDisposable implementation
public void Dispose() {
Dispose(true);
}
//subclasses of db can override Dispose(bool) and clean up their own fields
protected virtual void Dispose (bool disposing) {
if (disposing) {
//Supress finalization as all resources are released by this method
//Calling Dispose on IDisposable members should be done here
GC.SupressFinalize();
}
//Clean up unmanaged resources
//Do not call other objects as they might be already collected if called from the finalizer
}
}

You could hook it into Application_EndRequest.

Related

Asp.NET MVC Autofac Inject Dependence non-controller class

All classes that inherit from controller have already inserted the dependencies, but I do not know how to inject those who do not inherit from contoller.
in the example below the SendEmailAndLog() method waits for the ILoggerService interface to be injected. but I do not know how to do this.
public async Task Execute(IJobExecutionContext context)
{
SendEmailHelper sendEmailHelper = new SendEmailHelper();
await sendEmailHelper.SendEmailAndLog(user, "Task", user.UserName, UserManager, loggerService);
}
this task is called the method Application_Start() on Global.asax.cs
I created a constructor to receive this service as a parameter, this is working for the methods within the controllers that call the Class Emailservice. However there are classes that do not inherit from controller so I do not know how to inject.
My Service is:
public interface ILoggerService
{
void Error(ExceptionLogger exception);
void SaveLog();
}
public class LoggerService : ILoggerService
{
private readonly ILoggerRepository loggerRepository;
private readonly IUnitOfWork unitOfWork;
public LoggerService(ILoggerRepository loggerRepository, IUnitOfWork unitOfWork)
{
this.loggerRepository = loggerRepository;
this.unitOfWork = unitOfWork;
}
public void Error(ExceptionLogger exception)
{
loggerRepository.Error(exception);
}
public void SaveLog()
{
unitOfWork.Commit();
}
}

Unity.Webforms dbcontext per request

I am implementing dependency injection using Unity and the Unity.Webforms bootstrapper. I have a DbFactory in my webforms application which initializes my DbContext, and I am wanting to create one instance of this factory per web request, so that my various services will update under the same unit of work.
My question is, does the Unity.Webforms bootstrapper take care of this for me? I believe the answer in this post is suggesting doing the following in order accomplish a single context per request.
container.RegisterType<IDbFactory,DbFactory>(new HierarchicalLifetimeManager());
Is this correct, and is it all I need to do? I'm worried that it is creating a single context per request, but that it is an application wide context (all users sharing the same context).
This probably isn't necessary, but just in case, here is the implementation code for my DbFactory.
public class DbFactory : Disposable, IDbFactory
{
MyDbContext dbContext;
public MyDbContext Init()
{
return dbContext ?? (dbContext = new MyDbContext());
}
protected override void DisposeCore()
{
if(dbContext != null)
{
dbContext.Dispose();
}
}
}
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore(){}
}

Unity injection into asp.net web api controllers and filters

I have WebForms project, and there I have WebApi controller.
How I can inject to controller constructor and to action filter constructor?
I have implemented IDependencyResolver and use it in Global.asax (GlobalConfiguration.Configuration.DependencyResolver), but it doesn't help:
on request controller says that there is no default constructor and filter on application start says that it does not contain a constructor that takes 0 arguments.
Moreover, i need singletone injection to action filter.
Thanks.
UPD
public class ScopeContainer : IDependencyScope
{
protected readonly IUnityContainer _container;
public ScopeContainer(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.ResolveAll(serviceType) : new List<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
public class IoCContainer : ScopeContainer, IDependencyResolver
{
public IoCContainer(IUnityContainer container) : base(container)
{
}
public IDependencyScope BeginScope()
{
var child = _container.CreateChildContainer();
return new ScopeContainer(child);
}
}
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
ConfigureApi(GlobalConfiguration.Configuration);
}
void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterInstance<ILogger>(new Logger());
unity.RegisterType<IRepository, DbRepository>();
config.DependencyResolver = new IoCContainer(unity);
}
private static void RegisterRoutes()
{
RouteTable.Routes.MapHttpRoute("ServiceApi", "api/{controller}/{action}");
}
}
I think this may be the way you are registering your routes.
WebApi routes are registered in the default project examples via the GlobalConfiguration.Routes rather than the RouteTable.Routes which is used by MVC controllers. If the ApiController is being incorrectly loaded by the MVC routing method it won't find your dependency resolver.
Try modifying your code to this:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(GlobalConfiguration.Configuration);
ConfigureApi(GlobalConfiguration.Configuration);
}
void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterInstance<ILogger>(new Logger());
unity.RegisterType<IRepository, DbRepository>();
config.DependencyResolver = new IoCContainer(unity);
}
private static void RegisterRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute("ServiceApi", "api/{controller}/{action}");
}
}
I was having the same issue, I was working on a project trying to help modernize an old web forms project by converting page by page to Web API / Angular and getting the plumbing just right to use Unity was key.
When I was tracing I noticed unity was trying to resolve the controller classes but not the types to inject into their constructors, so I registered my controllers and it all worked. See my example below
Config setup, register controller and dependency
void ConfigureApi(HttpConfiguration config)
{
var container = UnitySingleton.UnityContainer;
container.RegisterType<IDashboardManager, ExampleStuff>();
container.RegisterType<DashboardController>(new InjectionConstructor(container.Resolve<IDashboardManager>()));
config.DependencyResolver = new UnityIoCContainer(container);
}
And my controller example:
public class DashboardController : ApiController
{
private readonly IDashboardManager _dashboardManager;
public DashboardController(IDashboardManager dashboardManager)
{
_dashboardManager = dashboardManager;
}
public async Task<IEnumerable<string>> Get()
{
return await _dashboardManager.GetDatas();
}
}
This is how I got mine working. It was a little different than the article above.

What are best practices for managing DataContext?

In an effort to make my entities persistent ignorant and make my repositories testable, I've implemented a repository pattern like so:
public interface IJobRepository : IRepository<Job>
{
Job GetJobById(int jobId); //Special case where I'm eager loading other entities
void SaveJob(Job job, Job originalJob);
}
public class JobRepository : IJobRepository
{
private readonly IContext _context;
public JobRepository()
{
_context = new CustomObjectContext();
}
public JobRepository(UnitOfWork unitOfWork)
{
_context = unitOfWork.Context;
}
//Basic GetAll, GetById, Add and Delete methods from IRepository<T> Interface here
//omitted for brevity
public Job GetJobById(int jobId)
{
var job = _context.Jobs.Include("Company").Include("Location").
Include("PlantInfo").Where(j => j.Jobid == jobId).SingleOrDefault();
_context.DisposeContext();
return job;
}
public void SaveJob(Job job, Job originalJob)
{
if (job.Jobid > 0)
{
// Update
_context.Jobs.Attach(originalJob);
_context.PlantInfoes.Attach(originalJob.PlantInfo);
_context.Jobs.ApplyCurrentValues(job);
_context.PlantInfoes.ApplyCurrentValues(job.PlantInfo);
Note: ApplyCurrentValues is an extension method I'm using on the ObjectSet
}
else
{
// Create
_context.Jobs.AddObject(job);
}
_context.Save();
}
}
public class UnitOfWork
{
private readonly IContext _context;
public UnitOfWork()
{
_context = new CustomObjectContext();
}
public UnitOfWork(IContext context)
{
_context = context;
}
public string Save()
{
return _context.Save();
}
internal IContext Context
{
get { return _context; }
}
}
public interface IContext
{
IObjectSet<Job> Jobs { get; }
IObjectSet<Company> Companies { get; }
IObjectSet<Location> Locations { get; }
IObjectSet<PlantInfo> PlantInfoes { get; }
string Save();
}
My ObjectContext inherits from IContext...So my understanding is that I will only use the overloaded constructor on the repository to facilitate unit tests or to use it in the case that I want to use the same context (not desirable based on this post I found on SO "Entity Framework and Connection Pooling" -- Is this right?
Also, assuming the context only gets disposed when the repository is garbage collected, I have to dispose the context explicitly to avoid the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker." exception when attaching the entity prior to a save.
That said, what is the best practice for managing the DataContext in a manner that keeps your entities persistent ignorant and repositories testable?
Note: This is an asp.net webapplication; UnitOfWork and IContext implementation was based on examples from "Programming Entity Framework", Second Edition by Julia Lerman Ch24.
Thanks in advance!
Firstly, I would ensure that whatever my "consumable" object is (either repository or unit of work, depending on your setup) implements IDisposable. When your consumbed object is disposed of, then you would dispose your underlying context.
For instance, if you're using your UnitOfWork as the consumable object (the one that gets created and called in your application), it would look something like:
public class UnitOfWork : IDisposable
{
// All the other stuff you had before plus:
public void Dispose ()
{
if (_context != null)
{
_context.Dispose ();
}
}
}
(Note: This can also be done on your repositories if they're the ones being consumed directly)
And then, you have a few options in your application. If you are going to use the UnitOfWork directly, you can use it like:
public void SomeMethodThatAccessesYourData ()
{
using (var unitOfWork = new UnitOfWork (/*Load in the context*/))
{
// Access your data here.
}
}
Or, in your Web Forms or MVC object you can use constructor injection and dispose of it when the Web Forms or MVC object is disposed of:
// If you're using MVC:
public class MyController : Controller
{
private UnitOfWork _unitOfWork;
public MyController (UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public override Dispose (bool Disposing)
{
if (Disposing && _unitOfWork != null)
{
_unitOfWork.Dispose ();
}
}
}
The same idea stands for a web forms Page.
The main reason for using the constructor overload is for Inversion of Control (IOC). It helps with both unit testing and with production code when used with an IoC Container. WebForms doesn't lend itself well to IoC, but it is really easy with MVC.
Edit
I don't really see the connection with your repositories and the unit of work. Usually you access the repositories from a unit of work or, in other implementations, you request a unit of work from your target repository. In your implementation (which I understand is not your own) there seems to be no need for both.
Edit 2
If the UoW is overkill for your application, and you know you can use IoC to inject your IContext, and you don't have very many repositories, you can do something like:
public IRepository<T> : IDisposable { }
public IJobRepository : IRepository<Job> { /* All the stuff you put here */ }
public JobRepository : IJobRepository
{
private IContext _context;
...
public void Dispose ()
{
if (_context != null)
{
_context.Dispose ();
}
}
public JobRepository (IContext context)
{
_context = context;
}
}
Then, how you use it depends on your specific task. I'm not a fan of this direct use of IRepository, but this answer is getting too long.

Physical path to application in global.asax

Guys, is it possible to get physical path to asp.net mvc 2 application inside Global.asax methods?
UPD: sorry, i forget to say, that I need to get that path in Ninject IoC container configuration.
This is a sketch of what i'm having now:
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(typeof(IOCControllerFactory));
}
}
public class IOCControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public IOCControllerFactory()
{
kernel = new StandardKernel(new NanocrmContainer());
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
var controller = kernel.TryGet(controllerType) as IController;
if (controller == null)
return base.GetControllerInstance(requestContext, controllerType);
var standartController = controller as Controller;
return standartController;
}
class NanocrmContainer : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IFileService>().To<BusinessLogic.Services.FileService>().InRequestScope().WithConstructorArgument("temp", "Temp").WithConstructorArgument("docs", "Documents"); // Temp and Documents should be replaced with corresponding paths
}
}
}
You're looking for the HttpRuntime.AppDomainAppPath property.

Resources