How can I inject dependencies into an ELMAH custom ErrorLog? - c#

I have an ELMAH custom ErrorLog that uses an EF Code-First context to store the errors:-
class EntityFrameworkElmahErrorLog
{
public EntityFrameworkElmahErrorLog(IDictionary config) : this() { }
public override ErrorLogEntry GetError(string id)
{
using (var context = new MyContext())
{
var intId = Int64.Parse(id, CultureInfo.InvariantCulture);
var item = context.ErrorLog.Single(x => x.Id == intId);
return new ErrorLogEntry(this, id, ErrorXml.DecodeString(item.Details));
}
}
// etc.
}
The ErrorLog is wired up in the web.config:-
<errorLog type="MyProject.EntityFrameworkErrorLog, MyProject" />
I'm already using Ninject elsewhere in the project. I'd like to inject MyContext so that the ErrorLog isn't instantiating its own dependency, but I'm not having any luck finding a hook in the documentation. ELMAH appears to be instantiating the ErrorLog internally, so the only option I seem to have is using a ServiceLocator inside my custom ErrorLog, which I'd like to avoid if possible.
Are there any better hooks available in ELMAH that I can use to inject ?

The Service location/Depdency injection extension point in ELMAH is the ServiceCenter.Current property where you can provide a delegate with the following signature:
public delegate IServiceProvider ServiceProviderQueryHandler(object context);
ELMAH will use the System.IServiceProvider returned by the ServiceCenter.Current to resolve the ErrorLog isntances.
So you need to do 3 things to setup it with Ninject (or any DI container)
Create your own System.IServiceProvider implementation with Ninject the IKernel interface already derives from from System.IServiceProvider, so it's done.
You need to register your EntityFrameworkElmahErrorLog in your container as an ErrorLog implemenation, because ELMAH will try to resolve an instance of ErrorLog.
Provide your delegate to ServiceCenter.Current
So you need something like the following in your RegisterServices method:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ErrorLog>().To<EntityFrameworkElmahErrorLog>();
ServiceCenter.Current = (httpContext) => kernel;
}
Note: in in the ServiceProviderQueryHandler delegate you get the current HttpContext and with that you can fine tune how your expediencies are resolved.
You should also note that with this approach you will lose the ability to configure your ErrorLog in your config file.
ELMAH will always use the resolved instance from your container, because the built in ServiceContainer reads the config file what you override with your custom logic.

Related

ReactiveUi: How can I replace the default IViewLocator when using AutoFac?

High!
I am trying to replace the default IViewLocator of ReactiveUi/Splat in WPF. I am using AutoFac as container.
My goal is very simple: ReactiveUi/Splat should use my custom implementation of IViewLocator when resolving a view for view model.
I really read every availabe tutorial and stackoverflow thread, but nothing helped.
Currently I do the following while bootstrapping: (I tried many different things...)
namespace MDM
{
public static class Bootstrapper
{
private static AutofacDependencyResolver? Locator;
private static IContainer? Container;
public static void Register()
{
Splat.Locator.CurrentMutable.InitializeSplat();
Splat.Locator.CurrentMutable.InitializeReactiveUI();
Splat.Locator.CurrentMutable.RegisterConstant<IViewLocator>(new ViewLocator());
var builder = new ContainerBuilder();
builder.RegisterType<MainWindowView>().As<IViewFor<MainWindowViewModel>>().SingleInstance();
builder.RegisterType<EinstellungenView>().As<IViewFor<EinstellungenViewModel>>().SingleInstance();
builder.RegisterType<MainWindowViewModel>().AsSelf().SingleInstance();
builder.RegisterType<EinstellungenViewModel>().AsSelf().SingleInstance();
Locator = builder.UseAutofacDependencyResolver();
builder.RegisterInstance(Locator);
Locator.InitializeReactiveUI();
Splat.Locator.SetLocator(Locator);
Container = builder.Build();
Locator.SetLifetimeScope(Container);
}
public static T Resolve<T>() where T : class
{
return Container!.Resolve<T>();
}
}
}
While debugging the following line of code in my IViewLocator is never hit:
public IViewFor? ResolveView<T>(T viewModel, string? contract = null)
{
}
So my question is: What do I need to do while bootstrapping, to tell ReactiveUi to use my IViewLocator?
If you decide to drop Splat (the IoC container used by ReactiveUI) and use Autofac, then you must go with it, especially when registering services.
Once you have registered a custom IoC container (properly), you shouldn't use Splat anymore to resolve any dependencies. Although Splat will redirect service requests to the Autofac container, I recommend against mixing the APIs.
var containerBuilder = new ContainerBuilder();
// TODO::Register application's dependencies with Autofac
/* Configure Splat to use Autofac */
var autofacResolver = containerBuilder.UseAutofacDependencyResolver();
containerBuilder.RegisterInstance(autofacResolver);
autofacResolver.InitializeReactiveUI();
// AFTER configuring the IoC redirect, register the Splat service overrides
containerBuilder.RegisterType<ViewLocator>()
.As<IViewLocator>()
.SingleInstance();
var container = containerBuilder.Build();
autofacResolver.SetLifetimeScope(container);
Don't use the Service Locator anti-pattern. The IoC container should not be distributed across the application. Neither as injected reference nor as static reference.
Use the Abstract Factory pattern instead.
For this reason, IViewLocator.ResolveView must use factories instead of the static Resolve method that you have implemented in your Bootstrapper.

