New MVC 4 web application using autofac 3.0 on IIS 7.5. How do I inject a dependency into an IHttpModule?
I tried constructor injection which resulted in:
Constructor on type 'AnonymousIdentityModule' not found
So it seems the internals require a parameterless constructor for http modules. I also tried property injection too but that resulted in no dependency actually being injected.
Registration
builder.RegisterType<AnonymousIdentityModule>().As<IHttpModule>().PropertiesAutowired().InstancePerHttpRequest();
IHttpModule Code
public class AnonymousIdentityModule : IHttpModule
{
private readonly IServiceManager _serviceManager;
// this causes "constructor not found" exception
public AnonymousIdentityModule(IServiceManager serviceManager)
{
_serviceManager = serviceManager;
}
// never assigned by autofac
public IServiceManager ServiceManager
{
get { return _serviceManager; }
set { _serviceManager = value; }
}
...
}
web.config
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules>
<add name="AnonymousIdentityModule" type="AnonymousIdentityModule" />
</modules>
</system.webServer>
I found this old article related to Windsor but did not see an equivalent in autofac.
Check out this SO question: IoC Dependency injection into Custom HTTP Module - how? (ASP.NET)
and this post by Phil Haack: http://haacked.com/archive/2011/06/02/dependency-injection-with-asp-net-httpmodules.aspx
They both talk about providing DI to HttpModules by creating another HttpModule to initialize them. And PH has provided a nuget package of his HttpModuleMagic if you want it:
PM> Install-Package HttpModuleMagic
But because HttpModules are only created once they are a kind of singleton, and your dependency also has to be a singleton (or rather, a single instance).
So, if you need a per-request dependency, check out this post: http://blog.sapiensworks.com/post/2013/03/18/Http-Module-Dependecy-Injection-with-Autofac-Gotcha.aspx
This looks at using a Factory function to retrieve a properly scoped dependency when needed.
Related
Is there a way to map all my repository objects to its interfaces in a single line. I donĀ“t want to repeat my self in declarations like these:
services.AddScoped<Repository.Interfaces.IModeloRepository, Repository.ModeloRepository>();
services.AddScoped<Repository.Interfaces.IMunicipioRepository, Repository.MunicipioRepository>();
services.AddScoped<Repository.Interfaces.IPeriodoRepository, Repository.PeriodoRepository>();
services.AddScoped<Repository.Interfaces.IPlanRepository, Repository.PlanRepository>();
Here is a declaration of one of these repositories:
public interface IChatRepository : IRepository<Models.Chat>
I already tried something like this:
services.AddScoped(typeof(Repository.Common.IRepository<>), typeof(Repository.Common.BaseRepository<>));
But gets the following error:
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An unhandled exception has occurred: Unable to resolve service for type 'SqlExpress.Repository.Interfaces.IChatRepository' while attempting to activate 'SqlExpress.Helpers.LessonTagHelper'.
System.InvalidOperationException: Unable to resolve service for type 'SqlExpress.Repository.Interfaces.IChatRepository' while attempting to activate '
SqlExpress.Helpers.LessonTagHelper'.
at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
Unfortunately, the built in DI container in ASP.NET Core is relatively simplistic. If you would like to use more advanced features like these, then you will need to use a different container.
The example below uses StructureMap as that's what I'm familiar with, but it is probably also possible with Autofac, Ninject etc.
Add the StructureMap library to project.json
"StructureMap.Dnx": "0.5.1-rc2-final"
Configure the DI container to use StructureMap, with naming conventions:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc().AddControllersAsServices();
// other service configuration
// Create a new StructureMap container
var container = new Container();
container.Configure(config =>
{
//add all the services that are already configured
config.Populate(services);
config.Scan(_ =>
{
_.WithDefaultConventions();
_.AssemblyContainingType<Startup>();
_.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});
});
//set ASP.NET Core to use the StructureMap container to build types
return container.GetInstance<IServiceProvider>();
}
It is worth checking our the documentation to see exactly how this works, but the default convention is to automatically register interface types such as IMyInterestingType with their implementation called MyInterestingType.
By using ConnectImplementationsToTypesClosing, each IRepository<> should also be registered to it's implementation.
Since NServiceBus internally uses autofac, should I register my bindings through nservicebus or should I just install AutoFac as usual with modules and bindings? If so, since I have a windows service project, where do I initiate the autofac setup? In my EndPointConfig.cs?
Note that this is for my own bindings, not IBus which registers itself automagically.
With all the containers available, there will be an overload in the endpoint config to pass in an instance of the container which should be loaded with all your stuff. From there, NSB will add in its internal stuff and everything will be available to you.
Configure.With().AutofacBuilder(builder)...
I have a separate class which implements INeedInitialization. In it's Init method I configure the DI.
For example:
using NServiceBus;
using NServiceBus.Config;
public class DependencyInjection : INeedInitialization
{
public void Init()
{
Configure.Instance.Configurer.RegisterSingleton<ISomeInterface>(
new SomeClassImplementingInterface());
}
}
I am migrating a project that was developed using WebApi Preview 5 (when it was part of WCF) to the final release of WebApi (part of MVC4). There is a document describing the process but it is extremely simplistic and doesn't cover most of the issues.
Now one of the issues I am facing is that a GlobalErrorHandler was created by inheriting from HttpErrorHandler and then overriding OnTryProvideResponse and that was used to hook error handling with Elmah. Now that was registered on AppStart with a line like this:
var configuration = new WebApiConfiguration();
//some other configuration for security and CreateInstance
configuration.ErrorHandlers =
(handlers, endpoint, description) => handlers.Add(new GlobalErrorHandler())
};
//then some registration
RouteTable.Routes.MapServiceRoute<SomeObject>("routeName", configuration);
and then mapping different route to this configuration. All this code doesn't work in the new world of MVC4 WebApi, it seems like there is a conflict between HttpErrorHandler and it can't even implement its members properly.
Now I've seen general posts about how to register Elmah with WebApi but I am trying to stick to the original code as much as possible and I am assuming - may be I am wrong - that there is a direct equivalent to what Microsoft had in the Preview version and what they released in the final one. So my questions:
What is the equivalent of this Global Error handling registation in ASP.NET MVC4 WebApi?
Do I need to do the configuration the same way it is done here (default webapi samples project doesn't seem to have similar code)
What is the equivalent of that route registration line of code: RouteTable.Routes.MapServiceRoute("routeName", configuration);
If you create a quick one-off WebApi MVC project in Visual Studio you will see an App_Start folder which contains some classes which have static methods for handling the registration, specifically:
FilterConfig.cs
WebApiConfig.cs
WebApi Config is where you need to register routes etc...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Filter config is what you need to handle your global errors... Filter config has a default error handler attribute added which you can swap out or out
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
Global.asax calls these static registration scripts like so:
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
In regard to Elmah it appears simplying including the Nuget package will register it...
Look for the package Elmah.Mvc
PM> Install-Package Elmah.MVC
it used to be like this How to get ELMAH to work with ASP.NET MVC [HandleError] attribute? but now according to this blog it has changed:
HandleErrorAttribute inside If you tried to use ELMAH in ASP.NET MVC,
you are probably implemented your own HandleErrorAttribute, as it's
shown in this example. You no longer need to apply this custom code
with Elmah.MVC. As soon you installed package, so can safely remove
your HandleError attribute, since it's already included into package.
This now appears to register itself in the Web.Config as a managedHandler so your code does not need to reference Elmah directly.
My current setup is using Ninject for simple IoC, everything goes fine, but I'm not able to resolve one of the classes I need inside my AuthorizeAttribute. I need to access a class that does ClaimsVerification:
Here's my code:
IoC Config:
var kernel = new StandardKernel(); // Ninject IoC
// These registrations are "per instance request".
// See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/
kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()
.InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<ISmartDocumentorUow>().To<SmartDocumentorUow>();
kernel.Bind<IClaimsVerification>().To<ClaimsVerification>();
// kernel
//kernel.BindFilter<MyAuthorizeAttribute>(FilterScope.Controller, 0).WhenControllerHas<RequireRolesAttribute>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
MyAuthorizeAttribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
[Inject]
IClaimsVerification clamisverify { get; set; }
public MyAuthorizeAttribute()
{
//var x = System.Web.Mvc.DependencyResolver.Current.(typeof(IClaimsVerification));
}
Yap, sorry, the problem was injecting the iClaimsverification that isn't working in web api..
I tryed with the public property and still it didn't work.
the bindfilter is commented out, because it doesn't exist in the core NInject api (dll), it does exists in the MVC dll of ninject but it works for Action filters in the web mvc, and not in the api mvc for what i can tell..
i do solved the issue like this, though i don't like a lot of this fix:
private IClaimsVerification verifier
{
get
{
return (GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IClaimsVerification)) as IClaimsVerification);
}
}
The property you have marked with Inject is private - you need to initialize Ninject with a custom configuration to opt into what would be a much less efficient process
(You didnt state the problem in your question. I see you were trying BindFilter, but it's commented out (why?) - this is the correct approach. I recommend reading the Ninject.MVC3 wiki article on BindFilter for an example)
I want to configure Dependency Injection with Ninject in my application, and my project is a Subscriber class library. What is the first event produced by NserviceBus for initialize my kernel and modules bindings?
What you need to do is in NServiceBus.Host.exe.config define your EndpointConfigurationType
<appSettings>
<add key="EndpointConfigurationType" value="<Assembly>", <Namespace>"/>
</appSettings>
After this define a class
public class EndpointConfiguration : AsA_Server, IWantCustomInitialization, IConfigureThisEndpoint
{
public void Init()
{
/do Ninject stuff here
}
}
Hope this makes sense. Let me know if you need more clarification. Good luck.