17

UPDATE - 26th July 2016

I have added the solution to this in ASP.NET Core 1.0.0 in the answers below.


I have created a simple MVC 6 app and have included the Microsoft.AspNet.WebListener library so I can host outside of IIS.

From project.json:

"dependencies": {
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.Mvc": "6.0.0-beta4"
},

"commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
}

When I publish this I can run the web.cmd file and get the site running in a console window. Great!

But in OWIN you can use TopShelf to launch your web app from a Console Application. This can then be built as an executable and installed as a Windows Service.

Is there a way to do this with an ASP.NET 5 MVC 6 web app?

JDTLH9
  • 1,765
  • 1
  • 23
  • 34

4 Answers4

10

You can run a DNX app as a Windows service, however, you can't run the CMD file directly. You will get an error saying the following: 'The service did not respond to the start or control request in a timely fashion.' You can point directly to dnx.exe and pass the project folder and command as arguments.

Read this post for a lot more detail: http://taskmatics.com/blog/run-dnx-applications-windows-service/

Once you have your app set up. You can bootstrap ASP.NET from the OnStart method of the service. To do this you can use WebHostBuilder from Microsoft.AspNet.Hosting.

Lastly, you can ensure the app is still runnable in VS by passing an argument (such as 'non-service') to the Main method and check that before calling ServiceBase.Run, and if present, you can call OnStart directly instead. The project's properties gives you the option to pass arguments when running in VS.

UPDATE:

There is a follow up post which builds upon the one above. It shows how to run ASP.NET 5 with static files and MVC 6 in a Windows service. The link is here: http://taskmatics.com/blog/host-asp-net-in-a-windows-service/

Erez T
  • 131
  • 1
  • 3
  • please would you be kind enough to share your code for bootstrapping your app. I had a good look on the [GitHub Page](https://github.com/aspnet/Hosting) but did not see any good examples. – JDTLH9 Aug 25 '15 at 16:38
  • I'm working on a follow up post to the one I referred to that will include all the information necessary to host ASP.NET (with MVC and static files) in a Windows service. I'm planning on having it ready by the end of the week. I'll update my response with the link once I publish it. – Erez T Aug 26 '15 at 18:49
  • Have you had a chance to try it out? I posted the code on Github as well. Let me know if this solves your problem. If not, I'd be glad to further help out. – Erez T Aug 28 '15 at 11:37
  • Not yet. Hopefully this weekend. I have scanned your post and it looks like everything I was after :) – JDTLH9 Aug 28 '15 at 14:17
  • 1
    Superb! Your article was very clear and worked like a charm! Thank you so much. I will mark you as the answer :) – JDTLH9 Aug 31 '15 at 15:38
  • Tried but couldn't get it to work. With verbatim code in the blog, VS2015 complains with "Program does not contain a static 'Main' method suitable for an entry point." and won't build. After changing to a non static Main, was able to run it from the command line (e.g. dnx run) and correctly complains in a dialog box that it cannot start service. Then tried to install and start and sc.exe responds with Access denied. I thought it was might be the _log but even commenting out the logs stmt, still get Access denied. What might I be doing wrong? TIA. – howardlo May 15 '16 at 11:09
  • Removed "compilationOptions": { "emitEntryPoint": true } and then all is fine. – howardlo May 25 '16 at 14:48
6

As of the latest ASP.NET Core Version 1.0.0 libraries this is now somewhat simplified.

There is an open discussion on this topic on the ASP.NET GitHub page.

All ASP.NET Core applications are now Console Applications and there is a new library to host as a Windows Service that runs on the full .NET framework (which makes sense as this whole problem assumes a Windows web server).

We need to create a new ASP.NET Core Web Application (.NET Framework)

Check the project.json file to ensure that the "frameworks" section is as below:

"frameworks": {
    "net461": {}
},

We need to then add the service hosting library Microsoft.AspNetCore.Hosting.WindowsServices and save the project.json to restore the package.

We then need to edit the program.cs file and add paths for running in debug and running as a service, the code for this is as follows:

    public static void Main(string[] args)
    {
        var isDebug = Debugger.IsAttached || ((IList)args).Contains("--debug");
        string runPath;

        if (isDebug)
            runPath = Directory.GetCurrentDirectory();
        else
        {
            var exePath = Process.GetCurrentProcess().MainModule.FileName;
            runPath = Path.GetDirectoryName(exePath);
        }

        var host = new WebHostBuilder()
                        .UseKestrel()
                        .UseContentRoot(runPath)
                        .UseStartup<Startup>()
                        .Build();

        if (isDebug)
            host.Run();
        else
            host.RunAsService();
    }

