Как запустить веб-хост Asp.Net Core из соседнего проекта?

Ранее мне удавалось запустить .Net Core 3.1 Asp.Net Core веб приложение из соседнего NUnit проекта так

[OneTimeSetUp]
public void Setup()
{
    Program.BuildWebHost(new string[] {}).Start();
}        

А Program.cs в веб-приложении выглядит так

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

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

Но после каких-то обновлений это перестало работать. Всё что я нашёл для NUnit, это совет использовать WebApplicationFactory

private WebApplicationFactory<Startup> _factory;
private HttpClient _client;

[OneTimeSetUp]
public void GivenARequestToTheController()
{
    _factory = new WebApplicationFactory<Startup>();
    _client = _factory.CreateClient();
}

Это работает. Но не годится, если я не хочу использовать вот этот вот HttpClient, а хочу использовать Selenium, например. Казалось бы, банальная задача запустить один проект из другого, но почему-то какие-то сложности. Конечно, я могу вручную найти сборку и запустить процесс, но это же не серьёзно.


Ответы (2 шт):

Автор решения: Andrei Khotko

Создал приложение ASP.NET Core Web Application по шаблону WebApi (.Net Core 3.1). Создал HelloDataManager:

namespace NetCoreWebAppSample.Managers
{
    public interface IHelloManager
    {
        string SayHelloTo(string name);
    }
}

namespace NetCoreWebAppSample.Managers
{
    public class HelloManager : IHelloManager
    {
        public string SayHelloTo(string name)
        {
            return $"Hello, {name}!";
        }
    }
}

Создал контроллер:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NetCoreWebAppSample.Managers;

namespace NetCoreWebAppSample.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class HelloController : ControllerBase
    {
        private readonly ILogger<HelloController> _logger;
        private readonly IHelloManager _manager;

        public HelloController(IHelloManager manager, ILogger<HelloController> logger)
        {
            _manager = manager;
            _logger = logger;
        }

        [HttpGet]
        [Route("{name}")]
        public string Get(string name)
        {
            var helloMessage = _manager.SayHelloTo(name);
            return helloMessage;
        }
    }
}

Program.cs

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace NetCoreWebAppSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

И создал сборку для тестов .Net Core 3.1 библиотека классов, в которую добавил класс:

using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using NUnit.Framework;

namespace NetCoreWebAppSample.Tests
{
    [TestFixture]
    public class HelloWebApiTests
    {
        private const string serviceUrl = "http://localhost:50200";
        private HttpClient _httpClient;

        [OneTimeSetUp]
        public void Init()
        {
            var arguments = new string[0];
            var builder = Program.CreateHostBuilder(arguments);

            _httpClient = new HttpClient();

            builder.ConfigureWebHostDefaults(w => w.UseUrls(serviceUrl)).Build().Start();
        }

        [Test]
        public async Task UserShouldBeAbleToGetHelloMessage()
        {
            const string userName = "Andrei";
            var requestUrl = $"{serviceUrl}/hello/{userName}";

            const string expected = "Hello, Andrei!";
            var response = await _httpClient.GetAsync(requestUrl);
            var actual = await response.Content.ReadAsStringAsync();
            Assert.AreEqual(expected, actual);
        }
    }
}

Тест был пройден:

введите сюда описание изображения

→ Ссылка
Автор решения: 4per

Для решения проблемы, описанной в вопросе (который раскрылся, по сути, только после последней правки), нужно было обеспечить сохранение исходной конфигурации. Для этого нужно воспользоваться методом .AddConfiguration()

Configuration = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile($"appsettings.json")
   .AddJsonFile($"secrets.json")
   .AddConfiguration(Configuration)
   .Build();
services.AddSingleton<IConfiguration>(Configuration);

P.S. Правда и это мне не помогло, но это уже тема для следующего вопроса Не могу получить index.html из теста NUnit

→ Ссылка