18

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
  • Is there such thing as an ASP.NET 5 Console Application? Surely it's either an ASP.NET Core Application, or a .NET Core Console Application? Commented Nov 8, 2016 at 19:12

1 Answer 1

19

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.)
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks this helps, once the ServiceProvider has been created as you've pointed out, I can pass it into the DbContext. Is it safe to make the ServiceProvider static? I'm assuming there's no way for it to be automatically attached like inside ASP.NET5 Hosting projects.
Once you use your IServiceProvider to create something, it can get an instance of the IServiceProvider through DI, and propagate itself. It's generally considered bad practice to have a singleton service provider; it breaks testability, for starts.
I've used the ServiceProvider to create a DbContext, if I create the context with the provider it works, but when I create a second DbContext without passing along the provider it fails. Is there some place I need to manually register the ServiceProvider in order for it to be accessible automatically?
Some of the namespaces have changed, but this is still the same here. To specify your own services in a console application, you'll need to build your own IServiceProvider as given in the second code block as far as I'm aware. (You can even construct it by using your Startup class if you explicitly access it!)
Main is static once again since RC1: github.com/aspnet/Announcements/issues/113
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.