The .RunAsService() method is an extension method provided by the Microsoft.AspNetCore.Hosting.WindowsServices lib.

To install as a service you just need to run the following command from an Administrator command prompt:

SC Create <service-name> binPath= "[PublishOutputPath]\mvc6-example.exe"

Please clone and view the working version on my GitHub repository.

I hope this helps :)

JDTLH9
  • 1,765
  • 1
  • 23
  • 34
  • Very useful in order to determine where views, etc, are during debugging when using Topshelf, or other, to self host. – paulio Sep 14 '16 at 11:40
  • @JDTLH9 only seems to "Run" with .UseIISIntegration() on the host? – Demodave Sep 22 '16 at 15:58
  • @Demodave please see the full Program.cs here: https://github.com/JDTLH9/mvc6-example/blob/master/src/mvc6-example/Program.cs . It uses the Microsoft.AspNetCore.Hosting lib. In version 1.0.0 .Run() is a method on IWebHost which is implemented by WebHostBuilder – JDTLH9 Sep 23 '16 at 08:32
5

UPDATE: It seems like there is going to be a Windows Service hosting option coming in with RC2. See this GitHub comment for more info and this answer.

I am afraid the answer is no for this. I have been looking into this as well and the best way to do this is to deploy your project into a known location on disk and have a Windows Service to spin up the process which calls the cmd file. This way, the Windows Service will only act as a watchdog.

I am hoping to get some blog posts and samples on this as I have been looking into this in terms of deployment. There is also an open discussion here: https://github.com/aspnet/Home/issues/465

Community
  • 1
  • 1
tugberk
  • 57,477
  • 67
  • 243
  • 335
  • Thanks for the response. I will read a bit more around this and check the GitHub link you have posted. Then I will mark you as the answer. Thanks again :) – JDTLH9 May 16 '15 at 23:07
  • 1
    I got a little further with this by creating an ASP.NET vNext Console Application and adding Topshelf to it. Unfortunately it all fell apart when I ran it, as the arguments to dnx were passed through to Topshelf which completely confused it. I have no idea whether or not the service would be appropriately self-contained had the installation succeeded. – alastairs Jul 16 '15 at 15:01
  • See [this issue](https://github.com/Topshelf/Topshelf/issues/238) on the Topshelf GitHub repository for updates... – alastairs Jul 16 '15 at 15:21
  • 1
    @alastairs I think that will never work unless Windows Service stuff somehow knows what DNX is. I tried invoking it as a separate process as mentioned above but it felt somehow wrong as there was basically no value doing it. I ended up dockerizing my workers and running/shipping them that way. I run [the dnx process under nodemon](http://blog.markrendle.net/running-dnx-apps-with-nodemon/) inside the container and it seems the best option to ship workers. – tugberk Jul 16 '15 at 15:43
  • @tugberk I am going to mark Erez T's solution as the answer as he solved this problem nicely – JDTLH9 Aug 31 '15 at 15:40
  • It seems like there is going to be a Windows Service hosting option coming in with RC2. See the updated answer. – tugberk Apr 13 '16 at 15:25
  • sorry, it seems like there is already an answer for this: http://stackoverflow.com/a/34567682/463785 – tugberk Apr 13 '16 at 15:27
3

It is worth looking at https://github.com/aspnet/Hosting/tree/dev/src/Microsoft.AspNet.Hosting.WindowsServices

It seems that ASP.NET team is working on native support for hosting ASP.NET MVC 6 applications within Windows Services.

Here is a simple ServiceBase hosting an ASP.NET MVC 6 app:

/// <summary>
///     Provides an implementation of a Windows service that hosts ASP.NET.
/// </summary>
public class WebApplicationService : ServiceBase
{
    private IWebApplication _application;
    private IDisposable _applicationShutdown;
    private bool _stopRequestedByWindows;

    /// <summary>
    /// Creates an instance of <c>WebApplicationService</c> which hosts the specified web application.
    /// </summary>
    /// <param name="application">The web application to host in the Windows service.</param>
    public WebApplicationService(IWebApplication application)
    {
        _application = application;
    }

    protected sealed override void OnStart(string[] args)
    {
        OnStarting(args);

        _application
            .Services
            .GetRequiredService<IApplicationLifetime>()
            .ApplicationStopped
            .Register(() =>
            {
                if (!_stopRequestedByWindows)
                {
                    Stop();
                }
            });

        _applicationShutdown = _application.Start();

        OnStarted();
    }

    protected sealed override void OnStop()
    {
        _stopRequestedByWindows = true;
        OnStopping();
        _applicationShutdown?.Dispose();
        OnStopped();
    }
}
Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123