Api Exception filters for autofac - c#

I have Configured webapi with IAutofacExceptionFilter to get the Exception Details. registered all the things in autofac.config
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options, (configuration, builder) =>
{
builder.RegisterType<ErrorLoggingExceptionFilter>()
.AsWebApiExceptionFilterFor<BaseController>()
.InstancePerApiRequest();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
//builder.RegisterType<ErrorLoggingExceptionFilter>()
//.AsWebApiExceptionFilterFor<BaseController>().SingleInstance();
builder.OverrideWebApiActionFilterFor<BaseController>();
builder.RegisterSource(
new AnyConcreteTypeNotAlreadyRegisteredSource(t =>
!(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Meta<>))
));
}
var serviceResolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
but it gives me error like
The AutofacWebApiDependencyResolver must be configured as the dependency resolver for Web API before the AutofacControllerConfigurationAttribute can resolve services from the container for a controller type.

You should do something like this to make AutofacWebApiDependencyResolver your default Web API dependency resolver :
// Set the dependency resolver to be Autofac.
var builder = new ContainerBuilder();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
See Autofac documentation for more info.

Related

Accessing a service before BuildServiceProvider

Im failing to build the following service, since configStoreService need to be injected to the AddInMemoryConfiguration, ConfigurationBuilder. So, is there a way to retrieve configStoreService and use it before building the service provider.
var services = new ServiceCollection();
var configStoreService = services.AddSingleton<ConfigurationStore>();
var configuration = new ConfigurationBuilder()
.AddInMemoryConfiguration(configStoreService)
.Build();
services.AddOptions();
services.Configure<Temp>(configuration.GetSection(typeof(Temp).Name));
services.RegisterOptionsType<Temp>(configuration);
_serviceProvider = services.BuildServiceProvider();
Foreword:
This seems a problematic request. You need configuration to configure services, but you need to configure services to get configuration. A chicken and egg problem.
What to do:
Create an instance of configuration use it to configure your services and also add it to your service collection
var configStoreService = new ConfigurationStore(location, sku);
services.AddSingleton(configStoreService);
var configuration = new ConfigurationBuilder()
.AddInMemoryConfiguration(configStoreService)
.Build();
services.AddOptions();
services.Configure<Temp>(configuration.GetSection(typeof(Temp).Name));
services.RegisterOptionsType<Temp>(configuration);
_serviceProvider = services.BuildServiceProvider();
FYI:
I also have to add you can't get anything from a IServiceCollection. You can get things from IServiceProviderwhich, you get AFTER registration is done and BuildServiceProvider called. So before that you can't access items in the collection.

.NET Core Identity How to set option value based on database

