Hangfire With Autofac in WebApi - c#

I have following configuration in startup.cs but I am getting error although I have installed Hangifre.Autofac nuget package and configured.
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.
Startup.cs
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
//if (AppConfigHelper.PlatformEnvironment == PlatformEnvironment.LocalHost)
builder.RegisterType<NLogLogger>().As<ILogger>().InstancePerLifetimeScope();
//else
//builder.RegisterType<SentryLogger>().As<ILogger>().InstancePerLifetimeScope();
//builder.RegisterWebApiFilterProvider(configuration);
// REGISTER CONTROLLERS SO DEPENDENCIES ARE CONSTRUCTOR INJECTED
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
//These lines warm up dlls and load into memory for automatic regisration
var r = new ReplyRepository(null);
var s = new BankService();
builder.RegisterModule(new SelfRegisterModule());
builder.RegisterModule(new RepositoryModule());
builder.RegisterModule(new ServiceModule());
builder.RegisterModule(new EFModule());
builder
.RegisterType<ApplicationOAuthProvider>()
.As<IOAuthAuthorizationServerProvider>()
.PropertiesAutowired() // to automatically resolve IUserService
.SingleInstance(); // you only need one instance of this provider
builder.RegisterType<SellutionUserStore>().As<IUserStore<ApplicationUser, int>>().InstancePerBackgroundJob().InstancePerRequest();
builder.RegisterType<SellutionUserManager>().AsSelf().InstancePerBackgroundJob().InstancePerRequest();
builder.RegisterType<SellutionRoleManager>().AsSelf().InstancePerBackgroundJob().InstancePerRequest();
builder.RegisterType<SellutionSignInManager>().AsSelf().InstancePerBackgroundJob().InstancePerRequest();
builder.Register<IAuthenticationManager>(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerBackgroundJob().InstancePerRequest();
builder.Register<IDataProtectionProvider>(c => app.GetDataProtectionProvider()).InstancePerBackgroundJob().InstancePerRequest();
builder.RegisterType<TicketDataFormat>().As<ISecureDataFormat<AuthenticationTicket>>();
builder.RegisterType<TicketSerializer>().As<IDataSerializer<AuthenticationTicket>>();
builder.Register(c => new DpapiDataProtectionProvider("Sellution360").Create("ASP.NET Identity")).As<IDataProtector>();
builder.RegisterType<CurrencyRatesJob>().AsSelf().InstancePerBackgroundJob();
// BUILD THE CONTAINER
var container = builder.Build();
Hangfire.GlobalConfiguration.Configuration.UseAutofacActivator(container);
JobActivator.Current = new AutofacJobActivator(container);
// REPLACE THE MVC DEPENDENCY RESOLVER WITH AUTOFAC
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Set the dependency resolver for Web API.
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
// Set the dependency resolver for MVC.
var mvcResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(mvcResolver);
// Register the Autofac middleware FIRST, then the Autofac MVC middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc().UseCors(CorsOptions.AllowAll);
app.UseAutofacWebApi(GlobalConfiguration.Configuration).UseCors(CorsOptions.AllowAll); ;
IocManager.Instance.IocContainer = container;
ConfigureAuth(app);
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("DefaultConnection");
app.UseHangfireDashboard();
app.UseHangfireServer();
RecurringJob.AddOrUpdate<CurrencyRatesJob>(j => j.Execute(), Cron.Minutely);
}
CurrencyRatesJob.cs
public class CurrencyRatesJob
{
private readonly ILogger _logger;
private readonly IBusinessTypeService _businessTypeService;
public CurrencyRatesJob(ILogger logger, IBusinessTypeService businessTypeService)
{
_logger = logger;
_businessTypeService = businessTypeService;
}
public void Execute()
{
var types = _businessTypeService.GetBusinessTypes();
_logger.Log("waqar");
}
}

