In ASP.NET Core I have a service that is registered in DI as scoped. Can I access the HTTP context in that service without using IHttpContextAccessor and the overhead it has?
You'd have to add a scoped service to the container, then you'd have to add a middleware that resolved that service and set the current http context on it.
public class ScopedHttpContext
{
public HttpContext HttpContext { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ScopedHttpContext>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<ScopedHttpContextMiddleware>();
}
public class ScopedHttpContextMiddleware
{
private readonly RequestDelegate _next;
public ScopedHttpContextMiddleware(RequestDelegate next)
{
_next = next;
}
public Task InvokeAsync(HttpContext context, ScopedHttpContext scopedContext)
{
scopedContext.HttpContext = context;
return _next(context);
}
}
Related
I have this middleware class when I want to show a List<string> in the output:
namespace WebAspNetCore2_1
{
public class LearningMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<LearningMiddleware> _logger_log;
private readonly List<string> logger;
public LearningMiddleware(RequestDelegate next,ILogger<LearningMiddleware> logger_log)
{
_next = next;
_logger_log = logger_log;
List<string> _logger = new List<string>
{
("EUR/USD"),
("1.0500")
};
logger = _logger;
}
public Task Invoke(HttpContext httpContext)
{
_logger_log.Log(Microsoft.Extensions .Logging.LogLevel.Information,"information of logger",logger[0]);
return _next(httpContext);
}
}
}
I have debugged my code but seen to be correct, my List<> is filled, I don't know why the compiler is throwing this exception:
InvalidOperationException: Could not create an instance of type Microsoft.Extensions.Logging.ILogger`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'logger' parameter a non-null default value.
i thought was the order declaration in StartUp, but not
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// app.UseLearningMiddleware();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMiddleware<LearningMiddleware>();
app.UseMvc();
}
link in video for detail evidence: https://youtu.be/2FoLvhLweYo
I tested your code in my side but it worked well... I created a new asp.net core 2.1 MVC project and create a middleware. In StartUp.cs, I put app.UseMiddleware<MyMiddleware>(); just before app.UseMvc(routes =>
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace WebApplication2
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<MyMiddleware> _logger_log;
private readonly List<string> logger;
public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger_log)
{
_next = next;
_logger_log = logger_log;
List<string> _logger = new List<string>
{
("EUR/USD"),
("1.0500")
};
logger = _logger;
}
public Task Invoke(HttpContext httpContext)
{
_logger_log.Log(Microsoft.Extensions.Logging.LogLevel.Information, "information of logger", logger[0]);
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
}
is there a way to access HttpContext.session in a class library? (im using .Net Core 5)
I have the configuration all set up and also using microsoft.AspNetCore.Http but im still unable to access the session variables.
If there is no way to do that whats the best way to perform actions that require the current User's ID/Identification?
As #King King answered, you could inject the IHttpContextAccessor into the class.
Step 1 Add Session service
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSession();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
...
}
Step 2 Access Session in custom class
public class SessionTest
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SessionTest(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void setSession()
{
_session.SetString("Test", "Hello World!");
}
public void getSession()
{
var message = _session.GetString("Test");
...
}
}
Step 3 access session via custom class
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ISession _session;
public HomeController(IHttpContextAccessor httpContextAccessor,ILogger<HomeController> logger)
{
_logger = logger;
_httpContextAccessor = httpContextAccessor;
_session = _httpContextAccessor.HttpContext.Session;
}
public IActionResult Index()
{
SessionTest session = new SessionTest(_httpContextAccessor);
session.setSession();
session.getSession();
return View();
}
}
I get the error System.NullReferenceException. Object reference not set to an instance of an object. At Club.BLL.MaintenanceBLL.Maintenance.DoMaintenance()
But the context code is the same as on scaffolded pages, so not sure what I need to do. Any help is appreciated.
The code is:
namespace Club.BLL.MaintenanceBLL
{
public class Maintenance
{
private readonly Club.Data.ApplicationDbContext Context;
public Maintenance(ApplicationDbContext context)
IN DEBUG MODE context IS INDICATED
AS OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT.
HOW DO I FIX THIS.
{
Context = context;
}
public Maintenance()
{
}
public void DoMaintenance()
{
//Parse Maintenance table and action those items
//where Active=True and ActionDate has passed
//==================================
//Retrieve list of rows in Maintenance table
var maintenances = Context.Maintenance; PROGRAM FAILS ON THIS LINE.
I imagine I am missing something fundamental as I am 'learning by doing'. The lines that call up the DoMaintenance routine are located in root/Pages/Index, which is a scaffolded page. The DoMaintenance routine is called from the following lines in the root/Pages/index.cshtml page:
public void OnGet()
{
Maintenance maintenance = new Maintenance();//Create new instance
maintenance.DoMaintenance();
}
AND startup.cs includes the lines
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles()
.AddEntityFrameworkStores();
ANY HELP WOULD BE APPRECIATED.
Thanks and cheers....Alan
According to your description and codes, I found you have register the dbcontext as a service in your application that means if you want to use it, you should inject the dbcontext into your Maintenance class.
Normally, we will create a service as BLL service in asp.net core.
Then we could register the service in the startup.cs and inject it in the razor page.
I suggest you could try to modify the Maintenance class as below codes shows:
You could create a interface called IMaintenance:
public interface IMaintenance
{
public void DoMaintenance();
}
Then you could let Maintenance inherit IMaintenance as below:
public class Maintenance : IMaintenance
{
private readonly TestDbcontext Context;
public Maintenance(TestDbcontext testDbcontext ) {
Context = testDbcontext;
}
public void DoMaintenance() {
var maintenances = Context.Employees.ToList() ;
}
}
At last, you could register the Maintenance as service in startup.cs ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<TestDbcontext>(ServiceLifetime.Transient);
services.AddTransient<IMaintenance, Maintenance>();
}
You could directly use the Maintenance in razor pages like below, the asp.net core dependency injection will inject the dbcontext automatically into Maintenance.
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly IStringLocalizer<IndexModel> _localizer;
private readonly IMaintenance _maintance;
public CustomerModel Customer { get; set; }
public IndexModel(ILogger<IndexModel> logger, IStringLocalizer<IndexModel> localizer, IMaintenance maintance)
{
_logger = logger;
_localizer = localizer;
_maintance = maintance;
}
public void OnGet()
{
_maintance.DoMaintenance()
}
}
namespace Club.Pages
{
[AllowAnonymous]
public class IndexModel : PageModel
{
private readonly IMaintenance _maintenance;
public IndexModel (IMaintenance<IndexModel> maintenance)
{
_maintenance = maintenance;
}
public void OnGet()
{
_maintenance.DoMaintenance();
}
}
}
You might have missed to inject your context and since there's default ctor, everything works fine without setting Context property.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<Context>(() => ...));
}
This question already has answers here:
How to do DI in asp.net core middleware?
(2 answers)
Closed 2 years ago.
I have created an API Logging middleware to log request to DB and to Azure Microsoft insight however for some reason the Dependency Injection for the Database context is not found (gives cannot resolve scoped service from root provider).
API Logging MiddleWare
public class APILoggingMiddleware
{
private readonly TelemetryClient _telemetry;
private readonly ILogger _logger;
private readonly RequestDelegate _next;
private APIsAuditContext db;
public static IConfiguration _configuration;
public APILoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, TelemetryClient telemetry, IConfiguration configuration, APIsAuditContext dbContext)
{
_configuration = configuration;
_telemetry = telemetry;
_next = next;
_logger = loggerFactory.CreateLogger<APILoggingMiddleware>();
db = dbContext;
}
//static class to simplify adding the middleware to the application’s pipeline
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
finally
{
Task logReq = logRequest(context);
Task lodRes = logResponse(context);
}
}
}
DB Context
public class APIsAuditContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
public APIsAuditContext(DbContextOptions<APIsAuditContext> options) : base(options) { }
public DbSet<APIsRequestsAudit> APIsRequestsAudits { get; set; }
}
Startup
public class Startup
{
public IConfiguration _configuration { get; }
public Startup(IConfiguration configuration)
{
_configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<APIsAuditContext>(options => options.UseSqlServer(_configuration["ConnectionStrings:APIAuditConnection"]));
services.AddApplicationInsightsTelemetry();
services.AddControllers();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//Pipeline to API Logging
app.UseRequestResponseLogging();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Can someone help please?
As per https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1#per-request-middleware-dependencies, you must inject scoped service in the Invoke method:
public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
// IMyScopedService is injected into Invoke
public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
{
svc.MyProperty = 1000;
await _next(httpContext);
}
}
I want to validate AntiForgery token in ASP.NET Core application. I know i can individually do that by adding [AutoValidateAntiforgeryToken] or [ValidateAntiforgeryToken] attributes on Action methods as suggested in SO post here
I'm looking for global approach to validate token for all POST methods. So i created a middleware to do so. However i could not find suitable method to validate the token. Like in classic asp.net there is AntiForgery.Validate().
What's the equivalent method in ASP.NET Core
public class ValidateAntiForgeryTokenMiddleware
{
private readonly RequestDelegate _next;
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Method.ToUpper() == "POST")
{
// where does this mehod exists?
// i could not find it in Microsoft.AspNetCore.Antiforgery namespace
AntiForgery.Validate();
}
await _next(httpContext);
}
}
public static class ValidateAntiForgeryTokenMiddlewareExtensions
{
public static IApplicationBuilder UseValidateAntiForgeryToken(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ValidateAntiForgeryTokenMiddleware>();
}
}
I have to Inject Antiforgery as service
public class ValidateAntiForgeryTokenMiddleware
{
private readonly RequestDelegate _next;
private readonly IAntiforgery _antiforgery;
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
{
_next = next;
_antiforgery = antiforgery;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Method.ToUpper() == "POST")
{
await _antiforgery.ValidateRequestAsync(httpContext);
}
await _next(httpContext);
}
}
add Antiforgery as service in startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery();
}
Use my middlware
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
{
app.UseValidateAntiForgeryToken();
}