Как запустить веб-браузер после запуска приложения ASP.NET Core?
У меня есть приложение ASP.NET Core, которое будет использоваться как клиент несколькими пользователями. Другими словами, он не будет размещен на центральном сервере, и они будут запускать опубликованный исполняемый файл в любое время, когда им нужно будет использовать приложение.
В файле Program.cs
есть следующее:
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
Я бы хотел, чтобы веб-браузер по умолчанию автоматически открывался, чтобы избежать избыточного шага пользователя, который должен открыть браузер и вручную ввести адрес http://localhost:5000
.
Каким будет лучший способ достичь этого? Вызов Program.Start
после вызова Run()
не будет работать, потому что Run
блокирует поток.
Ответы
Ответ 1
У вас есть две разные проблемы здесь:
Блокировка тем
host.Run()
действительно блокирует основной поток. Поэтому используйте host.Start()
(или await StartAsync
в 2.x) вместо host.Run()
.
Как запустить веб-браузер
Если вы используете ASP.NET Core поверх .NET Framework 4.x, Microsoft говорит, что вы можете просто использовать:
Process.Start("http://localhost:5000");
Но если вы ориентируетесь на мультиплатформенный .NET Core, приведенная выше строка не будет выполнена. Не существует единого решения, использующего .NET Standard
, которое работает на любой платформе. Решение только для Windows:
System.Diagnostics.Process.Start("cmd", "/C start http://google.com");
Изменение: я создал тикет, и разработчик MS ответил, что на сегодняшний день, если вам нужна многоплатформенная версия, вы должны сделать это вручную, например:
public static void OpenBrowser(string url)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url.Replace("&", "^&")}")); // Works ok on windows and escape need for cmd.exe
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url); // Works ok on linux
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url); // Not tested
}
else
{
...
}
}
Теперь все вместе:
using System.Threading;
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Start();
OpenBrowser("http://localhost:5000/");
}
public static void OpenBrowser(string url)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}"));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
// throw
}
}
}
Ответ 2
Вы можете запустить процесс веб-браузера прямо перед host.Run()
. Это работает с Chrome и, возможно, с другими браузерами:
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
var browserExecutable = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
Process.Start(browserExecutable, "http://localhost:5000");
host.Run();
}
В случае Chrome новое окно будет ждать, пока сервер запустится, а затем подключится и отобразит приложение.
В зависимости от конфигурации вашей системы вы можете сделать Process.Start("http://localhost:5000")
, чтобы запустить браузер по умолчанию, а не hardcoding путь к исполняемому файлу. Почему-то это не сработало для меня. Вы также можете вытащить путь к браузеру из реестра или из файла конфигурации.
Ответ 3
Еще один вариант здесь - разрешить объект IApplicationLifetime
в Startup.Configure
и зарегистрировать обратный вызов на ApplicationStarted
. Это событие запускается, когда хост развернулся и прослушивает.
public void Configure(IApplicationBuilder app, IApplicationLifetime appLifetime)
{
appLifetime.ApplicationStarted.Register(() => OpenBrowser(
app.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First()));
}
private static void OpenBrowser(string url)
{
Process.Start(
new ProcessStartInfo("cmd", $"/c start {url}")
{
CreateNoWindow = true
});
}
Ответ 4
Принятый ответ хорош, но из-за отсутствия блокировки программа сразу закончится, остановив сервер. Здесь отвечает версия, адаптированная от Херардо и Ивана.
Он создаст сервер, запустит браузер, когда сервер начнет прослушивать, и блокируется до тех пор, пока сервер не закончится:
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using System.Diagnostics;
using Microsoft.AspNetCore.Builder;
using static System.Runtime.InteropServices.RuntimeInformation;
using static System.Runtime.InteropServices.OSPlatform;
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:54321/";
using (var server = CreateServer(args, url))
{
StartBrowserWhenServerStarts(server, url);
server.Run(); //blocks
}
}
/// <summary>
/// Create the kestrel server, but don't start it
/// </summary>
private static IWebHost CreateServer(string[] args, string url) => WebHost
.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls(url)
.Build();
/// <summary>
/// Register a browser to launch when the server is listening
/// </summary>
private static void StartBrowserWhenServerStarts(IWebHost server, string url)
{
var serverLifetime = server.Services.GetService(typeof(IApplicationLifetime)) as IApplicationLifetime;
serverLifetime.ApplicationStarted.Register(() =>
{
var browser =
IsOSPlatform(Windows) ? new ProcessStartInfo("cmd", $"/c start {url}") :
IsOSPlatform(OSX) ? new ProcessStartInfo("open", url) :
new ProcessStartInfo("xdg-open", url); //linux, unix-like
Process.Start(browser);
});
}
}