【问题标题】:how to access IApplicationBuilder in a controller?如何在控制器中访问 IApplicationBuilder?
【发布时间】:2019-08-23 00:47:41
【问题描述】:

只是想知道,是否可以在 startup.cs 之外访问 IApplicationBuilder 属性?就像在控制器中一样?

我知道它只用于定义应用程序管道,那么解决方案是什么?比如注册一个打包实例的服务,然后注入服务而不是 IApplicationBuilder?

我正在尝试从 Autofac 取回我的 DbConext。代码如下:

Business 项目中:

 public class AutofacBusinessModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterModule(new AutofacDataModule());
        }
    }

在数据项目中:

 public class AutofacDataModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<AppDbContext>().InstancePerLifetimeScope();
        }
    }

DbContext

public class AppDbContext : DbContext
    {
        private const string DbContextName = "AppDbConnectionString";
        public DbSet<Contest> Contests { get; set; }

        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {
        }

        public AppDbContext()
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (optionsBuilder.IsConfigured) return;

            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();
            var connectionString = configuration.GetConnectionString(DbContextName);
            optionsBuilder.UseSqlServer(connectionString,
                x => x.MigrationsAssembly("Cri.CodeGenerator.Data"));
        }

        public virtual void Commit()
        {
            base.SaveChanges();
        }
    }

还有 ConfigureServices 在 Web 项目中的 startup.cs

public IServiceProvider 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;
    });

    var builder = new ContainerBuilder();

   builder.RegisterModule(new AutofacBusinessModule());


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

    services.AddScoped(sp => {
        var actionContext = sp.GetRequiredService<IActionContextAccessor>().ActionContext;
        var urlHelperFactory = sp.GetRequiredService<IUrlHelperFactory>();
        var urlHelper = urlHelperFactory.GetUrlHelper(actionContext);
        return urlHelper;
    });

    services.AddDistributedMemoryCache();
    builder.Populate(services);

    ApplicationContainer = builder.Build();

    //return the IServiceProvider implementation
    return new AutofacServiceProvider(ApplicationContainer);

}

我肯定遗漏了一些东西,但在 DI 和 .net 核心方面确实是新手...

-- 编辑--

在我的Controller

  private readonly IHostingEnvironment _hostingEnvironment;
        private readonly IApplicationBuilder _app;


        private const int NumberOfCharactersRepetion = 4;

        public UniqueCodesController(IHostingEnvironment hostingEnvironment, IApplicationBuilder app)
        {
            _hostingEnvironment = hostingEnvironment;
            _app = app;
        }

...

if (selectedAnswer == FileExtension.XLSX.GetStringValue())
                {
                    await FilesGenerationUtils.GenerateExcelFile(_app, uniqueCodesHashSet, model);
                }

GenerateExcelFile 方法中:

public static async Task GenerateExcelFile(IApplicationBuilder app, IEnumerable<string> hashSetCodes, ContestViewModel model)
        {
...

 try
                    {
                        var context = app.ApplicationServices.GetRequiredService<AppDbContext>();

                        var contest = new Contest
                        {
                            Name = model.ProjectName,
                            UserId = 1,
                            FileGenerationStatus = true,
                            FilePath = fileInfo.FullName
                        };
                        context.Contests.Add(contest);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

}

但是当我运行应用程序时,我收到了这条消息:

InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Builder.IApplicationBuilder' while attempting to activate 'Cri.CodeGenerator.Web.Controllers.UniqueCodesController'.

【问题讨论】:

  • 通常当你在 DI 中注册了一些东西时,你将它作为参数添加到构造函数中,所以在这种情况下你的控制器的构造函数。
  • 通常你会把依赖放在控制器的构造函数中,让DI容器解决它。那不工作吗?您到底在哪里认为需要 IApplicationBuilder?你还没有展示这个,所以理解这个问题有点困难。如果您尝试过但没有成功,请提供更多详细信息,例如是否存在异常或其他一些意外行为?乍一看,这里的一切看起来都很合理。
  • @MikeZboray 我刚刚更新了原始帖子,以显示我正在尝试做的事情以及尝试时得到的结果。谢谢你的时间:)

