I need to execute some one-time code on start of my application in the global.asax. I've already got autofac up and running with numerous registrations but the problem is that I can't figure out how to resolve or inject a dependency into SecurityConfig.RegisterActivities() that's inside my global.asax.
I tried manually resolving the dependency myself in global.asax using the autofac container but it threw the exception "No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested."
How do I get this dependency into that class?
protected void Application_Start()
{
var builder = new ContainerBuilder();
DependencyRegistrar dr = new DependencyRegistrar();
dr.Register(builder);
new SecurityConfig().RegisterActivities(); // this needs injecting into or resolving of IServiceManager instance
}
public class DependencyRegistrar
{
public virtual IContainer Register(ContainerBuilder builder)
{
builder.RegisterType<ServiceManager>().As<IServiceManager>().InstancePerHttpRequest();
builder.RegisterType<SecurityConfig>().AsSelf().PropertiesAutowired().InstancePerDependency();
}
}
public class SecurityConfig
{
public void RegisterActivities()
{
ServiceManager.DoSomething();
}
public IServiceManager ServiceManager { get; set; }
}
This allowed me to resolve my dependencies finally.
using(var scope = container.BeginLifetimeScope("AutofacWebRequest"))
{
scope.Resolve<SecurityConfig>().RegisterActivities();
}
Related
I am using ExceptionLogger to handle all the global exception. My inheriting class requires dependencies to be injected for Nlog to invoke.
public class NLogExceptionLogger : ExceptionLogger
{
private readonly ILoggingService _loggingService;
public NLogExceptionLogger(ILoggingService<NLogExceptionLogger> loggingService)
{
_loggingService = loggingService;
}
public override void Log(ExceptionLoggerContext context)
{
_loggingService.FirstLevelServiceLog(context.Exception.StackTrace);
}
}
LoggingService Class:
public class LoggingService<T> : ILoggingService<T>
{
private readonly ILogger _logger;
public LoggingService()
{
string currentClassName = typeof(T).Name;
_logger = LogManager.GetLogger(currentClassName);
}
public void FirstLevelServiceLog(string log)
{
_logger.Log(LogLevel.Debug, log);
}
}
My Unity Code:
public static UnityContainer RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType(typeof(ILoggingService<>), typeof(LoggingService<>))
}
I am registering ExceptionLogger globally by doing: (On this line i am getting an error)
config.Services.Add(typeof(IExceptionLogger), typeof(NLogExceptionLogger));
//Register Dependency Container
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.RegisterComponents());
I am getting following error at runtime:
System.ArgumentException: 'The type RuntimeType must derive from IExceptionLogger.'
My assumption is i am not properly registering the dependency for NLogExceptionLogger.
Any idea on how to resolve dependency while registering the service?
When adding service to ServicesContainer you add the type with the service instance.
Assuming dependency resolver has already been setup, that can be used to resolve the instance if it has dependencies.
var logger = config.DependencyResolver.GetService(typeof(NLogExceptionLogger));
config.Services.Add(typeof(IExceptionLogger), logger);
There is also a difference between exceptions loggers and exception handlers.
I suggest reviewing the following reference link to determine which one is appropriate for your needs.
Reference Global Error Handling in ASP.NET Web API 2
I'm trying to use Autofac for DI in my ASP.NET MVC application. It works fine but I cannot solve a problem with Hangfire.
Here my startup.cs code:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("MyContext");
var container = new AutofacContainer().Container;
var resolver = new AutofacDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.MapSignalR(new HubConfiguration
{
Resolver = resolver
});
AddSignalRInjection(container, resolver);
app.UseHangfireDashboard();
app.UseHangfireServer();
}
private void AddSignalRInjection(IContainer container, IDependencyResolver resolver)
{
var updater = new ContainerBuilder();
updater.RegisterInstance(resolver.Resolve<IConnectionManager>());
updater.RegisterInstance(resolver.Resolve<IMyContext>());
updater.RegisterInstance(resolver.Resolve<ILiveData>());
updater.RegisterInstance(resolver.Resolve<IErp>());
updater.Update(container);
}
}
}
here the AutofacContainer.cs:
public class AutofacContainer
{
public IContainer Container { get; set; }
public AutofacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterType<LiveData>().As<ILiveData>().PropertiesAutowired().InstancePerLifetimeScope();
builder.RegisterType<MyContext>().As<IMyContext>().PropertiesAutowired();
builder.RegisterType<Erp>().As<IErp>().PropertiesAutowired();
Container = builder.Build();
GlobalConfiguration.Configuration.UseAutofacActivator(Container);
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(Container));
}
}
here an extract from Erp.cs:
public interface IErp
{
void InitializeMachines();
}
public class Erp : IErp
{
public IConnectionManager ConnectionManager { get; set; }
public IMyContext _context { get; set; }
public ILiveData _liveData { get; set; }
public Erp(IMyContext context, ILiveData liveData)
{
_context = context;
_liveData = liveData;
}
public void InitializeMachines()
{
// do something
}
}
I add a job in this way:
Hangfire.BackgroundJob.Enqueue<Erp>(x => x.InitializeMachines());
I get the following Hangfire error:
Failed
An exception occurred during processing of a background job.
Autofac.Core.Registration.ComponentNotRegisteredException
The requested service 'MyProject.Classes.Erp' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
The message says the Erp service is not registered, but I don't understand why. As you saw above, I actually registered it:
builder.RegisterType<Erp>().As<IErp>().PropertiesAutowired();
Is the message saying something different I don't understand?
The issue is most likely your use of this line:
Hangfire.BackgroundJob.Enqueue<Erp>(x => x.InitializeMachines());
You have told Hangfire to enqueue a job using the concrete type Erp.
Unfortunately, you didn't tell Autofac how to resolve an Erp. You told it how to resolve an IErp:
builder.RegisterType<Erp>().As<IErp>().PropertiesAutowired();
You thus should change the second code sample to remove .As<IErp>().
I have a Autofac module as below
public class ServiceInjector:Module
{
protected override void Load(ContainerBuilder builder)
{
// many registrations and type looking up here
...
// One of the registration, say t which is found
// in above looking, is a resource consuming type
builder.RegisterType(t).As<ITimeConsume>();
// ...
}
}
And this module is used in a ServiceClass:
public class ServiceClass
{
static IContainer _ioc;
public ServiceClass()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceInjector>();
_ioc = builder.Build();
}
public void InvokeService()
{
using(var scope = _ioc.BeginLifetimeScope())
{
ITimeConsume obj = scope.Resolve<ITimeConsume>(...);
var result = obj.DoTimeConsumingJob(...);
// do something about result here ...
}
}
}
My questions is: how do I test ServiceClass by mocking (Moq) ITimeConsume class ? Here I try to write a test below:
public void Test()
{
Mock<ITimeConsume> moc = GetMockObj(...);
// How can I inject moc.Object into ServiceInjector module,
// so that ServiceClass can use this mock object ?
}
If this is not possible for the way, what's a better design for mocking the time consuming class which can also be injected?
**
Update:
**
Thanks #dubs and #OldFox hints. I think the key is that the Autofac injector should be initialized externally instead of internal controlled. So I leverage 'On Fly' building capability of Autofac.ILifetimeScope and design ServiceClass constructor with a LifeTime scope parameter. With this design I can on-flying registering any service in the unit test as below example:
using(var scope = Ioc.BeginLifetimeScope(
builder => builder.RegisterInstance(mockObject).As<ITimeConsume>())
In the current design you cannot inject your mock object.
The simplest solution with the least changes is to add an Internal Cto'r to ServiceClass:
internal ServiceClass(IContainer ioc)
{
_ioc = ioc;
}
Then use the attributte InternalsVisibleTo to enable the using of the C`tor in your test class.
In the arrange/setup/testInit phase initialize your class under test with the container which contains the mock object:
[SetUp]
public void TestInit()
{
Mock<ITimeConsume> moc = GetMockObj(...);
builder.RegisterInstance(moc).As<ITimeConsume>();
...
...
_target = new ServiceClass(builder.Build());
}
Personally I have multiple container instances. One for each endpoint.
Test project
public class AutofacLoader
{
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceProject.ServiceInjector>();
builder.RegisterModule<LocalTestProject.AutofacModule>();
Container = builder.Build();
}
public static IContainer Container { get; set; }
}
The local test project autofac module is then free to override the service project module with specific registrations.
If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service: http://autofac.readthedocs.org/en/latest/register/registration.html#default-registrations
Test class
public void Test()
{
AutofacLoader.Configure();
var x = AutofacLoader.Container.Resolve<ITimeConsume>();
}
I am using Autofac with MVC / Owin and WebApi.
Following Autofac documentation I am using the setup:
public static void Run(IAppBuilder application) {
ContainerBuilder builder = new ContainerBuilder();
HttpConfiguration configuration = GlobalConfiguration.Configuration;
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterModelBinders(typeof(MvcApplication).Assembly);
builder.RegisterModelBinderProvider();
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterSource(new ViewRegistrationSource());
builder.RegisterFilterProvider();
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
builder.RegisterWebApiFilterProvider(configuration);
builder.RegisterType<Test>().As<ITest>().PropertiesAutowired();
IContainer container = builder.Build();
application.UseAutofacMiddleware(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
I then tested constructor and property injection on a controller:
public interface ITest { }
public class Test : ITest { }
public partial class HomeController : Controller {
private ITest _testConstructor { get; set; }
public ITest TestProperty { get; set; }
public HomeController(ITest testConstructor) {
_testConstructor = testConstructor;
}
public virtual ActionResult Index() {
var test = TestProperty;
}
}
So _testConstructor is injected and TestProperty is always null.
I even checked its value inside Index method and it is null ...
I tried different configurations and in different parts of the application and Property injection always fails ...
Can someone, please, help me out with this?
Update 1
Adding .PropertiesAutowired(); to RegisterController work for controllers but not for ViewPages.
I am using a ViewPageBase as follows:
public abstract class ViewPageBase : WebViewPage {
public ITest Test { get; set; }
} // ViewPageBase
public abstract class ViewPageBase<T> : WebViewPage<T> {
public ITest Test { get; set; }
} // ViewPageBase
And then in Autofac setup I have:
builder.RegisterSource(new ViewRegistrationSource());
builder.RegisterType<Test>().As<ITest>();
builder.RegisterType<WebViewPage>().PropertiesAutowired();
builder.RegisterGeneric(typeof(WebViewPage<>)).PropertiesAutowired();
But when I access Test properties in my views it is null.
Why?
Update 2
If in my layout view I add:
#{
var test = DependencyResolver.Current.GetService<ITest>();
}
test is resolved correctly ...
Maybe is this a problem with Layout Pages and Autofac?
Update 3
I was able to replicate the problem and created a project in https://github.com/mdmoura/MvcAutofac
If you run the project there will be an error on _Layout master page on the second code line:
#SettingsA.Get()
#SettingsB.Get()
SettingsA is resolved in ViewPagePage using DependencyResolver and it works.
With SettingsB i am trying to use Property Injection and no luck.
Autofac configuration is in global.asax Application_Start.
Does anyone knows what might be wrong?
Properties injection is not done automatically in Autofac. You have to tell Autofac to inject properties on your controller registration.
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.PropertiesAutowired();
See Property and Method Injection for more information on autowiring properties.
I'm struggling with how to organize my Autofac component registrations in modules given that some of the modules themselves have dependencies.
I've implemented an abstraction of configuration data (i.e. web.config) in an interface:
interface IConfigurationProvider
{
T GetSection<T>(string sectionName)
where T : System.Configuration.ConfigurationSection;
}
along with implementations for ASP.NET (WebConfigurationProvider) and "desktop" applications (ExeConfigurationProvider).
Some of my autofac modules then require an IConfigurationProvider as a constructor parameter, but some don't:
class DependentModule : Module
{
public DependentModule(IConfigurationProvider config)
{
_config = config;
}
protected override void Load(ContainerBuilder builder)
{
var configSection = _config.GetSection<CustomConfigSection>("customSection");
builder.RegisterType(configSection.TypeFromConfig);
}
private readonly IConfigurationProvider _config;
}
class IndependentModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(/* other stuff not based on configuration */);
}
}
Since the RegisterType() extension method doesn't accept a registration delegate (Func<IComponentContext, T>), like Register() does, I can't register the IConfigurationProvider up-front and then resolve it when I go to register the type specified in the configuration, something like:
// this would be nice...
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig);
This means that I need to be able to register modules with and without a dependency on IConfigurationProvider.
It's obvious how to manually instantiate each module and register it:
IConfigurationProvider configProvider = ...;
var builder = new ContainerBuilder();
builder.RegisterModule(new DependentModule(configProvider));
builder.RegisterModule(new IndependentModule());
using (var container = builder.Build())
{
...
}
But I don't want to manually instantiate my modules - I want to scan assemblies for modules and register them automatically (as discussed in this question). So I have to use reflection to scan the assembly for IModule types, and use Activator.CreateInstance to make registerable instances. But how do I know whether or not to pass an IConfigurationProvider as a constructor parameter. And what happens when other modules have additional or different dependencies?
There's got to be a more straightforward way of accomplishing the basic task: register a type specified in some configuration provided via an interface, right? So how do I do that?
You could do something like this:
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using NUnit.Framework;
namespace Yo_dawg
{
[TestFixture]
public class I_heard_you_like_containers
{
[Test]
public void So_we_built_a_container_to_build_your_container()
{
var modules = GetModules();
Assert.That(modules.Length, Is.EqualTo(4));
var builder = new ContainerBuilder();
foreach (var module in modules)
builder.RegisterModule(module);
var container = builder.Build();
}
private IModule[] GetModules()
{
var builder = new ContainerBuilder();
var configurationProvider = new ConfigurationProvider();
builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned();
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.IsAssignableTo<IModule>())
.AsImplementedInterfaces();
using (var container = builder.Build())
return container.Resolve<IEnumerable<IModule>>().ToArray();
}
}
public class ModuleA : Module
{
public ModuleA(IConfigurationProvider config)
{
}
}
public class ModuleB : Module
{
public ModuleB(IConfigurationProvider config)
{
}
}
public class ModuleC : Module
{
}
public class ModuleD : Module
{
}
public interface IConfigurationProvider
{
}
public class ConfigurationProvider : IConfigurationProvider
{
}
}
For this scenario, Autofac's own XML configuration seems to cover the scenarios you're targeting. Adding a new IConfigurationProvider mechanism seems like reinventing this functionality already provided by the container. The basics are documented at: https://code.google.com/p/autofac/wiki/XmlConfiguration. The configuration syntax has in-built support for modules.
There's a nice alternative by Paul Stovell that allows modules to be registered in code yet receive parameters from config - see: http://www.paulstovell.com/convention-configuration. Hope this helps!