Using Startup class in ASP.NET5 Console Applicatio

2020-06-08 03:44发布

问题:

Is it possible for an ASP.NET 5-beta4 console application (built from the ASP.NET Console project template in VS2015) to use the Startup class to handle registering services and setting up configuration details?

I've tried to create a typical Startup class, but it never seems to be called when running the console application via dnx . run or inside Visual Studio 2015.

Startup.cs is pretty much:

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

I've tried to manually create the Startup class in my Main method, but this doesn't seem like the right solution and hasn't so far allowed me to configure the services.

I'm assuming there's some way for me to create a HostingContext that doesn't start up a web server but will keep the console application alive. Something along the lines of:

HostingContext context = new HostingContext()
{
  ApplicationName = "AppName"
};

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

However so far the only way I can get this to work is if I set the HostingContext.ServerFactoryLocation to Microsoft.AspNet.Server.WebListener, which starts up the web server.

回答1:

What you're looking for is the right idea, but I think you'll need to back up a moment.

Firstly, you may have noticed that your default Program class isn't using static methods anymore; this is because the constructor actually gets some dependency injection love all on its own!

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

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

Unfortunately, there aren't as many of the services you're used to from an ASP.NET 5 hosting environment registered; thanks to this article and the IServiceManifest you can see that there's only a few services available:

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

This means you'll get the joy of creating your own service provider, too, since we can't get the one provided by the framework.

private readonly IServiceProvider serviceProvider;

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

private void ConfigureServices(IServiceCollection services)
{
}

This takes away a lot of the magic that you see in the standard ASP.NET 5 projects, and now you have the service provider you wanted available to you in your Main.

There's a few more "gotchas" in here, so I might as well list them out:

  • If you ask for an IHostingEnvironment, it'll be null. That's because a hosting environment comes from, well, ASP.Net 5 hosting.
  • Since you don't have one of those, you'll be left without your IHostingEnvironment.EnvironmentName - you'll need to collect it from the environment variables yourself. Which, since you're already loading it into your Configuration object, shouldn't be a problem. (It's name is "ASPNET_ENV", which you can add in the Debug tab of your project settings; this is not set for you by default for console applications. You'll probably want to rename that, anyway, since you're not really talking about an ASPNET environment anymore.)