标签: c# asp.net-core dependency-injection autofac


【解决方案1】:

听起来您正在尝试获取AppDbContext 的新实例。

如果您必须将GenerateExcelFile() 保留为static 并希望通过参数重用AppDbContext,则可以使其接受AppDbContext 的实例而不是IApplicationBuilder

首先,直接注入这样一个服务实例:

    private readonly IHostingEnvironment _hostingEnvironment;
    private readonly AppDbContext _dbContext;

    // ...

    public UniqueCodesController(IHostingEnvironment hostingEnvironment, AppDbContext dbContext)
    {
        _hostingEnvironment = hostingEnvironment;
        _dbContext = dbContext;
    }

然后将GenerateExcelFile()改成接受AppDbContext的参数

public static async Task GenerateExcelFile(IApplicationBuilder app, IEnumerablehashSetCodes, ContestViewModel model) 公共静态异步任务 GenerateExcelFile(AppDbContext dbContext, IEnumerable hashSetCodes, ContestViewModel 模型) { ... 尝试{ var context = app.ApplicationServices.GetRequiredService(); var 竞赛 = 新竞赛 { 名称 = 模型.项目名称, 用户 ID = 1, FileGenerationStatus = true, FilePath = fileInfo.FullName }; context.Contests.Add(contest); context.Contests.Add(contest); } 捕捉(例外前) { Console.WriteLine(ex.Message); } }

最后,你可以像下面这样调用它:

    await FilesGenerationUtils.GenerateExcelFile(_dbContext, uniqueCodesHashSet, model);

附带说明,如果您无法在编译时确定所需的类型,并且想要动态解析某些服务类型,您可以注入IServiceProvider 而不是IApplicationBuilder。这样,您可以根据需要解析任何实例:

    var dbContext= sp.GetRequiredService<AppDbContext>();
    // or if you need a service only available within a scope 
    using(var scope = this._sp.CreateScope()){
        var _anotherDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        ...
    }

以您的代码为例,您可以将IServiceProvider 传递给GenerateExcelFile(IServiceProvider sp, IEnumerable&lt;string&gt; hashSetCodes, ContestViewModel model),在GenerateExcelFile() 方法中,您可以通过以下方式解析AppDbContext

    public static async Task GenerateExcelFile(IServiceProvider sp, IEnumerable<string> hashSetCodes, ContestViewModel model)
    {
        ...

        var dbContext= sp.GetRequiredService<AppDbContext>();

        try{
            var contest = new Contest
            {
                Name = model.ProjectName,
                UserId = 1,
                FileGenerationStatus = true,
                FilePath = fileInfo.FullName
            };

            dbContext.Contests.Add(contest);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }

【讨论】:

  • 哇,这是一个结构良好的答案,非常感谢!正如你所提到的,我已经尝试注入一个IServiceProvider,以解决AppDbContext,但是当涉及到dbContext.Contests.Add(contest);,我得到了这个System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\Program Files\IIS Express\appsettings.json'. ...有什么线索吗?
  • @j0w 我注意到您假设appsettings.json 在 IIS 中运行时驻留在当前目录中。出于某种原因,您的当前目录是'C:\Program Files\IIS Express。我认为不会有C:\Program Files\IIS Express\appsettings.json 文件。结果,它抛出。如果没有代码,我不确定为什么您的当前目录更改为C:\Program Files\IIS Express。但是,可以使用Assembly.GetExecutingAssembly().Location 获取基准位置。
  • 只要发现我在IIS 而不是web project 上启动项目,这就是为什么该目录不是好的目录。现在,我将启动 Web 项目,稍后我会尝试通过 IIS 从那里取回 appsettings.json,如果可能的话。非常感谢您的帮助!
【解决方案2】:

不,据我所知这是不可能的。

您必须编写一个中间件(或一些其他代码)来将数据从 IApplicationBuilder 获取到 HttpContext 实例。

然后您可以从控制器内部访问 HttpContext 实例。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    相关资源
    最近更新 更多