InstancePerBackgroundJob creates Per Macthing Life Time scope with BackgroundJobScope tag. But Per Request instances are resolved in another lifetimescope with Request tag. So when you try resolve Per Request object in BackgroundJobScope life time, it gives error. It says, you can only resolve me in Request lifetime not in root or another. So you should use Per Life Time Scope instead of Per Request.
So these Per Life Time Scope registered objects will get parents lifetimescope. If it's singleton they will be in root. If their parent lifetimescope is request they will live with this request scope. It's same for InstancePerBackgroundJob they will live in BackgroundJobScope life time scope.
And it's good for background objects has another life timescope if they use request lifetime scope your objects can be disposed when request finishes. Also if they are in root scope they will never dispose.

Related

How to Register ILogger(Microsoft.Extensions.Logging) with DI usinq autofac .net framework

I use ILogger from Microsoft.Extensions.Logging in a .net framework project.
Now I want to register the ILogger in the container but i cant.All the answers are about .net core.
i try
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
//first try
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>));
IServiceCollection services = new ServiceCollection();
//second try
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
IContainer container = builder.Build();
httpConfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);
also my class is
public class TestController : ApiController
{
private readonly ILogger<TestController > _logger;
private readonly IService _service;
public TestController (IService service, ILogger<TestController > logger)
{
_service = service;
_logger = logger;
}
}
The di is correct because other services have injected correct.
When i include the logger in constructor i get the message
An error occurred when trying to create a controller of type 'TestController '. Make sure that the controller has a parameterless public constructor.
Since trying to integraten with those extensions, consider populating the service collection is expected and populating the builder once everything is registered,
Example from docs
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
IServiceCollection services = new ServiceCollection();
// The Microsoft.Extensions.Logging package provides this one-liner
// to add logging services.
services.AddLogging();
// Once you've registered everything in the ServiceCollection, call
// Populate to bring those registrations into Autofac. This is
// just like a foreach over the list of things in the collection
// to add them to Autofac.
builder.Populate(services);
IContainer container = builder.Build();
httpConfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);
Reference Autofac: .Net Core Integration

Simple Injector: cannot register Web API controllers with AsyncScopedLifestyle

I am trying to integrate Simple Injector (4.0.12) in my .NET (4.6.1) Web API Project, but cannot find a way to register all Web API Controllers with the correct AsyncScopedLifestyle.
When I try injecting an async scoped instance of DatabaseProvider into the controller like so...
public class DatabaseController : ApiController
{
private readonly IDatabaseProvider databaseProvider;
public DatabaseController(IDatabaseProvider databaseProvider)
{
this.databaseProvider = databaseProvider;
}
[HttpGet]
public bool CheckDatabaseConnection()
{
return databaseProvider.IsConnected();
}
}
... I receive a SimpleInjector.ActivationException with the following error:
The DatabaseProvider is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.
But why?
This is how my code for registering the the controllers looks like:
public static Container Initialize()
{
var container = new Container();
container.Options.LifestyleSelectionBehavior = new CustomLifestyleSelectionBehavior();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
DependencyProvider.SetResolver(new SimpleInjectorDependencyProvider(container));
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
RegisterTypes(container);
//container.Verify();
return container;
}
public class CustomLifestyleSelectionBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType)
{
if (implementationType.GetCustomAttribute<ApplicationScoped>(true) != null)
{
return Lifestyle.Singleton;
}
return new AsyncScopedLifestyle();
}
}
As you can see the DefaultScopedLifestyle is set to AsyncScopedLifestyle and also my CustomLifestyleSelectionBehavior returns the same lifestyle for controllers.
However all controllers seem to be registered as Transient, because this is the output of container.Verify() for all controllers:
Exception Type: DiagnosticVerificationException
Exception Message: The configuration is invalid.
The following diagnostic warnings were reported:
-[Disposable Transient Component] DatabaseController is registered as transient, but implements IDisposable.
-[Disposable Transient Component] LoginDataController is registered as transient, but implements IDisposable.
...
Does anybody know how to set the lifestyle for WebAPIController-registrations to AsyncScoped so that I can inject async scoped business logic?
In .NET Core add:
// Sets up the basic configuration that for integrating Simple Injector with
// ASP.NET Core by setting the DefaultScopedLifestyle, and setting up auto
// cross wiring.
services.AddSimpleInjector(_container, options =>
{
// AddAspNetCore() wraps web requests in a Simple Injector scope and
// allows request-scoped framework services to be resolved.
options.AddAspNetCore()
.AddControllerActivation();
});
via https://simpleinjector.readthedocs.io/en/latest/aspnetintegration.html

