i want to inject the AuthenticationStateProvider into the DatabaseContext.
My Code looks like that:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddDbContextFactory<DatabaseContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("MyCon"));
options.EnableSensitiveDataLogging();
});
services.AddScoped<DatabaseContext>(p =>
p.GetRequiredService<IDbContextFactory<DatabaseContext>>()
.CreateDbContext());
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<DatabaseContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<MultilanguageIdentityErrorDescriber>();
}
public DatabaseContext : IdentityDbContext
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public DatabaseContext(DbContextOptions options, AuthenticationStateProvider authenticationStateProvider)
{
_authenticationStateProvider = authenticationStateProvider;
}
}
As soon as i start the App I run into the following error:
InvalidOperationException: Cannot resolve scoped service 'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider' from root provider.
in Startup.cs
{ options.UseSqlServer(Configuration.GetConnectionString("MyCon"));
options.EnableSensitiveDataLogging();
});
services.AddScoped<DatabaseContext>(p =>
p.GetRequiredService<IDbContextFactory<DatabaseContext>>()
.CreateDbContext());
What i am doing wrong?
Thanks for your help!
I found solution! From my view it is bug! Problem is because services.AddDbContextFactory is registered as Singleton. I create my own implementation of IDbContext factory and register it as Scoped. After this change everything’s works perfect. When I change registration scope of DbContextFactory to singleton, I get the error: GetAuthenticationStateAsync was called before SetAuthenticationState.
My DbContextFactory
public class BlazorContextFactory<TContext> : IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public BlazorContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
My StartUp
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ApplicationDbContext>();
services.AddScoped<IDbContextFactory<ApplicationDbContext>, BlazorContextFactory<ApplicationDbContext>>();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
Related
I am experiencing some issues with the AspNetCore.HealthChecks.UI package. I made the necessary settings in the Startup class of my API project, but when I access the endpoint to view the HealthCheck interface, only a JSON is displayed.
My HealthCheck UI
My project is on version 3.1 of .NET Core, in which I installed the following nuget packages:
AspNetCore.HealthChecks.UI v3.1.3
AspNetCore.HealthChecks.UI.Client v3.1.2
AspNetCore.HealthChecks.UI.InMemory.Storage v3.1.2
Microsoft.Extensions.Diagnostics.HealthChecks v5.0.9
Below is the extension method in which I use the HealthCheck settings:
public static IServiceCollection AddHealthCheckConfiguration(
this IServiceCollection services,
IConfiguration configuration)
{
string mongoConnectionString = configuration.GetSection("MongoSettings").GetSection("Connection").Value;
string mongoDatabaseName = configuration.GetSection("MongoSettings").GetSection("DatabaseName").Value;
string redisConnectionString = configuration.GetConnectionString("Redis");
services
.AddHealthChecks()
.AddRedis(redisConnectionString)
.AddMongoDb(mongoConnectionString, mongoDatabaseName: mongoDatabaseName);
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15);
opt.MaximumHistoryEntriesPerEndpoint(60);
opt.SetApiMaxActiveRequests(1);
opt.AddHealthCheckEndpoint("default api", "/api-health");
})
.AddInMemoryStorage();
return services;
}
And in another extension method I add the necessary settings for displaying the interface:
public static IApplicationBuilder UseMvcConfiguration(this IApplicationBuilder app)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHealthChecks("/api-health", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecksUI();
});
return app;
}
Finally, my Startup class looks like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddApiResponseCompressionConfig();
services.AddApiCachingConfig(Configuration);
services.AddHateoasConfig();
services.AddMongoDbConfig();
services.AddAutoMapper(typeof(Startup));
services.AddWebApiConfig();
services.AddHealthCheckConfiguration(Configuration);
services.ResolveGeneralDependencies();
services.ResolveRepositories();
services.ResolveApplicationServices();
services.AddSwaggerConfig();
}
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IApiVersionDescriptionProvider provider)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ExceptionMiddleware>();
app.UseHealthChecks("/healthcheck");
app.UseMvcConfiguration();
app.UseSwaggerConfig(provider);
}
}
I searched for similar errors here on StackOverflow, but none of the answers I found solved my problem.
Thanks to #fbede help, I managed to solve the problem with the question.
I wasn't correctly mapping the healthcheck generation endpoints and the monitoring interface itself.
It was necessary to make adjustments to the code I presented in the question, starting with my extension method:
public static IServiceCollection AddHealthCheckConfiguration(
this IServiceCollection services,
IConfiguration configuration)
{
string mongoConnectionString = configuration.GetSection("MongoSettings").GetSection("Connection").Value;
string mongoDatabaseName = configuration.GetSection("MongoSettings").GetSection("DatabaseName").Value;
services
.AddHealthChecks()
.AddMongoDb(mongoConnectionString, mongoDatabaseName: mongoDatabaseName);
services.AddHealthChecksUI().AddInMemoryStorage();
return services;
}
And ending with the Configure method of my Startup class:
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IApiVersionDescriptionProvider provider)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHealthChecks("/healthcheck", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecksUI(options =>
{
options.UIPath = "/healthchecks-ui";
options.ApiPath = "/health-ui-api";
});
app.UseMiddleware<ExceptionMiddleware>();
app.UseMvcConfiguration();
app.UseSwaggerConfig(provider);
}
}
Also, I removed the following unnecessary configuration:
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/api-health", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecksUI();
});
These fixes led to the expected loading of the interface:
I'm trying to replicate a working app and when I refactor the whole thing I'm getting
[Error] Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer: Connection ID "17726168147825789580", Request ID "80000a8e-0003-f600-b63f-84710c7967bb":
An unhandled exception was thrown by the application.System.InvalidOperationException:
Unable to resolve service for type 'Projects.Models.DatabaseContext' while attempting to activate 'Projects.Controllers.BoxDetailController'.at
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
Aa
Here's my DBcontext:
namespace Projects.Models
{
public class DatabaseContext: DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
}
public DbSet<BoxDetail> BoxDetails { get; set; }
}
}
Here's my controller:
namespace Projects.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BoxDetailController : ControllerBase
{
private readonly DatabaseContext _context;
public BoxDetailController(DatabaseContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<BoxDetail>>> GetBoxDetails()
{
return await _context.BoxDetails.ToListAsync();
}
}
}
and my startup class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddJsonOptions(options =>
{
var resolver = options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
services.AddCors();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(options =>
options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
try adding this to ConfigureServices() :
services.AddMvc()
.AddControllersAsServices();
I am getting an error when trying to call the controller below using Lamar to resolve the dependencies at runtime.
I have tried .AddControllersAsServices() and without and still get the same result.
Using
ASP.NET Core: 3.1
Lamar
Container.GetInstance<IDataAccess>() works inside the watch window but will not resolve at runtime
Container.WhatDoIHave() also shows that the dependency is there
Question?
What am I missing in Lamar configuration to resolve the controllers?
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IDataAccess _dataAccess;
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(IDataAccess dataAccess, ILogger<WeatherForecastController> logger)
{
_dataAccess = dataAccess;
}
[HttpGet]
public IEnumerable<string> Get()
{
return _dataAccess.GetAll();
}
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IContainer Container { get; private set; }
public void ConfigureContainer(ServiceRegistry services)
{
Container = new Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
a.FullName.Contains("Test3.1"));
scanner.WithDefaultConventions();
scanner.SingleImplementationsOfInterface();
});
});
services
.AddControllers(options =>
{
// Disable automatic fallback to JSON
options.ReturnHttpNotAcceptable = true;
// Honor browser's Accept header (e.g. Chrome)
options.RespectBrowserAcceptHeader = true;
})
.AddControllersAsServices();
services.AddMvc()
.AddControllersAsServices();
Container.WhatDidIScan();
Container.WhatDoIHave();
Console.Write("Container Instantiated");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseLamar()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
});
}
An unhandled exception occurred while processing the request.
LamarException: Cannot build registered instance weatherForecastController of 'Test3._1.Controllers.WeatherForecastController':
Cannot fill the dependencies of any of the public constructors
Available constructors:new WeatherForecastController(IDataAccess dataAccess, ILogger<Test3._1.Controllers.WeatherForecastController> logger)
* IDataAccess is not registered within this container and cannot be auto discovered by any missing family policy
The error message indicates that the container can't resolve the controller's dependencies. Make sure those dependencies are registered with the container so it knows how to resolve them when activating controllers.
This is because separate containers are being configured in Startup and the one used by the framework is unaware of IDataAccess as the Scan was not applied to its container.
Reference Lamar - Integration with ASP.Net Core
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
//REMOVED IContainer. It is not needed
public void ConfigureContainer(ServiceRegistry services) {
//Apply scan to the registry used by framework so container is aware of types.
services.Scan(scanner => {
scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
a.FullName.Contains("Test3.1"));
scanner.WithDefaultConventions();
scanner.SingleImplementationsOfInterface();
});
services
.AddControllers(options => {
// Disable automatic fallback to JSON
options.ReturnHttpNotAcceptable = true;
// Honor browser's Accept header (e.g. Chrome)
options.RespectBrowserAcceptHeader = true;
})
.AddControllersAsServices();
services.AddMvc()
.AddControllersAsServices();
services.WhatDidIScan();
services.WhatDoIHave();
Console.Write("Container Instantiated");
}
//...omitted for brevity
}
I am working in asp.net signal core under asp.net core 2.2, i want to inject dependency in hub constructor, how i can do this?
I made it generic,to pass parameter on constructor.
My Hub:
public class IntegratedHUB : Hub<IIntegratedHubClient>
{
private readonly AuthorizeConnection _authorizeConnection = new AuthorizeConnection();
private readonly ISignalRIdentity _signalRIdentity;
private readonly IVideoService _videoService;
public IntegratedHUB(ISignalRIdentity signalrIdentity, IVideoService videoService)
{
_signalRIdentity = signalrIdentity;
_videoService = videoService;
}
}
My Start up class
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var _unitofWork = new UnitOfWork(new DbFactory());
var _SignalrIdentity = new SignalRIdentity(_unitofWork, new UnitOfWork(new DbFactory()));
var _videoService = new VideoService(_unitofWork, new UnitOfWork(new DbFactory()));
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.SetIsOriginAllowed((host) => true)/*WithOrigins("https://localhost:44381")*/
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddTransient<IntegratedHUB, IntegratedHUB>(); // how i change it?
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<IntegratedHUB>("/integratedHUB");
});
app.UseHttpsRedirection();
app.UseMvc();
}
How i can inject dependency in hub constructor?
I'm getting a 500 error when I try access an object I've injected using services.AddSingleton<>() in the ConfigureServices method in Startup.cs:
Could not resolve a service of type proj.Auth.IAuthProvider for the parameter authProvider of method Configure on type proj.Startup.
As far as I can tell from looking at "working" code samples this should be working...
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AppSettings>(Configuration);
services.AddSingleton<IAuthProvider, TranslatorAuthProvider>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IAuthProvider authProvider)
{
...
app.Run(async context =>
{
await authProvider.GetToken();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
TranslatorAuthProvider.cs:
namespace proj.Auth
{
public class TranslatorAuthProvider : IAuthProvider
{
public TranslatorAuthProvider(IHttpContextAccessor httpContextAccessor, IOptions<AppSettings> settings)
{
...
}
public async Task<OAuthToken> GetToken()
{
...
}
}
}
IAuthProvider.cs:
namespace proj.Auth
{
public interface IAuthProvider
{
Task<OAuthToken> GetToken();
}
}
Yes that's expected. It fails to resolve IHttpContextAccessor, because the IHttpContextAccessor is not registered by default since recently (see #190)
You should register it manually in ConfigureServices() like so
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();