The ILoggerProvider Dispose function is not being invoked when I am running a unit test. Here is how I am initating the logger provider:
.AddTransient<ILogger, MyLogger>()
.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.AddProvider(new LoggerProvider(config));
})
and in InitializeTest() I am getting the logger like this
logger = servicesProvider.GetRequiredService<ILogger>();
the loggerprovider class:
public class LoggerProvider : ILoggerProvider
{
public IConfiguration Config { get; }
private MyLogger logger;
public LoggerProvider(IConfiguration config)
{
Config = config;
}
/// <summary>
/// Create logger method.
/// </summary>
/// <param name="categoryName">Category name</param>
/// <returns></returns>
public ILogger CreateLogger(string categoryName)
{
logger = new MyLogger(Config);
return logger;
}
/// <summary>
/// Dispose.
/// </summary>
public void Dispose()
{
logger.Dispose();
}
}
Unit test part
[TestInitialize()]
public void InitializeTest()
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory
.GetCurrentDirectory()) Microsoft.Extensions.Configuration.Json
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
servicesProvider = ServiceProvider.BuildDi(config);
logger = servicesProvider.GetRequiredService<ILogger>();
}
[TestMethod]
public void TestInformation()
{
try
{
logger.LogInformation("Testing");
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
Assert.IsTrue(true);
}
Is dispose not triggered after running a unit test?
Generally speaking for the resources inside the ServiceProvider to be disposed, the ServiceProvider needs to be disposed itself (unless the resource is scoped, then the scope needs to be disposed).
So in this case ServiceProvider needs to be moved to within the test and it needs to be wrapped inside a using:
using (var servicesProvider = ServiceProvider.BuildDi(config))
{
...
}
Or the new way:
using var servicesProvider = ServiceProvider.BuildDi(config);
Here is a .Net Fiddle illustrating this behavior.
Related
we can access the IServiceProvider as:
public class ProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IServiceProvider serviceProvider)
{
_productRepository = serviceProvider.GetRequiredService<IProductRepository>();
}
...
}
so it is obvious that .net registers IServiceProvider as a service by default, but I checked the source code:https://github.com/aspnet/Hosting/blob/master/src/Microsoft.Extensions.Hosting/HostBuilder.cs#L198
private void CreateServiceProvider() {
var services = new ServiceCollection();
services.AddSingleton(_hostingEnvironment);
services.AddSingleton(_hostBuilderContext);
services.AddSingleton(_appConfiguration);
services.AddSingleton<IApplicationLifetime, ApplicationLifetime>();
services.AddSingleton<IHostLifetime, ConsoleLifetime>();
services.AddSingleton<IHost, Host>();
services.AddOptions();
services.AddLogging();
foreach (var configureServicesAction in _configureServicesActions) {
configureServicesAction(_hostBuilderContext, services);
}
var containerBuilder = _serviceProviderFactory.CreateBuilder(services);
foreach (var containerAction in _configureContainerActions) {
containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder);
}
_appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder); // _appServices is IServiceProvider
if (_appServices == null) {
throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider.");
}
}
so we can see that for example:
services.AddSingleton(_appConfiguration);
register IConfiguration (ConfigurationRoot instance under the hood), that's why we can use it in the startup.cs:
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
but I can't see the source code register _appServices(IServiceProvider) anywhere, there is no sth like services.AddSingleton(_appServices); in the source code
So how we still can access IServiceProvider automatically? or I must be missing somewhere, the source code does register IServiceProvider somewhere else?
When BuildServiceProvider extension is eventually invoked on the service collection
/// <summary>
/// Creates a <see cref="ServiceProvider"/> containing services from the provided <see cref="IServiceCollection"/>
/// optionally enabling scope validation.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> containing service descriptors.</param>
/// <param name="options">
/// Configures various service provider behaviors.
/// </param>
/// <returns>The <see cref="ServiceProvider"/>.</returns>
public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return new ServiceProvider(services, options);
}
Source
The ServiceProvider instance, adds itself as a service.
internal ServiceProvider(ICollection<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
// note that Root needs to be set before calling GetEngine(), because the engine may need to access Root
Root = new ServiceProviderEngineScope(this, isRootScope: true);
_engine = GetEngine();
_createServiceAccessor = CreateServiceAccessor;
_realizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
// The list of built in services that aren't part of the list of service descriptors
// keep this in sync with CallSiteFactory.IsService
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ConstantCallSite(typeof(IServiceScopeFactory), Root));
CallSiteFactory.Add(typeof(IServiceProviderIsService), new ConstantCallSite(typeof(IServiceProviderIsService), CallSiteFactory));
if (options.ValidateScopes)
{
_callSiteValidator = new CallSiteValidator();
}
if (options.ValidateOnBuild)
{
List<Exception> exceptions = null;
foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors)
{
try
{
ValidateService(serviceDescriptor);
}
catch (Exception e)
{
exceptions = exceptions ?? new List<Exception>();
exceptions.Add(e);
}
}
if (exceptions != null)
{
throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray());
}
}
DependencyInjectionEventSource.Log.ServiceProviderBuilt(this);
}
Source
I know this is a repeated question , went through answers and dont know whats happening here. In this problem we need to transfer the values from appsettings.json to another class other than Controllers here its ServiceSettings.cs.
This is a sample 'hello world' like program, here we need transfer values from appsettings.json to plugins.
This is folder architecture
appsettings.json
"Application": {
"TimerInterval": 10000,
"LogLevel": "Debug"
}
I created a class based upon this app setting in class library-
ApplicationSettings.cs
public class ApplicationSettings
{
public int TimerInterval { get; set; }
public string LogLevel { get; set; }
}
I tried push data from appsettings via the last line code
services.Configure<ApplicationSettings>(hostContext.Configuration.GetSection("Application"));
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IConfiguration>(hostContext.Configuration);
// Service Settings Injected here
services.AddOptions<ServiceSettings>();
services.AddHostedService<Worker>();
services.Configure<ApplicationSettings>(hostContext.Configuration.GetSection("Application"));
// for configure application
});
}
Here during start method of the worker class i need to get values from ServiceSettings() which always returns null value.
Worker.cs(Re Edited)
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IConfiguration _configuration;
private ServiceSettings _settings;
public Worker(ILogger<Worker> logger, IConfiguration config)
{
_logger = logger;
_configuration = config;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Start Asynch Method");
// Load Settings From Configuration Files
_settings = new ServiceSettings();
_settings.Load();
_logger.LogInformation("Settings: {setting}", _settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var values = _configuration.GetSection("DataSources").Get<List<DataSource>>();
while (!stoppingToken.IsCancellationRequested) {
await Task.Delay(Convert.ToInt32(_configuration["Application:TimerInterval"]), stoppingToken);
}
}
}
The service settings values are provided below which receives the null value
ServiceSettings.cs
public class ServiceSettings
{
private readonly IOptions<ApplicationSettings> _appSettings;
public ServiceSettings(IOptions<ApplicationSettings> appSettings)
{
_appSettings = appSettings;
}
public int TimerInterval { get; set; }
public string LogLevel { get; set; }
public void Load()
{
// Error is shown here
try { TimerInterval = Convert.ToInt32(_appSettings.Value.TimerInterval); }
catch { TimerInterval = 60; }
try
// Here too
{ LogLevel = Convert.ToString(_appSettings.Value.LogLevel).ToLower(); }
catch { LogLevel = "info"; }
}
}
I am pretty new to worker service, What i miss here? kindly guide me with the resources Thank you all.
This appears to be a design issue.
First lets fix the composition root. Avoid injecting IConfiguration. It can be seen as a code smell as IConfiguration should ideally be used in startup.
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) => {
IConfiguration config = hostContext.Configuration;
// parse settings
ApplicationSettings appSettings = config
.GetSection("Application").Get<ApplicationSettings>();
//set defaults.
if(appSettings.TimerInterval == 0)
appSettings.TimerInterval = 60;
if(string.IsNullOrWhiteSpace(appSettings.LogLevel))
appSettings.LogLevel = "Debug";
services.AddSingleton(appSettings); //<-- register settings run-time data
services.AddHostedService<Worker>();
});
}
Note how the settings are extracted from configuration and added to the service collection.
Since there is already a strongly defined type (ApplicationSettings) There really is no need for the ServiceSettings based on what was shown in the original question.
Update the worker to explicitly depend on the actual object required.
public class Worker : BackgroundService {
private readonly ILogger<Worker> _logger;
private readonly ApplicationSettings settings;
public Worker(ILogger<Worker> logger, ApplicationSettings settings) {
_logger = logger;
this.settings = settings; //<-- settings injected.
}
public override Task StartAsync(CancellationToken cancellationToken) {
Console.WriteLine("Start Asynch Method");
_logger.LogInformation("Settings: {setting}", settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
await Task.Delay(settings.TimerInterval), stoppingToken);
}
}
}
You always have to get instances from your service collection. You typically do this by injecting them in class constructor.
// WRONG
// Worker.cs
_settings = new ServiceSettings();
This code does not compile because your ServiceSettings class has a constructor that requires one parameter but no parameter is given.
how should your class know anything about the options stored in service collection without any reference?
Then it seems to make no sense to have two classes with the same data ServiceSettings and ApplicationSettings are the same. If you need the application settings in a service inject IOptions<ApplicationSettings> that's all. If you need separate settings classes, provide them as IOption<MyOtherSectionSettings>.
In the end, it could look like so:
public class Worker {
private readonly ApplicationSettings _settings;
private readonly ILogger<Worker> _logger;
public Worker(IOptions<ApplicationSettings> settingsAccessor, ILogger<Worker> logger) {
_settings = settingsAccessor.Value;
_logger = logger;
}
public override Task StartAsync(CancellationToken cancellationToken) {
Console.WriteLine("Start Asynch Method");
_logger.LogInformation("Settings: {setting}", _settings.TimerInterval);
return base.StartAsync(cancellationToken);
}
}
Note that reading settingsAccessor.Value is the place where the framework really tries to access the configuration and so here we should think about error conditions (if not validated before).
I did not managed to find any similar example, so I decided to ask the question.
I am using Autofac to register my service layer interfaces and I am wondering, can I inject one into App.xaml.cs?
I am having my own log service, that I want to run in case of fatal error in the application.
As far as I know similar way you can inject dependency to the window, can I do it the same in App.xaml.cs?
public partial class App : Application
{
private readonly ILogService _log;
public App()
{
}
public App(ILogService log) : this()
{
_log = log;
}
async Task App_DispatcherUnhandledExceptionAsync(object sender, DispatcherUnhandledExceptionEventArgs e)
{
_log.Error("App.xaml.cs exception: " + e.Exception.Message);
await _log.SaveAllLinesAsync();
e.Handled = true;
}
}
Autofac IoC:
public class BootStrapper
{
/// <summary>
/// IoC container
/// </summary>
/// <returns></returns>
public static IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<EventAggregator>()
.As<IEventAggregator>().SingleInstance();
builder.RegisterType<LogService>()
.As<ILogService>().SingleInstance();
builder.RegisterType<DeleteView>().AsSelf();
builder.RegisterType<DeleteViewModel>().AsSelf().SingleInstance();
builder.RegisterType<PhraseView>().AsSelf();
builder.RegisterType<PhraseViewModel>().AsSelf().SingleInstance().WithParameter(new NamedParameter("searchPhrase", ""));
builder.RegisterType<PopulateDictionaries>().AsSelf().SingleInstance();
return builder.Build();
}
}
IoC initializing in ViewModelLocator:
public class ViewModelLocator
{
IContainer _container;
public ViewModelLocator()
{
_container = BootStrapper.BootStrap();
}
//view models below
}
If you want to inject the App class with a dependency, you should define a custom Main method where you instantiate the App class:
public class Program
{
[STAThread]
public static void Main(string[] args)
{
ILogService logService = ...;
App app = new App(logService);
app.InitializeComponent();
app.Run();
}
}
If you do this, remember to change the Build Action of App.xaml from ApplicationDefinition to Page.
I have a project with three-level architecture:
project.Data
project.Domain
project.Web
I need to implement Quartz.Net to user interface level.
And use it following way:
public class EmailSender : IJob
{
ISomeService _service;
public EmailSender(ISomeService service)
{
_service = service;
}
public void Execute(IJobExecutionContext context)
{
_service.Create();
}
}
public class EmailScheduler
{
public static void Start()
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<EmailSender>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(1)
.RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
}
In global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
EmailScheduler.Start();
}
}
In project.Data
I use pattern of repositories. As I use few repositories for each entity, I use Unit of Work pattern to make easier connection to database.
public interface IUnitOfWork : IDisposable
{
ISomeRepository SomeRepository { get; }
void Save();
}
EFUnitOfWork class in constructor receives string with name of connection, which will be sent to data context constructor
So we will interact with database through EFUnitOfWork class.
public class EFUnitOfWork : IUnitOfWork
{
private Context db;
private SomeRepository _someRepository;
public EFUnitOfWork(string connectionString)
{
db = new Context(connectionString);
}
public ISomeRepository SomeRepository
{
get
{
if (_someRepository == null)
_someRepository = new SomeRepository(db);
return _someRepository;
}
}
}
In project.Domain
ServiceModule is a special module Ninject, which is used for organizing dependencies matching.
It replaces EFUnitOfWork with IUnitOfWork.
public class ServiceModule : NinjectModule
{
private string connectionString;
public ServiceModule(string connection)
{
connectionString = connection;
}
public override void Load()
{
Bind<IUnitOfWork>().To<EFUnitOfWork>().WithConstructorArgument(connectionString);
}
}
public interface ISomeService
{
void Create();
}
public class SomeService : ISomeService
{
IUnitOfWork Database { get; set; }
public LetterService(IUnitOfWork uow)
{
Database = uow;
}
public void Create(){
}
}
In project.Web
To set dependencies I use following class:
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<ISomeService>().To<SomeService>();
}
}
In App_Start folder
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(evenafter.WEB.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(evenafter.WEB.App_Start.NinjectWebCommon), "Stop")]
namespace project.WEB.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Util;
using Ninject.Modules;
using Domain.Infrastructure;
using Quartz.Impl;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
// set connection string
var modules = new INinjectModule[] { new ServiceModule("DefaultConnection") };
var kernel = new StandardKernel(modules);
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
}
}
I have a custom AuthorizationFilter Attribute on my Web Api project like this
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class GenericAuthenticationFilter : AuthorizationFilterAttribute
{
/// <summary>
/// Public default Constructor
/// </summary>
public GenericAuthenticationFilter()
{
}
private readonly bool _isActive = true;
/// <summary>
/// parameter isActive explicitly enables/disables this filter.
/// </summary>
/// <param name="isActive"></param>
public GenericAuthenticationFilter(bool isActive)
{
_isActive = isActive;
}
/// <summary>
/// Checks basic authentication request
/// </summary>
/// <param name="filterContext"></param>
public override void OnAuthorization(HttpActionContext filterContext)
{
if (!_isActive) return;
var identity = FetchAuthHeader(filterContext);
if (identity == null)
{
ChallengeAuthRequest(filterContext);
return;
}
var genericPrincipal = new GenericPrincipal(identity, null);
Thread.CurrentPrincipal = genericPrincipal;
if (!OnAuthorizeUser(identity.Name, identity.Password, filterContext))
{
ChallengeAuthRequest(filterContext);
return;
}
base.OnAuthorization(filterContext);
}
My StartUpClass is like this
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
WebApiConfig.Register(config);
IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
config.DependencyResolver =
new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());
// Register your Web Api controllers.
IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterWebApiModelBinderProvider();
IoC.Instance.RegisterWebApiFilterProvider(config);
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
and my IoC class where all dependencies are resolved is like this
public class IoC : ContainerBuilder
{
/// <summary>
///
/// </summary>
private readonly static IoC _instance = new IoC();
/// <summary>
///
/// </summary>
private static object _lock;
/// <summary>
///
/// </summary>
private IContainer _componentsContainer;
/// <summary>
///
/// </summary>
public static IoC Instance
{
get
{
return _instance;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IContainer GetComponentsContainer()
{
if (_componentsContainer == null)
{
lock (_lock)
{
if (_componentsContainer == null)
_componentsContainer = this.Build();
}
}
return _componentsContainer;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Resolve<T>() where T : class
{
return GetComponentsContainer().Resolve<T>();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ILifetimeScope BeginLifetimeScope()
{
return GetComponentsContainer().BeginLifetimeScope();
}
/// <summary>
///
/// </summary>
private IoC()
{
_lock = new object();
ConfigureDependencies();
}
/// <summary>
///
/// </summary>
private void ConfigureDependencies()
{
//Configure all your depedendencies here!!
//Database connection
var connectionString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerRequest();// InstancePerLifetimeScope();
//Database Connection OrmLite
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
//Register Repositories
this.RegisterType<Repository>().As<IRepository>().InstancePerRequest();// InstancePerLifetimeScope();
// Register Services
this.RegisterType<UserService>().As<IUserService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<TokenService>().As<ITokenService>().InstancePerRequest();
this.RegisterType<DKMenuService>().As<IDKMenuService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<DKGRIDTblService>().As<IDKGRIDTblService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<FKService>().As<IFKService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<LOVService>().As<ILOVService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<JobService>().As<IJobService>().InstancePerRequest();// InstancePerLifetimeScope();
this.RegisterType<MADEService>().As<IMADEService>().InstancePerRequest();// InstancePerLifetimeScope();
}
}
And I decorate my Controllers with this filter like this
[GenericAuthenticationFilter]
public AuthenticateController(ITokenService tokenService)
{
_tokenService = tokenService;
}
My Problem is that the OnAuthorazation method of the GenericAuthenticationFilter is never fired.
If on the IoC Class class I change InstancePerRequest to InstancePerLifetimeScope everything works ok, but I want my dependencies to work per Request
Any Ideas?
I'm not sure if this is part or all of your issue, but... you can only build a ContainerBuilder once. In Startup.Configuration() I see on lines 11-12:
config.DependencyResolver =
new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());
And IoC.Instance.GetComponentsContainer() calls Build() to create the container.
But just two lines later I see you're adding more components to the container, and after that I see a second call:
app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());
Based on your code, that's going to be the same container that was built before you added the new registrations. The container won't include the API controllers, the model binders, or the filter provider.
I'm actually not sure why you're not having more problems than you're having now.
Try moving the setting of the containers (the calls to IoC.Instance.GetComponentsContainer()) until all the way at the end, after you've finished registering all of your dependencies.
The only configuration that worked was the following
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
WebApiConfig.Register(config);
// Register your Web Api controllers.
IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterWebApiModelBinderProvider();
config.DependencyResolver =
new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());
// Register your Web Api controllers.
//IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
//IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
//IoC.Instance.RegisterWebApiModelBinderProvider();
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
I am still not sure whether it is right.
Examples of usage. I have a filter like the following
public class ApiAuthenticationFilter : GenericAuthenticationFilter
{
/// <summary>
/// Default Authentication Constructor
/// </summary>
public ApiAuthenticationFilter()
{
}
}
A method in this filter is using a service which is resolved like this
protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
{
var provider = actionContext.Request.GetDependencyScope().GetService(typeof(IUserService)) as IUserService;
}
My controllers on the other hand do not have parameterless constructors and the dependencies are resolved automatically
public class DKMenuController : ApiController
{
#region Private variable.
private readonly ITokenService _tokenService;
private readonly IDKMenuService _dkMenuService;
private readonly IUserService _userservice;
private const string Token = "Token";
#endregion
#region Public Constructor
/// <summary>
/// Public constructor to initialize DKMenu service instance
/// </summary>
public DKMenuController(ITokenService tokenService, IUserService userservice, IDKMenuService dkMenuService)
{
_tokenService = tokenService;
_dkMenuService = dkMenuService;
_userservice = userservice;
}
}
I don't know whether it is correct but it works