Подтвердить что ты не робот

Хостинг ASP.NET Core как служба Windows

Как я понимаю, в RC2 есть поддержка для размещения приложений в Windows Services. Я попытался проверить его на простой веб-проект api (используя .NET Framework 4.6.1).

Здесь мой код Program.cs:

using System;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.WindowsServices;

namespace WebApplication4
{
  public class Program : ServiceBase
  {
    public static void Main(string[] args)
    {
      if (args.Contains("--windows-service"))
      {
        Run(new Program());
        return;
      }

      var program = new Program();
      program.OnStart(null);
      Console.ReadLine();
      program.OnStop();
    }

    protected override void OnStart(string[] args)
    {
      var host = new WebHostBuilder()
      .UseKestrel()
      .UseContentRoot(Directory.GetCurrentDirectory())      
      .UseStartup<Startup>()
      .Build();

      host.RunAsService();
    }

    protected override void OnStop() {}
  }
}

Все остальные вещи в основном основаны на шаблоне .NET Core (хотя я изменил структуру на net461 и добавил некоторые зависимости в project.json).

После публикации с помощью dotnet publish и создания службы Windows с помощью sc create я могу успешно запустить свою службу, но я не могу связаться ни с одним из моих контроллеров (порты не отображаются). Я предполагаю, что я делаю что-то неправильно.

Поэтому я предполагаю, что главный вопрос заключается в том, как сделать самообслуживаемую веб-api и запустить ее как службу Windows. Все найденные решения не работают после обновления RC2.

4b9b3361

Ответ 1

Здесь у вас есть несколько вариантов: используйте класс Microsoft WebHostService, наследуйте WebHostService или напишите свой собственный. Причина последнего заключается в том, что с использованием реализации Microsoft мы не можем написать общий метод расширения с параметром типа, наследующим WebHostService, поскольку этот класс не содержит конструктора без параметров и не может получить доступ к локатору службы.

Использование WebHostService

В этом примере я собираюсь создать консольное приложение, которое использует Microsoft.DotNet.Web.targets, выводит .exe и работает как приложение MVC (Views, Controllers и т.д.). Я предполагаю, что создание Консольного приложения, изменение целевых показателей в .xproj и изменение project.json, чтобы иметь правильные варианты публикации и копирование представлений, контроллеров и webroot из стандартного шаблона веб-приложений .NET Core, тривиально.

Теперь важная часть:

  • Получите этот пакет и убедитесь, что ваша фреймворк в файле project.json является net451 (или новее)

  • Убедитесь, что корневой каталог содержимого в точке ввода правильно установлен в каталог публикации файла приложения .exe и вызывается метод расширения для AccessAsService(). Например:

    public static void Main(string[] args)
    {
        var exePath= System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
        var directoryPath = Path.GetDirectoryName(exePath);
    
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(directoryPath)
            .UseStartup<Startup>()
            .Build();
    
        if (Debugger.IsAttached || args.Contains("--debug"))
        {
            host.Run();
        }
        else
        {
            host.RunAsService();
        }
    }
    

Теперь .exe можно легко установить, используя следующую команду

    sc create MyService binPath = "Full\Path\To\The\Console\file.exe"

Как только служба запущена, веб-приложение размещается и успешно находит и отображает свои представления.

Наследовать WebHostService

Одним из основных преимуществ этого подхода является то, что это позволяет нам переопределять методы OnStopping, OnStarting и OnStarted.

Предположим, что следующий пользовательский класс, который наследует WebHostService

internal class CustomWebHostService : WebHostService
{
    public CustomWebHostService(IWebHost host) : base(host)
    {
    }

    protected override void OnStarting(string[] args)
    {
        // Log
        base.OnStarting(args);
    }

    protected override void OnStarted()
    {
        // More log
        base.OnStarted();
    }

    protected override void OnStopping()
    {
        // Even more log
        base.OnStopping();
    }
}

Следуя приведенным выше шагам, мы должны записать собственный метод расширения, который запускает хост с использованием нашего пользовательского класса:

public static class CustomWebHostWindowsServiceExtensions
{
    public static void RunAsCustomService(this IWebHost host)
    {
        var webHostService = new CustomWebHostService(host);
        ServiceBase.Run(webHostService);
    }
}

Единственная строка, которая по-прежнему должна быть изменена из предыдущего примера точки входа, - это инструкция else в конце, она должна вызвать правильный метод расширения

host.RunAsCustomService();

Наконец, установив службу, используя те же шаги, что и выше.

sc create MyService binPath = "Full\Path\To\The\Console\file.exe"

Ответ 2

Если это нормально для работы только с полной платформой .NET Framework, достаточно получить предыдущие ответы (Наследование с ServiceBase или с помощью Microsoft WebHostService).