How to dynamically resolve InstancePerLifetimeScope dependency in ASP.NET Core?

I have an ASP.NET Core project. I want to dynamically resolve a "one instance per request" dependency inside my other dependencies.
I have registered a dependency using Autofac as an InstancePerLifetimeScope dependency in my Startup class:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>().AsImplementedInterfaces().InstancePerLifetimeScope();
return new AutofacServiceProvider(builder.Build());
}
When I use this dependency directly in controller's constructor, it works as expected - it is a new instance per request.:
public MyController(IMyDependency dependency)
{
}
I want to achieve the same in one of the dependent classes. Dependency is dynamic, so I want to resolve that from IServiceProvider:
public class MyDeepDeepDependency
{
public MyDeepDeepDependency(IServiceProvider serviceProvider)
{
var dep = serviceProvider.GetService(typeof(IMyDependency));
}
}
However, a "dep" instance is the same across all requests.
I assume there is a new scope created per request, and controller is resolved from a new scope. When resolving IServiceProvider, I always get a root IServiceProvider instead of a request one.
Is there a way to resolve IServiceProvider specific for a request? I think it's the same as HttpContext.RequestServices in controller, but I don't want to pass the reference down through all my classes.
Is there any other way to resolve a dynamic dependency once per request?
I ended up injecting IHttpContextAccessor:
public class MyDeepDeepDependency
{
public MyDeepDeepDependency(IHttpContextAccessor contextAccessor)
{
var dep = contextAccessor.HttpContext.RequestServices.GetService(typeof(IMyDependency));
}
}

ASP.NET Core View Injection problems

Has anyone tried to use the new View Injection from ASP.NET Core?
I'm trying to use straight forward as described on the documentation (https://docs.asp.net/en/latest/mvc/views/dependency-injection.html) but no success at all.
The unique diference from my implementation and the documentation is that I'm using AutoFac for DI.
When I try to use the injection on my view I get an exception that my Service has not been registered.
#inject Domain.Service.LevelService LevelService
Error Message:
ComponentNotRegisteredException: The requested service 'Domain.Service.LevelService' 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.
Btw, the service is correctly registered and can be accessed from the controller for example.
Edit to include Startup:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddMemoryCache();
services.AddSession();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
return new AutofacServiceProvider(DependencyInjection.RegisterServices(services));
}
Code of the method RegisterServices:
public static IContainer RegisterServices(IServiceCollection services)
{
// Create the container builder.
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
assembly.GetTypes()
.Where(x => x.IsSubclassOf(typeof(ServiceInjectionModule)))
.ToList()
.ForEach(x =>
{
var t = (ServiceInjectionModule)Activator.CreateInstance(x, new object[] { true });
t.AddtoContainer(builder);
});
// Add automapper configurations
var mapperConfiguration = AutoMapperConfig.Configure();
var mapper = mapperConfiguration.CreateMapper();
builder.RegisterInstance(mapper).As<IMapper>();
// Populate default services
builder.Populate(services);
return builder.Build();
}
The problem is in the assembly scanning section you've written. It's much easier to use the built in functionality of AutoFac. Not sure your code is .Net Core just based on the fact you're not using GetTypeInfo. GetTypeInfo is backwards compatible so will work with .Net 4.x
public static IContainer RegisterServices(IServiceCollection services)
{
// Create the container builder.
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.GetTypeInfo().IsSubclassOf(typeof(ServiceInjectionModule)))
.AsSelf();
// Add automapper configurations
var mapperConfiguration = AutoMapperConfig.Configure();
var mapper = mapperConfiguration.CreateMapper();
builder.RegisterInstance(mapper).As<IMapper>();
// Populate default services
builder.Populate(services);
return builder.Build();
}
OK, I solved the problem.
Well, I didn't paid attention and seems that no one too :p.
The problem is that I'm trying to inject an instance and not an interface. Just changed the implementation and everything started working.
Final code:
#inject Domain.Service.Interfaces.ILevelService LevelService

