3

I currently have a ASP.NET Core application implementing a basic web API. I have a need to write a script that hooks into the same environment with access to at least the database, but can't find a place to add new entry points to the application. I can easily look at string[] args in the Main method in Program.cs and not start the server, but I don't see how I can load up the environment and run arbitrary code without just standing up the normal Kestrel server. I'm pretty new to the .NET world so I'm hoping there is an easy way to do this that I've just failed to find in the documentation.

Basically I'd like to be able to run something like dotnet run foo which would execute some synchronous piece of code on the server instead of starting up the normal kestrel server.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
cmwright
  • 3,406
  • 5
  • 26
  • 33
  • @cmwright What's wrong with having this code run in a separate project? – Nate Barbettini Dec 23 '16 at 17:08
  • @NateBarbettini he never said there *was* anything wrong with it - but it's pretty non-obvious to me how to go about creating a runnable project that can use the DI container from the ASP.NET application, and explaining that is probably a whole answer's worth of work. – Mark Amery May 09 '17 at 15:52
  • Shoot. I'm looking for something similar. It's a lot like this question but in .NET Core: https://stackoverflow.com/questions/9757261/how-do-i-run-a-ruby-file-in-a-rails-environment – Jose A Nov 03 '18 at 20:54
  • The below answer is correct, it's mostly just wrapping your head around the dotnet way of doing things. Generally (this was true in my case), it means you've tightly coupled some logic to your server that should be in it's own class library. Once that business logic is out of your server project you import it to the server and whatever other projects need access to it. – cmwright Nov 06 '18 at 22:55

1 Answers1

2

You can do this by adding new projects. The idea is to have three projects co-exist in your solution:

  • the ASP.NET Core application, and
  • a .NET Core Console App containing your executable scripts, and
  • a .NET Class Library containing common dependencies of the two and containing service collection configuration, so that you can use the ASP.NET DI container from within your scripts

Steps to go from a single-project ASP.NET Core application to the configuration above (assuming that you're using Visual Studio) look something like:

  1. Right-click your solution in Solution Explorer, go to Add -> New Project..., and select the project type Console App (.NET Core). Give it a name (e.g. Scripts) and click OK.
  2. Add another project with type Class Library (.NET Core), named e.g. Common.
  3. Migrate any classes that you want to use from the ASP.NET Core project to the Common project.
  4. Add a CommonStartup class to your Common project. Give it a public static void ConfigureServices(IServiceCollection services) and cut and paste across any service configuration from your ASP.NET Core application's Startup.ConfigureServices method that you want to share with your Scripts project. Add a call to CommonStartup.ConfigureServices(services) to Startup.ConfigureServices method in the ASP.NET Core project. (You'll need to add references to Microsoft.Extensions.DependencyInjection; and Microsoft.Extensions.DependencyInjection.Abstractions; to the Common project and a reference to Common to the ASP.NET Core project; Visual Studio should offer these as sidebar actions.
  5. At the start of your Scripts project's Main method, add:

    var services = new ServiceCollection();
    CommonStartup.ConfigureServices(services);
    var provider = services.BuildServiceProvider();
    

    (You'll once again have to add references.)

  6. You can now use the DI system from within your Scripts project to get instances of classes, by writing e.g. var widgetFactory = provider.GetService<IWidgetFactory>().

You can build and run your script by running dotnet run from within the folder of your Scripts project.

If you want multiple executable scripts, just add a switch statement to your Main method that does something different depending upon the value of args[0], then call your scripts with dotnet run wibble, dotnet run wobble, etc.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459