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.
Related
I'm using Structure Map for DI in ASP.net MVC and calling actions from angularjs service but the constructor is not getting called to which I have injected dependency while parameter less constructor is getting called.
It is not giving any error.
I have configured it for the first time in the project.
Code:-
public class StructureMapControllerFactory : DefaultControllerFactory
{
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controllerType = base.GetControllerType(requestContext, controllerName);
return controllerType == null ? null : ObjectFactory.GetInstance(controllerType) as IController;
}
}
public class SiteConfig
{
public static void BootStrap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<fullpath.BusinessRegistry>();
});
//Controller Factory
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
}
In Application_Start() called BootStrap() method.
public BusinessRegistry()
{
For<IDemoBL>().Use<DemoBL>();
}
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.
I am always getting the error
No parameterless constructor defined for this object.
when I execute the codes below.
It must be something to do with my ninject modules.
What seems to be the problem here?
Controller
public class AccountController : Controller
{
private readonly IUserService _service;
public AccountController(IUserService service)
{
_service = service;
}
}
Service Layer
public class UserService : ServiceBase<User>, IUserService
{
public UserService(IRepository repository) : base(repository)
{
}
}
public interface IUserService : IService<User>
{
}
Repository
public class UserRepository : RepositoryBase<User>, IUserRepository
{
}
public interface IUserRepository : IRepository<User>
{
}
Ninject ----
ServiceModule
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IUserService>().To<UserService>();
}
}
RepositoryModule
public class RepositoryModule : NinjectModule
{
public override void Load()
{
Bind<IUserRepository>().To<UserRepository>();
}
}
Setup
public static void SetupDependencyInjection()
{
// Create Ninject DI kernel
var kernel = CreateKernel();
// Tell ASP.NET MVC 3 to use our Ninject DI Container
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
private static IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule(),
new RepositoryModule()
};
return new StandardKernel(modules);
}
Have have registered:
Bind<IUserRepository>().To<UserRepository>();
But you are referring to the base IRepository interface in UserService:
public UserService(IRepository repository) : base(repository)
{
}
So Ninject won't know how to construct a generic IRepository. You need to Bind a implementation for IRepository. Or use IUserRepository in UserService:
public UserService(IUserRepository repository) : base(repository)
{
}
There are plenty of examples for having it worked on an MVC application. How is it done on Web Forms?
Here are the steps to use Ninject with WebForms.
Step1 - Downloads
There are two downloads required - Ninject-2.0.0.0-release-net-3.5 and the WebForm extensions Ninject.Web_1.0.0.0_With.log4net (there is an NLog alternative).
The following files need to be referenced in the web application: Ninject.dll, Ninject.Web.dll, Ninject.Extensions.Logging.dll and Ninject.Extensions.Logging.Log4net.dll.
Step 2 - Global.asax
The Global class needs to derive from Ninject.Web.NinjectHttpApplication and implement CreateKernel(), which creates the container:
using Ninject; using Ninject.Web;
namespace Company.Web {
public class Global : NinjectHttpApplication
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel(new YourWebModule());
return kernel;
}
The StandardKernel constructor takes a Module.
Step 3 - Module
The Module, in this case YourWebModule, defines all the bindings the web application will need:
using Ninject;
using Ninject.Web;
namespace Company.Web
{
public class YourWebModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>();
}
In this example, wherever the ICustomerRepository interface is referenced the concrete CustomerRepository will be used.
Step 4 - Pages
Once that's done each page needs to inherit from Ninject.Web.PageBase:
using Ninject;
using Ninject.Web;
namespace Company.Web
{
public partial class Default : PageBase
{
[Inject]
public ICustomerRepository CustomerRepo { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
Customer customer = CustomerRepo.GetCustomerFor(int customerID);
}
The InjectAttribute -[Inject] - tells Ninject to inject ICustomerRepository into the CustomerRepo Property.
If you already have a base page you just need to get your base page to derive from the Ninject.Web.PageBase.
Step 5 - Master Pages
Inevitably, you'll have master pages, and to allow a MasterPage to access injected objects you'll need to derive your master page from Ninject.Web.MasterPageBase:
using Ninject;
using Ninject.Web;
namespace Company.Web
{
public partial class Site : MasterPageBase
{
#region Properties
[Inject]
public IInventoryRepository InventoryRepo { get; set; }
Step 6 - Static Web Service Methods
The next problem was not being able to inject into static methods. We had a few Ajax PageMethods, which are obviously static, so I had to move the methods into a standard web service. Again, the web service needs to derive from a Ninject class - Ninject.Web.WebServiceBase:
using Ninject;
using Ninject.Web;
namespace Company.Web.Services
{
[WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class YourWebService : WebServiceBase
{
#region Properties
[Inject]
public ICountbackRepository CountbackRepo { get; set; }
#endregion
[WebMethod]
public Productivity GetProductivity(int userID)
{
CountbackService _countbackService =
new CountbackService(CountbackRepo, ListRepo, LoggerRepo);
In your JavaScript you'll need to reference the standard service - Company.Web.Services.YourWebService.GetProductivity(user, onSuccess), rather than PageMethods.GetProductivity(user, onSuccess).
The only other problem I found was injecting objects into User Controls. While it's possible to create your own base UserControl with Ninject capabilities, I found it quicker to add a Property to the user control for the required object and setting the Property in the container page. I think supporting UserControls out of the box is on the Ninject "to-do" list.
Adding Ninject is quite simple and it is an eloquent IoC solution. Many people like it because there is no Xml configuration. It has other useful "tricks" such as turning objects into Singletons with just the Ninject syntax - Bind<ILogger>().To<WebLogger>().InSingletonScope(). There is no need to change WebLogger into an actual Singleton implmentation, I like this.
It's gotten easier with the release of Ninject v3.0 (as of 4/12/2012). Injection is implemented via HttpModule so there is no need to have your pages inherit from a custom Page / MasterPage. Here are the steps (and code) for a quick spike.
Create a new ASP.NET WebForms project
Use NuGet to add the Ninject.Web lib (which will also bring down the Ninject.Web.Common and Ninject libs)
Register your custom bindings in App_Start / NinjectWebCommon.cs / RegisterServices method
Use attribute injection on your pages
NinjectWebCommon / RegisterServices
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IAmAModel>().To<Model1>();
}
Default
public partial class _Default : System.Web.UI.Page
{
[Inject]
public IAmAModel Model { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
}
}
Site.Master
public partial class SiteMaster : System.Web.UI.MasterPage
{
[Inject]
public IAmAModel Model { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("From master: "
+ Model.ExecuteOperation());
}
}
Models
public interface IAmAModel
{
string ExecuteOperation();
}
public class Model1 : IAmAModel
{
public string ExecuteOperation()
{
return "I am a model 1";
}
}
public class Model2 : IAmAModel
{
public string ExecuteOperation()
{
return "I am a model 2";
}
}
Results from output window
I am a model 1
From master: I am a model 1
The answer here currently does not work due to a open bug. Here is a modified version of #Jason's steps using a customer httpmodule to inject into pages and controls without needing to inherit from ninject classes.
Create a new ASP.NET WebForms project
Use NuGet to add the Ninject.Web lib
Register your custom bindings in App_Start / NinjectWebCommon.cs / RegisterServices method
Add InjectPageModule and register in NinjectWebCommon
Use attribute injection on your pages
InjectPageModule.cs
public class InjectPageModule : DisposableObject, IHttpModule
{
public InjectPageModule(Func<IKernel> lazyKernel)
{
this.lazyKernel = lazyKernel;
}
public void Init(HttpApplication context)
{
this.lazyKernel().Inject(context);
context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
var currentPage = HttpContext.Current.Handler as Page;
if (currentPage != null)
{
currentPage.InitComplete += OnPageInitComplete;
}
}
private void OnPageInitComplete(object sender, EventArgs e)
{
var currentPage = (Page)sender;
this.lazyKernel().Inject(currentPage);
this.lazyKernel().Inject(currentPage.Master);
foreach (Control c in GetControlTree(currentPage))
{
this.lazyKernel().Inject(c);
}
}
private IEnumerable<Control> GetControlTree(Control root)
{
foreach (Control child in root.Controls)
{
yield return child;
foreach (Control c in GetControlTree(child))
{
yield return c;
}
}
}
private readonly Func<IKernel> lazyKernel;
}
NinjectWebCommon / RegisterServices
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHttpModule>().To<InjectPageModule>();
kernel.Bind<IAmAModel>().To<Model1>();
}
Default
public partial class _Default : System.Web.UI.Page
{
[Inject]
public IAmAModel Model { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
}
}
Site.Master
public partial class SiteMaster : System.Web.UI.MasterPage
{
[Inject]
public IAmAModel Model { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("From master: "
+ Model.ExecuteOperation());
}
}
Models
public interface IAmAModel
{
string ExecuteOperation();
}
public class Model1 : IAmAModel
{
public string ExecuteOperation()
{
return "I am a model 1";
}
}
public class Model2 : IAmAModel
{
public string ExecuteOperation()
{
return "I am a model 2";
}
}
Results from output window
I am a model 1
From master: I am a model 1
I think here are the steps to implement Ninject.Web on ASP.NET Web Forms.
Implement NinjectHttpApplication at Global.asax. For the Kernel, pass it in by implementing NinjectModule.
On each web forms page load event at code behind, implement Ninject.Web.PageBase. Add instance class with [Inject] filter on top of it.
For more detailed example, below are some useful links I found:
1.http://joeandcode.net/post/Ninject-2-with-WebForms-35
2.http://davidhayden.com/blog/dave/archive/2008/06/20/NinjectDependencyInjectionASPNETWebPagesSample.aspx
Check the book "Pro ASP.NET MVC 2 Framework, 2nd Edition" by Steve Sanderson (Apress). The author uses Ninject to connect with a database. I think you can use the examples and adapt them to your needs.
public IGoalsService_CRUD _context { get; set; }
The _context object is being set to null somehow. Following are the rest of the settings
public partial class CreateGoal : Page
{
[Inject]
public IGoalsService_CRUD _context { get; set; }
}
For Global File
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel(new Bindings());
return kernel;
}
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<goalsetterEntities>().To<goalsetterEntities>();
Bind<IGoalsService_CRUD>().To<GoalsService_CRUD>();
}
}
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.