How to get DbContext in nested methods using Simple Injector

I have a doubt since I'm new to Dependency Injection and IoC.
I have a domain layer (with business logic) and a data layer. We do not implement repositories, we use EF Core directly.
It is a Class Library project, we use it in a ASP.NET CCore Web API, WinForms, and inside another framework.
The idea is to use the same context inside a scope.
The problem is that I'm not being able to get the same context in the nested method execution, I'm sure it is because I did not understand the concept completely, can you guys give me a help on that?
Example:
public class MyTest
{
public void TestContainer()
{
var parentContext = MyContainer.Container.GetInstance<MyContext>();
TestParentAndChildContext(parentContext);
}
private void TestParentAndChildContext(MyContext parentContext)
{
var childContext = MyContainer.Container.GetInstance<MyContext>();
Assert.AreEqual(parentContext, childContext);
}
}
public class MyContainer
{
public static Container Container
{
get { return container ?? (container = RegisterAndVerifyContainer()); }
}
private static Container RegisterAndVerifyContainer()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.Register<DbContext, MyContext>(Lifestyle.Scoped);
container.Verify();
return container;
}
}
In Simple Injector you register an implementation by its abstraction. In your case you registed an MyContext by its DbContext base type. From this point on Simple Injector will know that it will need to construct a MyContext in case someone asks for a DbContext. This is the whole purpose of
Program to an interface, not an implementation
In your case however, although you do register the MyContext by its abstraction, you request a new instance of MyContext directly, instead of requesting it through its abstraction. This causes Simple Injector to look for the MyContext in its list of registered abstractions. Since there is no registration for MyContext (there is for DbContext though, but that's a totally different type what Simple Injector is concerned), Simple Injector will try to add the missing registration. This succeeds because MyContext is concrete and has single resolvable constructor, while you are using Simple Injector v4.x.
By default the older versions of Simple Injector will resolve unregistered concrete types as Transient. This default changed in v5, where it won't create any unregistered concrete type by default.
So MyContext is resolved as transient when requested directly. You can solve this by changing your test to the following:
public void TestContainer()
{
using (MyContainer.Container.BeginExecutionContextScope()) {
var parentContext = MyContainer.Container.GetInstance<DbContext>();
TestParentAndChildContext(parentContext);
}
}
private void TestParentAndChildContext(MyContext parentContext)
{
var childContext = MyContainer.Container.GetInstance<DbContext>();
Assert.AreEqual(parentContext, childContext);
}
Do note that Simple Injector usually detects these kinds of mistakes. In case you register MyContext by its DbContext base type, but inject MyContext directly in a constructor of a type, Simple Injector will throw a Short-Circuited Dependency error when calling Verify().
The reason you didn't get warned about this, is because you've called Verify() before the resolve action (you should typically not call GetInstance from within your application; instead you should build all object graphs up front). But when you'd call Verify (again) after resolving MyContext you would see the exception popping up:
[TestMethod]
public void TestContainer()
{
var container = MyContainer.Container.GetInstance<DbContext>();
var parentContext = container.GetInstance<MyContext>();
var childContext = container.GetInstance<MyContext>();
// This call will fail
container.Verify();
}

Autofac/FluentValidation: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested

Attempting to inject data into a FluentValidation validator:
public class MyFormValidator : AbstractValidator<MyForm>
{
private readonly IQueryable<Models.User> _users;
public MyFormValidator(IQueryable<Models.User> users)
{
_users = users;
...
}
}
My validator factory:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly IContainer container;
public DependencyResolverValidatorFactory(IContainer container)
{
this.container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return container.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
My Autofac configurator:
public class AutofacConfigurator
{
public static void Configure()
{
var builder = new ContainerBuilder();
...
builder.RegisterType<MyFormValidator>()
.Keyed<IValidator>(typeof(IValidator<MyForm>))
.As<IValidator>()
// 2nd parameter returns IQueryable<User>
.WithParameter("users", new SqlRepository<User>(dataContext))
.InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register the validator factory with FluentValidation, and register
// FluentValidation as the model validator provider for the MVC framework.
// see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(container));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
}
}
Getting the following exception:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have other validators, most of which will not need data injected into them.
This is largely new ground for me (in both Autofac and FluentValidation) and am still trying to understand what I am doing here. I suspect I'm simply registering my type incorrectly. How do I fix this and properly register my type?
(My apologies if this is too similar to other questions that were already asked.)
I have zero experience with FluentValidation, but I doubt it's the cause of your issues anyway, so I'll plow forward regardless.
The exception you're getting means that Autofac can't resolve your service as 'instance per request'. There's a lot of documentation as to what this means on the Autofac documentation page. To summarize, it means that Autofac will attempt to resolve the service from a lifetime scope that is automatically created for each request sent to the webserver. When you register something as .InstancePerRequestScope() but then attempt to resolve that service outside of that scope, you'll get the DependencyResolutionException you see.
So we've established that your MyFormValidator isn't being resolved from a 'Request' scope. Why?
The custom DependencyResolverValidatorFactory you've written takes the actual IContainer that was built by Autofac, and resolves from that. This is a special type of ILifetimeScope, the 'root scope'. There's no request lifetime scope directly associated with this, so you get your exception. You need to to resolve from an ILifetimeScope that is began from the 'request' scope, or a sub-scope that is contained within the request scope.
The Autofac/MVC integration already automatically hosts a request scope (within the AutofacDependencyResolver, see the source), but your custom DependencyResolverValidatorFactory doesn't resolve from it. If you want to do that, I suppose you could modify your DependencyResolverValidatorFactory to accept the AutofacDependencyResolver instance instead, and use that to resolve.
It would look something like this:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly AutofacDependencyResolver resolver;
public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
{
this.resolver = resolver;
}
public override IValidator CreateInstance(Type validatorType)
{
return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
Note the RequestLifetimeScope stuck in there.
Then you create this in your .Configure() method using
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(resolver));
That should get rid of the exception, assuming that this factory does indeed have a request to work from when creating instances of IValidators. If not, You might need to register using the default behavior (.InstancePerDependency(), where it creates a new instance every time it's requested) or a singleton (.SingleInstance()), depending on how/if validators can or should be shared.
Good luck.

Simple Injector unable to inject dependencies in Web API controllers

I am attempting to do some basic constructor DI with Simple Injector, and it seems that it is unable to resolve the dependencies for Web API controllers.
I have an API controller in an "API" folder, that is outside the "Controllers" folder.
I have also tried placing it within the "Controllers" folder, but
that did not seem to make much of a difference. The stack trace that
I receive is similar to the one presented in this question.
I am using a fresh install of the "Simple Injector MVC Integration Quick Start" NuGet Package (v. 2.1.0).
I have the base SimpleInjectorWebApiDependencyResolver from the documentation, which is also the same as found here.
I am using Entity Framework, and have looked at the discussion
thread about changes to correctly load the context.
This does not
seem to be a problem, but I still receive the following error:
Type 'MyProject.API.ArticleController' does not have a default
constructor
System.ArgumentException at
System.Linq.Expressions.Expression.New(Type type) at
System.Web.Http.Internal.TypeActivator.Create[TBase](Type
instanceType) at
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage
request, Type controllerType, Func`1& activator) at
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage
request, HttpControllerDescriptor controllerDescriptor, Type
controllerType)
It would be appreciated if someone could offer me some suggestions, on whether anything should be modified from its current state/call order.
ArticleController (basic structure):
public class ArticleController : ApiController
{
private readonly IArticleRepository articleRepository;
private readonly IUserRepository userRepository;
private readonly IReleaseRepository releaseRepository;
public ArticleController(IArticleRepository articleRepository, IUserRepository userRepository, IReleaseRepository releaseRepository)
{
this.articleRepository = articleRepository;
this.userRepository = userRepository;
this.releaseRepository = releaseRepository;
}
// GET api/Article
public IEnumerable<Article> GetArticles(){ // code }
// GET api/Article/5
public Article GetArticle(int id){ // code }
// PUT api/Article/5
public HttpResponseMessage PutArticle(int id, Article article){ // code }
// POST api/Article
public HttpResponseMessage PostArticle(ArticleModel article){ // code }
// DELETE api/Article/5
public HttpResponseMessage DeleteArticle(int id){ // code }
}
SimpleInjectorInitializer:
public static class SimpleInjectorInitializer
{
public static void Initialize()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
container.Register<IArticleRepository, ArticleRepository>();
container.Register<IUserRepository, UserRepository>();
container.Register<IReleaseRepository, ReleaseRepository>();
}
}
Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication
{
private void ConfigureApi()
{
// Create the container as usual.
var container = new Container();
// Verify the container configuration
// container.Verify();
// Register the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ConfigureApi();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
TLTR: the problem is caused by the implicit way Web API handles resolving controller types; register your Web API controllers explicitly and you'll see where the problem is.
Here is a step by step what is happening under the covers:
The System.Web.Http.DefaultHttpControllerActivator calls into the SimpleInjectorWebApiDependencyResolver and requests the creation of an API controller.
SimpleInjectorWebApiDependencyResolver forwards that call to the SimpleInjector.Container instance.
That Container instance however, does not have any explicit registrations for that API Controller (since you supplied an empty container to the resolver).
Since there is no explicit registration, the container tries to do a last minute registration for that type.
That Controller type however depends on interfaces that can't be resolved because they are not registered in the container (remember, your container is empty).
Although the container would normally throw an exception, null is returned in this case, because the type is requested through the IServiceProvider.GetService method and the type was not registered explictly.
The SimpleInjectorWebApiDependencyResolver's GetService method will return null as well, since it's by definition that it should return null; It should return null when no registration exists (which currently is the case).
Since the DependencyResolver returned null, DefaultHttpControllerActivator will fall back to its default behavior, which means creating that type itself, but this requires the controller to have a default constructor.
Long story short, the problem is caused by the implicit way Web API handles resolving controller types.
So the solution here is to:
Have only one single Container in your web application. This prevents all sorts of trouble and complication of your configuration.
Register all Web API Controllers explicitly in the container. Registering controllers explicitly will ensure that Simple Injector will throw an exception when a controller can't be resolved. Besides, this allows you to call container.Verify() which will make the application fail during startup when the configuration is invalid (a verifiable configuration is important). And this also allows you to diagnose the configuration which gives you even more confidence about the correctness of your configuration.
My advice is to place MVC and Web API in their own project. This will make things much easier.
Registering all Web API controllers can be done with the following code:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
UPDATE:
Because this error is so common, newer versions of the SimpleInjectorWebApiDependencyResolver class will simply never return null when a controller type is requested. Instead it will throw a descriptive error. Because of this you should never see error anymore, as long as you use the official SimpleInjectorWebApiDependencyResolver.
Following setups work for me:
1) include Unity.WebAPI from https://www.nuget.org/packages/Unity.WebAPI/
2) in UnityConfig
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// **** Important note -----
// register all your components with the container here
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
3) in Global.asax file
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Getting started with Unity.WebAPI
To get started, just add a call to UnityConfig.RegisterComponents() in the Application_Start method of Global.asax.cs
and the Web API framework will then use the Unity.WebAPI DependencyResolver to resolve your components.
e.g.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents(); // <----- Add this line
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Add your Unity registrations in the RegisterComponents method of the UnityConfig class. All components that implement IDisposable should be
registered with the HierarchicalLifetimeManager to ensure that they are properly disposed at the end of the request.

How to inject dependencies in an HttpModule with a NinjectHttpApplication (no nuget)?

I have a .Net MVC 3.0 application and I'm using Ninject 3.0. I didn't install any nuget. I'm referencing Ninject.dll, Ninject.Web.Common.dll and Ninject.Web.Mvc.dll (and 2 others). I want to have dependencies injected in a custom HttpModule and I can't figure out how to make it work with a NinjectHttpApplication.
I have this error:
Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Here is the code:
Global.asax
public class MvcApplication: NinjectHttpApplication
{
...
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule()
};
IKernel kernel = new StandardKernel(modules);
return kernel;
}
}
Web.Config
<httpModules>
<add name="NinjectHttpModule" type="Ninject.Web.Common.NinjectHttpModule"/>
</httpModules>
CustomHttpModule.cs
public class CustomHttpModule : IHttpModule
{
private ITesttService service;
public CustomHttpModule(ITesttService service)
{
this.service = service;
}
...
}
ServiceModule.cs
public class ServiceModule : NinjectModule
{
public override void Load()
{
...
Kernel.Bind<ITestService>().To<TestService>();
Kernel.Bind<IHttpModule>().To<CustomHttpModule>().InSingletonScope();
}
}
This binding solves my problem:
kernel.Bind<Func<IKernel>>().ToMethod(c => () => this.Kernel);
But according to this post on github, I'm not supposed to do it.
Can you someone tell me what I'm doing wrong or missing?
Currently there is no good way to use the NinjectHttpModule when deriving from NinjectHttpApplication. The bootstrapper registers the HttpApplicationInitializationHttpModule for both ways and as soon as the NinjectHttpModule is loaded this module is loaded as well.
Unfortunately there is no good point where you can unload it.
I suggest you use the WebActivator instead on deriving from NinjectHttpApplication. It's the only proper way to get it running. You don't necessarily have to use nuget to setup your application that way. You can also add the same files manually and manually reference all required assemblies.

Categories