在ASP.NET5控制台应用程序中使用启动类

17

一个由ASP.NET控制台项目模板在VS2015中构建的ASP.NET 5-beta4控制台应用程序是否可以使用Startup类处理注册服务和设置配置细节?

我已经尝试创建一个典型的Startup类,但是当通过dnx . run或在Visual Studio 2015中运行控制台应用程序时,它似乎从未被调用。

Startup.cs主要包含:

public class Startup
{
  public Startup(IHostingEnvironment env)
  {
    Configuration configuration = new Configuration();
    configuration.AddJsonFile("config.json");
    configuration.AddJsonFile("config.{env.EnvironmentName.ToLower()}.json", optional: true);
    configuration.AddEnvironmentVariables();

    this.Configuration = configuration;
  }

  public void ConfigureServices(IServiceCollection services)
  {
    services.Configure<Settings>(Configuration.GetSubKey("Settings"));

    services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<ApplicationContext>(options => options.UseSqlServer(this.Configuration["Data:DefaultConnection:ConnectionString"]));
  }

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  {
    loggerFactory.AddConsole(minLevel: LogLevel.Warning);
  }
}
我尝试在我的Main方法中手动创建Startup类,但这似乎不是正确的解决方案,并且到目前为止还没有让我配置服务。
我假设有一种方式可以创建一个HostingContext,它不会启动Web服务器,但会使控制台应用程序保持活动状态。类似于以下内容:
HostingContext context = new HostingContext()
{
  ApplicationName = "AppName"
};

using (new HostingEngine().Start(context))
{
  // console code
}

然而到目前为止,我唯一能让它工作的方法是将 HostingContext.ServerFactoryLocation 设置为 Microsoft.AspNet.Server.WebListener,这会启动 Web 服务器。


有ASP.NET 5控制台应用程序这样的东西吗?它肯定是一个ASP.NET Core应用程序,或者是一个.NET Core控制台应用程序吧? - Matthew Layton
1个回答

19

你所寻找的是正确的想法,但我认为你需要先回退一步。

首先,你可能已经注意到你的默认程序类不再使用静态方法了;这是因为构造函数其实已经独自获得了一些依赖注入的爱!

public class Program
{
    public Program(IApplicationEnvironment env)
    {            
    }        

    public void Main(string[] args)
    {
    }
}

很不幸,与ASP.NET 5托管环境中您所熟悉的服务相比,可注册的服务要少得多;感谢这篇文章IServiceManifest,您可以看到只有几个可用的服务:

Microsoft.Framework.Runtime.IAssemblyLoaderContainer Microsoft.Framework.Runtime.IAssemblyLoadContextAccessor Microsoft.Framework.Runtime.IApplicationEnvironment Microsoft.Framework.Runtime.IFileMonitor Microsoft.Framework.Runtime.IFileWatcher Microsoft.Framework.Runtime.ILibraryManager Microsoft.Framework.Runtime.ICompilerOptionsProvider Microsoft.Framework.Runtime.IApplicationShutdown

这意味着您也将享受创建自己的服务提供程序的乐趣,因为我们无法获得框架提供的服务提供程序。

private readonly IServiceProvider serviceProvider;

public Program(IApplicationEnvironment env, IServiceManifest serviceManifest)
{
    var services = new ServiceCollection();
    ConfigureServices(services);
    serviceProvider = services.BuildServiceProvider();
}

private void ConfigureServices(IServiceCollection services)
{
}

这会带走你在标准ASP.NET 5项目中看到的很多魔法,现在你可以在Main中使用你想要的服务提供程序。

还有一些“陷阱”,我可以列出来:

  • 如果你请求IHostingEnvironment,它将为null。那是因为托管环境来自于ASP.Net 5托管。
  • 由于你没有一个托管环境,你将无法获取到IHostingEnvironment.EnvironmentName - 你需要自己从环境变量中收集它。不过,既然你已经将它加载到了你的Configuration对象中,这应该不是一个问题。(它的名称是“ASPNET_ENV”,你可以在项目设置的Debug选项卡中添加它;对于控制台应用程序,默认情况下不会为你设置它。你可能想重新命名它,毕竟你现在不再谈论一个ASPNET环境了。)

谢谢,这很有帮助。一旦像你指出的那样创建了ServiceProvider,我就可以将它传递给DbContext。把ServiceProvider设置为静态是否安全?我猜想它不会自动附加,就像在ASP.NET5托管项目中那样。 - sixones
1
一旦你使用 IServiceProvider 创建某些东西,它可以通过 DI 获取 IServiceProvider 的实例并传播自己。通常认为单例服务提供程序是不好的做法;首先它会破坏可测试性。 - Matt DeKrey
我使用了 ServiceProvider 来创建一个 DbContext,如果我使用提供程序来创建上下文,它可以正常工作,但是当我创建第二个 DbContext 时,没有传递提供程序就会失败。是否需要在某个地方手动注册 ServiceProvider,以便它可以自动访问? - sixones
1
一些名称空间已更改,但这仍然是相同的。如果要在控制台应用程序中指定自己的服务,则需要构建自己的“IServiceProvider”,如我所知,在第二个代码块中提供了示例(如果您明确访问它,则甚至可以使用您的“Startup”类构建它!) - Matt DeKrey
1
主函数再次在RC1中被声明为静态:https://github.com/aspnet/Announcements/issues/113 - Chris
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接