I need to change parameter value for IdentityOptions dynamically from db. So, in my ConsigureServices(...) method in Startup.cs:
services.AddIdentity<AppUser, IdentityRole>(option =>
{
option.Lockout.MaxFailedAccessAttempts = 3; // I need to set this value dynamically from database when server starts
}).AddEntityFrameworkStores<DataContext>()
.AddDefaultTokenProviders();
I have tried to inject IdentityOptions in my Configure(...) method but with no success:
public void Configure(
IApplicationBuilder app,
DataContext dataContext,
IdentityOptions identityOptions)
{
var sysPolicy = dataContext.SysPolicy.FirstOrDefault();
identityOptions.Lockout.MaxFailedAccessAttempts = sysPolicy.DisablePwdLoginFail;
}
It throws an exception like this (it seems that I can't inject it on my Configure):
System.Exception: Could not resolve a service of type 'Microsoft.AspNetCore.Identity.IdentityOptions' for the parameter 'identityOptions' of method 'Configure' on type 'App.Startup'.
You can try out this:
services.AddIdentity<AppUser, IdentityRole>(
options =>
{
var scopeFactory = services.BuildServiceProvider().GetRequiredService<IServiceScopeFactory>();
using var scope = scopeFactory.CreateScope();
var provider = scope.ServiceProvider;
using var dataContext = provider.GetRequiredService<DataContext>();
options.Lockout.MaxFailedAccessAttempts = dataContext.SysPolicy.FirstOrDefault();
})
.AddEntityFrameworkStores<DataContext>()
.AddDefaultTokenProviders();
NOTE: Building a service provider is an antipattern and will result in creating an additional copy of singleton services. I would suggest reading the configs from appsettings.json for example, then you can implement it without building the service provider

Inject IServiceProvider using ServiceProvider into SignInManager

I've made some research, and there isn't much info about registering standard classes for manual DI. Experiencing lots of issues trying to implement unit tests in asp net core 2.1 app, here is the last one. Getting null refrence exception when trying to SignInAsync user created by UserManager - it seems it can't inject IServiceProvider instance
var userManager = Resolve<UserManager<ApplicationUser>>();
await signInManager.SignInAsync(userManager.FindByIdAsync(adminId), false); // here
Value cannot be null.
Parameter name: provider
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Identity.SignInManager1.SignInAsync(TUser user, AuthenticationProperties authenticationProperties, String authenticationMethod)
at UnitTests.TestBase1.ConfigureIdentity() in C:\Users\alexa\source\repos\octopusstore\UnitTests\TestBase.cs:line 72
resolving like this
protected static ServiceCollection services = new ServiceCollection();
protected T Resolve<T>()
{
var serviceProvider = services.BuildServiceProvider();
return serviceProvider.GetRequiredService<T>();
}
how I am registering dependencies, it worked so far
services.AddDbContext<AppIdentityDbContext>();
var conf = new Mock<IConfiguration>();
services.AddSingleton<IConfiguration>(conf.Object);
services.AddSingleton<IServiceProvider, ServiceProvider>() ; // except for this
services.AddSingleton(services.BuildServiceProvider()); // and this
services.AddScoped<SignInManager<ApplicationUser>> ();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddScoped<IAuthorizationService, DefaultAuthorizationService> ();
services.AddScoped<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>();
services.AddScoped<IAuthorizationHandlerProvider, DefaultAuthorizationHandlerProvider>();
services.AddScoped<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>();
services.AddScoped<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>();
interesting that UserManager worked fine
To register the service provider itself, you can do it like this:
services.AddSingleton<IServiceProvider>(sp => sp);
This uses the factory function which you can use to get an instance using the service provider sp. Since you want to register the service provider itself, you can just return sp directly.

Autofac does not pass a instance of object Resolved using xml (Refection API) in web API

I have a webapi controller where in the constructor has 2 parameters. I am using the autofac as the DI container. The RegisterAutofac() is the function called in the global.asax of the web api project
private static void RegisterAutofac()
{
var builder = new ContainerBuilder();
// Register the Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// get the first param via xml
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
// get the 2nd param directly
builder.Register(c => new Assets()).As<IAssets>().InstancePerLifetimeScope();
// Build the container.
var container = builder.Build();
// Create the depenedency resolver.
var resolver = new AutofacWebApiDependencyResolver(container);
// Configure Web API with the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver = resolver;
//Register Autofac ends
}
When I run the controller , i can see that the first param is null and the 2nd one has a valid value. In the debug mode, I can verify that the first param ( using container.Resolve<>() ) has a valid value . Not sure why the autofac does not pass the dependency as a valid object to the controller when it is able to resolve it in the global.asax.

Register autofac in windows service project

I want to use autofac in my project for windows service but I get this error:
"The requested service 'InsideView.Business.Services.BusinessServiceFactory' 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."
My code:
var builder = new ContainerBuilder();
foreach (var type in typeof(IMyService).Assembly.GetTypes().Where(type => type.Name.EndsWith("Service") && type.IsClass))
{
var siblingInterface = type.GetInterfaces().First(i => i.Name == "I" + type.Name);
builder.RegisterType(type).Keyed(siblingInterface, typeof(IBusinessService)).InstancePerLifetimeScope();
}
builder.RegisterType<BusinessServiceFactory>()
.As<IBusinessServiceFactory>().InstancePerLifetimeScope();
IContainer container = builder.Build();
var businessFactory = container.Resolve<BusinessServiceFactory>()
Any ideas?
Thanks
When you have registered the service as IBusinessServiceFactory you must also resolve for IBusinessServiceFactory, not the class type BusinessServiceFactory as you are doing in the sample.

Categories