如何在启动ASP.NET Core应用程序后打开Web浏览器?

32

我有一个ASP.NET Core应用程序,将被多个用户用作客户端。换句话说,它不会托管在中央服务器上,他们将在需要使用该应用程序时运行已发布的可执行文件。

Program.cs文件中有以下内容:

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

host.Run();

我希望默认的网络浏览器能够自动打开,以避免用户需要手动打开浏览器并输入 http://localhost:5000 地址这一冗余步骤。

如何实现最佳效果?在调用 Run() 后调用 Program.Start 不起作用,因为 Run 阻塞了线程。

4个回答

48

您有两个不同的问题:

线程阻塞

host.Run()确实会阻塞主线程。所以,使用host.Start()(或2.x上的await StartAsync),而不是host.Run()

如何启动Web浏览器

如果您正在使用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");

编辑:我创建了一个问题单,微软的开发人员回答说,截至今日,如果你想要一个多平台版本,你需要手动完成,例如:

public static void OpenBrowser(string url)
{
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); // Works ok on windows
    }
    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(url) { UseShellExecute = true });
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            Process.Start("xdg-open", url);
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            Process.Start("open", url);
        }
        else
        {
            // throw 
        }
    }
}

对我来说,如果我尝试使用带有查询字符串的url,那么某种原因它只接受第一个查询参数,而且会丢弃其他的。它似乎有问题处理和字符&。你尝试过这个吗?需要进行转义吗?如果我改为以下方式: Process.Start(@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", url);那么它将按预期工作。 - UmaN
1
是的@UmaN,根据https://dev59.com/3nM_5IYBdhLWcg3wjj6r#27960888,`&`应该这样转义:`^&`。因此,请尝试`Process.Start(new ProcessStartInfo("cmd", $"/c start {url.Replace("&", "^&")}"));`。 - Gerardo Grignoli
4
根据您提供的链接所示,现在可以使用 new ProcessStartInfo(url) { UseShellExecute = true } 实现该功能。 - Kyle Delaney
你还需要在 Main 方法的结尾添加 host.WaitForShutdown(); 以防止服务器立即关闭。 - mrmashal

8

这里还有另一种选项,就是在Startup.Configure中解析一个IApplicationLifetime对象,并在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 
        });
}

6

接受的答案不错,但因为没有阻塞程序,所以程序会立即结束,停止服务器。这里是一个从Gerardo和Ivan的答案中改编的版本。

它将创建服务器,在服务器开始侦听时启动浏览器,并阻塞直到服务器结束:

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);
        });
    }
}

2

您可以在host.Run()之前启动Web浏览器进程。这适用于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")来启动默认浏览器,而不是硬编码可执行文件路径。由于某些原因,这对我无效。您还可以从注册表或配置文件中获取浏览器路径。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接