Если, однако, у вас есть/хотите работать только на .NET Core (например, на windows nano server, один бинарный файл, который работает на Linux как обычное приложение и как служба на окнах, или нужно запускать бок о бок с приложениями на старой версии .NET Framework, чтобы вы не могли обновить системную инфраструктуру), вам нужно будет сделать соответствующие API окна API самостоятельно через P/Invokes. Поскольку я должен был это сделать, я создал библиотеку которая делает именно это.

Существует sample, который также может быть установлен при запуске с правами администратора (например, dotnet MyService.dll --register-as-service).

Ответ 3

Используя последний шаблон VS2015 Update 2 ASP.NET Core Web Application (.NET Framework) и с модами в Program.cs, как показано ниже, он отлично работает при запуске в качестве службы автономно и в VS. Обратите внимание, что путь к каталогу, содержащему wwwroot, должен быть установлен при запуске в качестве службы.

Пока мне очень нравится этот шаблон и шаблон. Может разрабатывать код MVC6, как обычно, в Visual Studio, а затем он автоматически развертывается как служба. Фактически, я заметил, что при развертывании локального экземпляра службы для тестирования нет необходимости удалять/создавать службы с помощью sc.exe. Просто остановите службу, опубликуйте код и перезапустите службу, и он подберет новые изменения.

public class Program
{
    public static void Main(string[] args)
    {
        IWebHost host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        if (args.Contains("--windows-service"))
        {
            host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot("<directory-containing-wwwroot>")
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseUrls("http://+:5000")
            .Build();

            Startup.is_service = true;
            host.RunAsService();
        }
        else
        {
            host.Run();
        }
    }
}

Ответ 4

Я нашел эту тему, ища решение подобной проблемы. Закончилось внедрение чего-то, что очень похоже на очень (очень) упрощенную Topshelf. Вы можете легко запускать консоль и/или устанавливать, деинсталлировать и, таким образом, использовать ее как услугу. Я думаю, что это может быть очень полезно для кого-то. Вы можете найти здесь код: https://github.com/PeterKottas/DotNetCore.WindowsService и здесь также можно найти https://www.nuget.org/packages/PeterKottas.DotNetCore.WindowsService/. Наслаждайтесь:)

Ответ 5

Службы Windows можно легко создать с помощью Visual Studio 2017. Вам нужно будет перенести свой код .NET Core в библиотеку классов, которая нацелена на NetStandard, на которую можно ссылаться. Ваш проект службы Windows должен будет настроить таргетинг на всю платформу .NET Framework, но может ссылаться на вашу общую библиотеку.

Поместив весь свой код в библиотеку классов, у вас будет возможность переносимости между службами Windows и другими приложениями, отличными от Windows.

С VS 2015 вы не смогли создать проект службы Windows и ссылаться на .NET Core xproj. Visual Studio 2017 исправляет, что после преобразования всех ваших проектов в csproj.

Этот блог просматривает его более подробно: Как создать .NET Core Windows Services с Visual Studio 2017

Ответ 6

Вам нужно указать Microsoft.AspNetCore.Hosting и Microsoft.AspNetCore.Hosting.WindowsServices и использовать этот код в своем классе Startup, чтобы он выполнялся как служба Windows:

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
                .UseIISIntegration()
                .UseKestrel()
                .UseContentRoot(@"Path\To\Content\Root")
                .UseStartup<Startup>()
                .Build();

    if (Debugger.IsAttached || args.Contains("--debug"))
    {
        host.Run();
    }
    else
    {
        host.RunAsService();
    }
}

Затем вам нужно добавить метод расширения для IWebHost.RunAsService, чтобы обернуть его своим пользовательским классом WebHostService с помощью обработчиков событий OnStopping и OnStarting:

public static class MyWebHostServiceServiceExtensions
{
    public static void RunAsMyService(this IWebHost host)
    {
        var webHostService = new MyWebHostService(host);
        ServiceBase.Run(webHostService);
    }
}

internal class MyWebHostService : WebHostService
{
    public MyWebHostService(IWebHost host) : base(host)
    {
    }

    protected override void OnStarting(string[] args)
    {
        base.OnStarting(args);
    }

    protected override void OnStarted()
    {
        base.OnStarted();
    }

    protected override void OnStopping()
    {
        base.OnStopping();
    }
}

Этот пост Как разместить свой ASP.NET Core в службе Windows, а комментарии охватывают детали.

ОБНОВЛЕНИЕ (подробнее см. в Краткая сводка о том, что нового в ASP.NET Core 2.0):

В ASP.NET Core 1.1 у нас было что-то вроде этого:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

В ASP.NET Core 2.0 он выглядит так:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}