J.C
J.C

Reputation: 752

How to pass IHttpContextAccessor in startup in ASP.NET CORE

I would like to pass IHttpContextAccessor in the startup class. Here is my startup page.

    public class Startup
    {
        public Startup(IConfiguration configuration, IHttpContextAccessor httpContext)
        {
            Configuration = configuration;
            HttpContext = httpContext;
        }

        public IConfiguration Configuration { get; }
        public IHttpContextAccessor HttpContext { get; }
}

However I get this error

Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'project_name.Startup'.'

Here is my objective I want to passs htppcontext in DatabaseInterceptor.

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<ApplicationSettings>(Configuration.GetSection("AppSettings"));

            services.AddTransient<DatabaseMigrator>();
            services.AddScoped<TenantInfo>();
            services.UseSchemaPerTenant(Configuration);

            TenantInfo tenantInfo = new TenantInfo();
            tenantInfo.Name = "erp_colombia";

            services.AddDbContext<erp_colombiaDbContext>(options => options.UseMySql(
                     Configuration.GetConnectionString("DefaultConnection")).AddInterceptors(new DatabaseInterceptor(tenantInfo, HOW_CAN_I_GET_HTTP_CONTEXT_HERE)));
        }

What must I do to fix this issue. Thank you

Upvotes: 0

Views: 2094

Answers (2)

t.ouvre
t.ouvre

Reputation: 2981

One way to achieve the result you want is to configure EFCore to use the same service provider you use. I don't know how to do that with the mysql provider (maybe you should add the nuget package you use), but I already done something similar with sqlserver provider.

First, your interceptor, if it is an IDCommandInterceptor has a parameter in each method of type CommandEventData. This parameter hold a reference to your DbContext, wich can resolve services. So you can write an interceptor like this one :

public class Interceptor : IDbCommandInterceptor
{
    public DbCommand CommandCreated(CommandEndEventData eventData, DbCommand result)
    {
        var httpContextAccessor = eventData.Context.GetService<IHttpContextAccessor>();
        var request = httpContextAccessor.HttpContext.Request;
        var url = request.GetDisplayUrl();
        Console.WriteLine(url);
        return result;
    }
}

Then, when you register your services, you must not use AddDbContext, you have to fill your service collection with the internal stuff required by your provider (for SQLServer the method is AddEntityFrameworkSqlServer) and configure manually the service corresponding to your DbContext:

services.AddHttpContextAccessor();
services.AddEntityFrameworkSqlServer();
services.AddScoped(sp =>
{
    var dbContextOptions = new DbContextOptionsBuilder<AppContext>()
        .UseSqlServer("your connection string")
        .UseApplicationServiceProvider(sp)
        .UseInternalServiceProvider(sp)
        .AddInterceptors(new Interceptor())
        .Options;
    return new AppContext((DbContextOptions<AppContext>)dbContextOptions);
});

Upvotes: 3

Jason Pan
Jason Pan

Reputation: 21916

From the perspective of your code, the code in Startup also needs to pay attention to the following.

ConfigureServices is used to register services and needs to be added for your needs.

services. AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

In Configure, you can use IHttpContextAccessor directly. As follows:

namespace WebApplication8
{
    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.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddRazorPages();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHttpContextAccessor httpContext)
        {
            // make use of it here
            // HttpContextAccessor
            //
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            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.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
    }
}

Upvotes: 0

Related Questions