I'm trying to get instance of ILogger<T> when resolving a dependency in the Startup class of an Azure Function v4 in process version.
Only this doesn't work and will result in an exception, null or a not working logger.
I followed the following AutoFac documentation for Azure Functions.
I register some types and try to resolve a type in the Startup class. The problem is the ILogger<T>. In this case the Logger<EventBusServiceBus>.
In the sample I try to resolve IEventBus in the ConfigureEventBus method. Because of this, services.AddSingleton<IEventBus, EventBusServiceBus>(sp => ....); is trying to be resolved in the AddEventBus method.
I don't understand why it can't be resolved because I see some registered types in the Autofac container.
See the comments in the code.
Thanks!
Simplified Startup from the docs:
internal class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// Use IServiceCollection.Add extension method to add features as needed, e.g.
//builder.Services.AddDataProtection();
builder.Services.AddSingleton(GetContainer(builder.Services));
// Important: Use AddScoped so our Autofac lifetime scope gets disposed
// when the function finishes executing
builder.Services.AddScoped<LifetimeScopeWrapper>();
builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivator), typeof(AutofacJobActivator)));
builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IJobActivatorEx), typeof(AutofacJobActivator)));
builder.Services.AddCustomIntegrations(configuration);
builder.Services.AddEventBus(configuration);
var serviceProvider = builder.Services.BuildServiceProvider();
ConfigureEventBus(serviceProvider);
}
private static IContainer GetContainer(IServiceCollection serviceCollection)
{
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(serviceCollection);
containerBuilder.RegisterModule<LoggerModule>();
// This is a convenient way to register all your function classes at once
containerBuilder.RegisterAssemblyTypes(typeof(Startup).Assembly)
.InNamespaceOf<Function1>();
// TODO: Register other dependencies with the ContainerBuilder like normal
return containerBuilder.Build();
}
private void ConfigureEventBus(ServiceProvider sp)
{
var eventBus = sp.GetRequiredService<BuildingBlocks.EventBus.Abstractions.IEventBus>();
// Unable to use eventBus here
}
}
Some extension methods:
static class CustomExtensionsMethods
{
public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var serviceBusConnectionString = configuration["EventBusConnection"];
var subscriptionClientName = configuration["SubscriptionClientName"];
return new DefaultServiceBusPersisterConnection(serviceBusConnectionString);
});
return services;
}
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
{
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
// Get autofac container so we rolve dependencies from there
var autoFacContainer = sp.GetRequiredService<IContainer>();
// This doesn't work
////var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
// This does work
var iLifetimeScope = autoFacContainer.Resolve<ILifetimeScope>();
// This doesn't work
//var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
// This doesn't work either but at least now no error/exception. Resolves into empty logger.
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.CreateLogger<EventBusServiceBus>();
// Tried these for logging without luck.
// Don't understand because I see a loggerfactory and Ilogger in the container...
//var loggerFactory = autoFacContainer.ResolveNamed<ILoggerFactory>("loggerFactory");
//var loggerFactory = autoFacContainer.Resolve<ILoggerFactory>();
////var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
////var logger = loggerFactory.CreateLogger<EventBusServiceBus>();
////autoFacContainer.Resolve<ILogger<EventBusServiceBus>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
string subscriptionName = configuration["SubscriptionClientName"];
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
eventBusSubcriptionsManager, iLifetimeScope, subscriptionName);
});
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
return services;
}
}
So I did found a working solution for now. Maybe someone has a better solution but this works for me for now...
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
{
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
// Get autofac container so we resolve dependencies from there
var autoFacContainer = sp.GetRequiredService<IContainer>();
// This does work
var iLifetimeScope = autoFacContainer.Resolve<ILifetimeScope>();
// Create a new logger that is connected to the console with a minimum loglevel from host.json based on the namespace
var loggerFactory = LoggerFactory.Create(builder =>
{
var logLevel = configuration.GetValue<LogLevel>("AzureFunctionsJobHost:logging:logLevel:" + typeof(Startup).Namespace, LogLevel.Information);
builder.AddConsole();
builder.SetMinimumLevel(logLevel);
});
var logger = loggerFactory.CreateLogger<EventBusServiceBus>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
string subscriptionName = configuration["SubscriptionClientName"];
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
eventBusSubcriptionsManager, iLifetimeScope, subscriptionName);
});
return services;
}
So the important part is this:
// Create a new logger that is connected to the console with a minimum loglevel from host.json based on the namespace
var loggerFactory = LoggerFactory.Create(builder =>
{
var logLevel = configuration.GetValue<LogLevel>("AzureFunctionsJobHost:logging:logLevel:" + typeof(Startup).Namespace, LogLevel.Information);
builder.AddConsole();
builder.SetMinimumLevel(logLevel);
});
var logger = loggerFactory.CreateLogger<EventBusServiceBus>();
Related
I'm building .NetCore console app which uses SimpleRabbit (RabbitMQ).
I am attempting to use HostBuilder() to this purpose (dependecy injection, configuration, services).
I create a SimpleInjector container in the Bootstrap class.
I would like to inject this container for use into HostBuilder.
As you can see below, the FooSubscriberService constructor is expecting a container.
I see HostBuilder exposes a ConfigureContainer() method which sounds like what I'm looking for.
I've looked around but I'm unclear as how to use this/inject the container.
Supporting Class Snippets
public class FooSubscriberService : IFooSubscriberService
{
Container container;
private readonly ILogger<FooSubscriberService> logger;
public FooSubscriberService(Container container, ILogger<DiscoverySubscriberService> logger)
{
this.container = container;
this.logger = logger;
}
....
}
public class QueueManagementService : BasicRabbitService, IQueueManagementService
{
ILogger _logger;
public QueueManagementService(RabbitConfiguration config, ILogger<QueueManagementService> _logger) : base(config)
{
this._logger = _logger;
}
....
}
Container Creation
public class Bootstrap
{
public static Container container;
public static void ConfigureServices(IConfigurationRoot configurationRoot)
{
container = new SimpleInjector.Container();
container.Options.ResolveUnregisteredConcreteTypes = false;
container.Options.EnableAutoVerification = false;
RabbitConfiguration rabbitConfiguration = new RabbitConfiguration();
configurationRoot.GetSection("RabbitConfiguration").Bind(rabbitConfiguration);
var runtimeModel = new RuntimeConfigurationModel();
var runtimeStatus = new RuntimeServicesStatus();
container.ConfigureServices(rabbitConfiguration, runtimeModel, runtimeStatus, searchJobStatus);
}
}
Code Snippet for initializing and running HostBuilder.
Bootstrap.ConfigureServices(configurationRoot);
var container = Bootstrap.container;
var builder = new HostBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
})
.ConfigureServices((context, services) =>
{
var config = context.Configuration;
services
.AddRabbitConfiguration(configurationRoot.GetSection("RabbitConfiguration"))
.AddSubscriberConfiguration(configurationRoot.GetSection("Subscribers"))
.AddPublisherServices()
.AddSubscriberServices()
.AddSingletonMessageHandler<FooSubscriberService>()
.AddSingleton<IQueueManagementService, QueueManagementService>()
.AddSingleton<IHostedService, FooConsoleService>();
});
// ??? .ConfigureContainer<Container>( => { }); ???
await builder.RunConsoleAsync();
What is the method for injecting my Container into HostBuilder()?
Are there additional NuGet packages I need to use?
Im trying to use Hangfire with Microsoft.Extensions.DependencyInjection in an Asp.Net 4.7.2 MVC Application.
I have the DI setup and working, I just cant seem to configure Hangfire correctly. The current implementation below runs the dashboard, but executing a background task returns the error:
JobActivator returned NULL instance of the 'Dh.Web.Services.EmailService' type.
I know EmailService is correctly setup in DI because I can access it using DI in the same controller that is calling the BackgroundJob.Enqueue method.
My Implementation is:
HangfireActivator.cs
public class HangfireActivator : JobActivator
{
private readonly IServiceProvider _serviceProvider;
public HangfireActivator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public override object ActivateJob(Type type)
{
return _serviceProvider.GetService(type);
}
}
ConfigureHangfire Method inside startup.cs
private void ConfigureHangfire(IServiceProvider serviceProvider, IAppBuilder app)
{
var hangfireConnString = ConfigurationManager.ConnectionStrings["Dh"].ConnectionString;
GlobalConfiguration.Configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseActivator(new HangfireActivator(serviceProvider))
.UseSqlServerStorage(hangfireConnString, new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.FromSeconds(10),
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true,
}
);
app.UseHangfireServer(new BackgroundJobServerOptions {WorkerCount = 3});
var options = new DashboardOptions()
{
Authorization = new[] {new SystemAuthorizationFilter()}
};
app.UseHangfireDashboard("/hangfire",options);
}
and then finally Configuration Method in Startup.cs
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
//App DI
ConfigureServices(services);
var serviceProvider = services.BuildServiceProvider();
var resolver = new DefaultDependencyResolver(serviceProvider);
DependencyResolver.SetResolver(resolver);
//Hangfire
ConfigureHangfire(serviceProvider,app);
}
I have a suspicion that its the line: var serviceProvider = services.BuildServiceProvider(); that is creating a seperate service provider to the one i setup all my App DI in, but i dont know how to get the ServiceProvider to the UseActivator option in Hangfire without that line...
I would really really appreciate any input. Thank you!
I had registered in my DI:
services.AddTransient<IEmailService,EmailService>();
However adding this to register the concrete class without the interface worked.
services.AddTransient<EmailService>();
I am trying to implement Dependency Injection in Xunit test for AppService. Ideal goal is to run the original application program Startup/configuration, and use any dependency injection that was in Startup, instead of reinitializing all the DI again in my test, thats the whole Goal in question.
Update: Mohsen's answer is close. Need to update couple syntax/requirement errors to work.
For some reason, original application works and can call Department App Service. However, it cannot call in Xunit. Finally got Testserver working using Startup and Configuration from original application.
Now receiving error below:
Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService
namespace Testing.IntegrationTests
{
public class DepartmentAppServiceTest
{
public DBContext context;
public IDepartmentAppService departmentAppService;
public DepartmentAppServiceTest(IDepartmentAppService departmentAppService)
{
this.departmentAppService = departmentAppService;
}
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
var options = new DbContextOptionsBuilder<SharedServicesContext>()
.UseInMemoryDatabase(databaseName: "TestDatabase")
.Options;
context = new DBContext(options);
TestServer _server = new TestServer(new WebHostBuilder()
.UseContentRoot("C:\\OriginalApplication")
.UseEnvironment("Development")
.UseConfiguration(new ConfigurationBuilder()
.SetBasePath("C:\\OriginalApplication")
.AddJsonFile("appsettings.json")
.Build()).UseStartup<Startup>());
context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
context.SaveChanges();
var departmentDto = await departmentAppService.GetDepartmentById(2);
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
I am receiving this error:
Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService
Need to use Dependency injection in testing just like real application.
Original application does this. Answers below are not currently sufficient , one uses mocking which is not current goal, other answer uses Controller which bypass question purpose.
Note: IDepartmentAppService has dependency on IDepartmentRepository which is also injected in Startup class, and Automapper dependencies. This is why calling the whole startup class.
Good Resources:
how to unit test asp.net core application with constructor dependency injection
Dependency injection in Xunit project
You are mixing unit test with integration test. TestServer is for integration test and if you want to reuse Startup class to avoid register dependencies again, you should use HttpClient and make HTTP call to controller and action that use IDepartmentAppService.
If you want do unit test, you need to setup DI and register all needed dependencies to test IDepartmentAppService.
Using DI through Test Fixture:
public class DependencySetupFixture
{
public DependencySetupFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDbContext<SharedServicesContext>(options => options.UseInMemoryDatabase(databaseName: "TestDatabase"));
serviceCollection.AddTransient<IDepartmentRepository, DepartmentRepository>();
serviceCollection.AddTransient<IDepartmentAppService, DepartmentAppService>();
ServiceProvider = serviceCollection.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
public class DepartmentAppServiceTest : IClassFixture<DependencySetupFixture>
{
private ServiceProvider _serviceProvide;
public DepartmentAppServiceTest(DependencySetupFixture fixture)
{
_serviceProvide = fixture.ServiceProvider;
}
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
using(var scope = _serviceProvider.CreateScope())
{
// Arrange
var context = scope.ServiceProvider.GetServices<SharedServicesContext>();
context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
context.SaveChanges();
var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();
// Act
var departmentDto = await departmentAppService.GetDepartmentById(2);
// Arrange
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
Using dependency injection with unit test is not good idea and you should avoid that. by the way if you want don't repeat your self for registering dependencies, you can wrap your DI configuration in another class and use that class anywhere you want.
Using DI through Startup.cs:
public class IocConfig
{
public static IServiceCollection Configure(IServiceCollection services, IConfiguration configuration)
{
serviceCollection
.AddDbContext<SomeContext>(options => options.UseSqlServer(configuration["ConnectionString"]));
serviceCollection.AddScoped<IDepartmentRepository, DepartmentRepository>();
serviceCollection.AddScoped<IDepartmentAppService, DepartmentAppService>();
.
.
.
return services;
}
}
in Startup class and ConfigureServices method just useIocConfig class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
IocConfig.Configure(services, configuration);
services.AddMvc();
.
.
.
if you don't want use IocConfig class, change ConfigureServices in Startup class:
public IServiceCollection ConfigureServices(IServiceCollection services)
{
.
.
.
return services;
and in test project reuse IocConfig or Startup class:
public class DependencySetupFixture
{
public DependencySetupFixture()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true));
configuration = builder.Build();
var services = new ServiceCollection();
// services = IocConfig.Configure(services, configuration)
// or
// services = new Startup(configuration).ConfigureServices(services);
ServiceProvider = services.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
and in test method:
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
using (var scope = _serviceProvider.CreateScope())
{
// Arrange
var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();
// Act
var departmentDto = await departmentAppService.GetDepartmentById(2);
// Arrange
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
Use Custom Web Application Factory and ServiceProvider.GetRequiredService below, feel free to edit and optimize the answer
CustomWebApplicationFactory:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((hostingContext, configurationBuilder) =>
{
var type = typeof(TStartup);
var path = #"C:\\OriginalApplication";
configurationBuilder.AddJsonFile($"{path}\\appsettings.json", optional: true, reloadOnChange: true);
configurationBuilder.AddEnvironmentVariables();
});
// if you want to override Physical database with in-memory database
builder.ConfigureServices(services =>
{
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
services.AddDbContext<ApplicationDBContext>(options =>
{
options.UseInMemoryDatabase("DBInMemoryTest");
options.UseInternalServiceProvider(serviceProvider);
});
});
}
}
Integration Test:
public class DepartmentAppServiceTest : IClassFixture<CustomWebApplicationFactory<OriginalApplication.Startup>>
{
public CustomWebApplicationFactory<OriginalApplication.Startup> _factory;
public DepartmentAppServiceTest(CustomWebApplicationFactory<OriginalApplication.Startup> factory)
{
_factory = factory;
_factory.CreateClient();
}
[Fact]
public async Task ValidateDepartmentAppService()
{
using (var scope = _factory.Server.Host.Services.CreateScope())
{
var departmentAppService = scope.ServiceProvider.GetRequiredService<IDepartmentAppService>();
var dbtest = scope.ServiceProvider.GetRequiredService<ApplicationDBContext>();
dbtest.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
dbtest.SaveChanges();
var departmentDto = await departmentAppService.GetDepartmentById(2);
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
Resources:
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
https://fullstackmark.com/post/20/painless-integration-testing-with-aspnet-core-web-api
When you are testing. You need to use mocking libraries or Inject your service directly on contructor ie.
public DBContext context;
public IDepartmentAppService departmentAppService;
/// Inject DepartmentAppService here
public DepartmentAppServiceTest(DepartmentAppService departmentAppService)
{
this.departmentAppService = departmentAppService;
}
In an extension method called from ConfigureServices I'm adding an instance of EmbeddedFileProvider to RazorViewEngineOptions. I'd like to test that it gets added but I can't find how to get the RazorViewEngineOptions instance.
This works when the application is run:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddMyServices(Configuration);
}
public static IServiceCollection AddMyServices(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(typeof(MyClass).Assembly, "My.Namespace"));
});
return services;
}
But how do I test it? A NullReferenceException is thrown here:
[Fact]
public void MyTest()
{
var services = new ServiceCollection();
var serviceProvider = services.BuildServiceProvider();
MyServicesBuilder.AddMyServices(services, new Mock<IConfiguration>().Object);
var razorOptions = serviceProvider.GetService<IOptions<RazorViewEngineOptions>>();
Assert.Equal(1, razorOptions.Value.FileProviders.Where(x => x.GetType() == typeof(EmbeddedFileProvider)).Count());
}
I have tried adding services.AddMvc() or services.AddSingleton<RazorViewEngineOptions>().
I've also tried calling services.GetRequiredService<RazorViewEngineOptions>() but that throws System.InvalidOperationException : No service for type 'Microsoft.Extensions.Options.IOptions'1[Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions
I've also tried asking for RazorViewEngineOptions rather than IOptions<RazorViewEngineOptions>.
Anything added to the service collection after the provider has already been built, wont be known to the provider.
Added everything needed to the service collection and only then build the provider to perform your assertions
For example
[Fact]
public void MyTest() {
//Arrange
var services = new ServiceCollection();
services.AddOptions();
IConfiguration config = new ConfigurationBuilder()
// Call additional providers here as needed.
//...
.Build();
//Act
MyServicesBuilder.AddMyServices(services, config);
//OR
//services.AddMyServices(config);
//Assert
var serviceProvider = services.BuildServiceProvider();
var razorOptions = serviceProvider.GetService<IOptions<RazorViewEngineOptions>>();
Assert.NotNull(razorOptions);
Assert.Equal(1, razorOptions.Value.FileProviders.Where(x => x.GetType() == typeof(EmbeddedFileProvider)).Count());
}
I am trying to use IHttpClientFactory in my solution instead of just instances of HttpClient.
startup.cs:
services.AddHttpClient("Test", client =>
{
client.BaseAddress = new Uri("http://localhost:57863");
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Clear();
});
and in my services in need of a HttpClient:
private readonly Uri _clusterLinuxUri;
private readonly IHttpClientFactory _clientFactory;
public LiasseService(ConfigSettings settings, IHttpClientFactory clientFactory)
{
_clusterLinuxUri = new Uri($"{settings.LinuxClusterEndpoint}");
_clientFactory = clientFactory;
}
public async Task<LiasseDetails> CreateLiasseAsync(LiasseCreate liasseData)
{
using (var response = await _clientFactory.CreateClient("Test")
.PostAsJsonAsync($"{_clusterLinuxUri}{_createPath}", liasseData))
{
await response.CheckHttpError($"{nameof(CreateLiasseAsync)} - error in CL");
var detailsList = await response.Content.ReadAsAsync<LiasseDetailsList>();
return detailsList.Details.FirstOrDefault();
}
}
The part I haven't figured out is how to inject it in Autofac.
program.cs
private static void Main()
{
try
{
var builder = new ContainerBuilder();
builder.RegisterModule(new GlobalAutofacModule());
builder.RegisterServiceFabricSupport();
builder.RegisterStatelessService<FacadeCore>("xxx.FacadeCoreType");
using (builder.Build())
{
ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(FacadeCore).Name);
Thread.Sleep(Timeout.Infinite);
}
}
catch (Exception e)
{
ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
throw;
}
}
public class GlobalAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ConfigSettings>();
builder.RegisterType<PaymentService>().As<IPaymentService>();
builder.RegisterType<MailerService>().As<IMailerService>();
builder.RegisterType<LiasseService>().As<ILiasseService>();
builder.RegisterType<AnalyseFinanciereService>().As<IAnalyseFinanciereService>();
builder.RegisterType<ApimService>().As<IApimService>();
builder.RegisterType<UserRepository>().As<IUserRepository>();
builder.RegisterType<ApplicationProcessRepository>().As<IApplicationProcessRepository>();
builder.RegisterType<LiasseRepository>().As<ILiasseRepository>();
builder.RegisterType<CustomUserIdProvider>().As<IUserIdProvider>();
}
}
Am I supposed to create some custom client that implements IHttpClientFactory to be able to inject it? How should I do this? Any examples? Thanks.
Please see Interface documentation here
So to answer your question:
1) Using IServiceCollection from 'ConfigureServices' method call .AddHttpClient()
2) Create new Autofac container builder and populate it with IServiceCollection mentioned above
3) From ConfigureServices method return new AutofacServiceProvider
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient();
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
P.S.
Make sure to add - Autofac.Extensions.DependencyInjection nuget package, in order to be able to use AutofacServiceProvider class.
Apart from doing using a WebHostBuilder based solution similar to what you get when creating a vanilla Asp.Net Core Service Fabric project, you can alternatively just do this
public class HttpClientModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(_ =>
{
var services = new ServiceCollection();
services.AddHttpClient();
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
})
.As<IServiceProvider>()
.SingleInstance();
builder.Register(ctx =>
{
var scope = ctx.Resolve<IComponentContext>();
var provider = scope.Resolve<IServiceProvider>();
var factory = provider.GetService<IHttpClientFactory>();
return factory.CreateClient();
}).As<HttpClient>();
}
}