autofac with signalr no parameterless constructor defined for this object

I'm using autofac on my current Asp project and everything works fine until i decided to use dependancy injection in a signalR Hub
here's my startup class
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.RegisterType<DbFactory>().As<IDbFactory>().InstancePerLifetimeScope();
//builder.RegisterHubs(Assembly.GetExecutingAssembly());
builder.RegisterType<DiscussionHub>();
// Repositories
builder.RegisterAssemblyTypes(typeof(LanguagesRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerRequest();
// Services
builder.RegisterAssemblyTypes(typeof(LanguageService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
var config = new HubConfiguration
{
Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container)
};
app.UseAutofacMiddleware(container);
AutoMapperConfiguration.Configure();
app.MapSignalR("/signalr",config);
}
}
and here's my Hub
public class DiscussionHub : Hub
{
private readonly IDiscussionService _discussionService;
public DiscussionHub(IDiscussionService discussionService)
{
_discussionService = discussionService;
}}
the error is that i'm getting no parameterless constructor on my Hub? any suggestion ?!
You should register your hub ExternallyOwned it should manage lifetimescope by itself. That's mean autofac will not disposed them.
Second, everything will be resolved from root container in your hub. That's mean Per Dependency or Per LifeTimeScope will live with your hub(forever with app). So you should manage lifetime in your hub.
Even if we manage life time in your hub, Per Request will not be supported. Because of this, when we create new lifetimescope, we will create it with AutofacWebRequest tag. That way, we can resolve your Per Request instance. But pay attention this instance will be totaly different with other instance in normal request lifetimescope.
Your Hub should be like this:
public class DiscussionHub : Hub
{
private readonly ILifetimeScope _hubLifetimeScope;
private readonly IDiscussionService _discussionService;
public MyHub(ILifetimeScope lifetimeScope)
{
// Create a lifetime scope for the hub.
_hubLifetimeScope = lifetimeScope.BeginLifetimeScope("AutofacWebRequest");
// Resolve dependencies from the hub lifetime scope.
_discussionService = _hubLifetimeScope.Resolve<IDiscussionService>();
}
protected override void Dispose(bool disposing)
{
// Dipose the hub lifetime scope when the hub is disposed.
if (disposing && _hubLifetimeScope != null)
{
_hubLifetimeScope.Dispose();
}
base.Dispose(disposing);
}
}
Your register should be like this:
.
.
builder.RegisterType<DiscussionHub>().ExternallyOwned();
var container = builder.Build();
GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container);
.
.
Owin Integration:
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD SIGNALR SETUP:
// Get your HubConfiguration. In OWIN, you'll create one
// rather than using GlobalHost.
var config = new HubConfiguration();
// Register your SignalR hubs.
builder.RegisterHubs(Assembly.GetExecutingAssembly());
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.Resolver = new AutofacDependencyResolver(container);
// OWIN SIGNALR SETUP:
// Register the Autofac middleware FIRST, then the standard SignalR middleware.
app.UseAutofacMiddleware(container);
app.MapSignalR("/signalr", config);
}
Check more detail.

Categories

Resources