如何从 Visual Studio 2019 部署 Blazor 服务器托管的应用程序

How can I deploy a Blazor server-hosted application from Visual Studio 2019

我正在使用 VS2019 预览版。 我使用最新的 Blazor 扩展 (16.0.19227) 创建了一个 "server-hosted" Blazor 应用程序。这是包含 3 个独立项目的变体...

我可以通过使 MyApp.Server 成为活动项目来调试它,并且一切正常,但我正在努力 publish/deploy 将它发送到 Azure。我尝试了以下...

此时我在部署期间遇到错误...

CSC(0,0): Error CS0006: Metadata file 'D:\work\Applications\Web\MyApp.Client\bin\Release\netstandard2.0\win-x86\MyApp.Client.dll' could not be found

这似乎是因为网络部署配置文件中的 "Target Runtime" 设置为 win-x86。客户端应用程序实际上正在构建为

"D:\work\Applications\Web\MyApp.Client\bin\Release\netstandard2.0\MyApp.Client.dll"

(没有额外的 win-x86 子文件夹)所以部署过程似乎对构建过程使用的路径做出了错误的假设。在发布对话框中无法指定 blank/don 无关目标运行时。

是否有解决此问题的方法,或者我使用了错误的部署方法?

有一些official documentation,但不是很有用。

Update 看来部署是使用Client项目的输出路径,然后只是追加netstandard2.0{Target Runtime} 因此更改客户端项目中的输出路径不足以解决此问题。

更新 2 通过编辑 xml 删除发布配置文件中的 RuntimeIdentifier 标记只会导致部署时错误说明空的 RuntimeIdentifier 与自包含部署不兼容。不幸的是,独立部署是必要的,因为 Azure 尚未直接托管 .net core 3。

无法在评论中放图片,所以我想在这里展示一下。这是我当前的发布向导。

刚刚通过新项目 -> Asp.net 核心 Web 应用程序 -> blazor(Asp.net 核心托管)构建并发布了 Azure 应用程序服务。

because Azure does not yet host .net core 3 directly.

但确实如此。

在 Azure 门户中,部署后转到您的 WebApp(或预先创建一个)。

转到扩展并单击添加 [+] 和 select ASP.NET Core 3(x86 用于免费托管)。

同时转到“设置”、“常规”并启用 WebSockets,它们默认处于关闭状态。


临时的:

请注意,Preview-6 不可作为扩展使用,因此请使用 Preview-5 或部署为 self-contained。

我的回答是:

  • 将发布配置文件配置为 "Self-contain" 部署模式。
  • 编辑所有 .csproj 文件以将 <TargetFramework>...</TargetFramework> 节点名称更改为 <TargetFrameworks>...</TargetFrameworks>。 (另请参阅:
  • 在运行时修复 Startup class 中的 Web 根文件夹路径字符串,如下所示。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Serialization;
using System.IO;
using System.Linq;

namespace BlazorHostedOnAzure.Server
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().AddNewtonsoftJson();
            services.AddResponseCompression(opts =>
            {
                opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                    new[] { "application/octet-stream" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseResponseCompression();

            // ---- APPEND PART.1 BEGIN ----
            var clientBlazorWebRootPath = default(string);
            // ---- APPEND PART.1 END ----

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBlazorDebugging();
            }

            // ---- APPEND PART.2 BEGIN ----
            else
            {
                if (env.WebRootPath != null)
                {
                    var pathOfIndex = Path.Combine(env.WebRootPath, "index.html");
                    var pathOfContent = Path.Combine(env.WebRootPath, "_content");
                    if (!File.Exists(pathOfIndex) && Directory.Exists(pathOfContent))
                    {
                        clientBlazorWebRootPath = Directory.GetDirectories(pathOfContent).FirstOrDefault();
                        if (clientBlazorWebRootPath != null)
                        {
                            env.WebRootPath = clientBlazorWebRootPath;
                        }
                    }
                }
            }
            // ---- APPEND PART.2 END ----

            app.UseClientSideBlazorFiles<Client.Startup>();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
                endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
            });

            // ---- APPEND PART.3 BEGIN ----
            if (clientBlazorWebRootPath != null)
            {
                app.UseStaticFiles(new StaticFileOptions
                {
                    FileProvider = new PhysicalFileProvider(clientBlazorWebRootPath)
                });
            }
            // ---- APPEND PART.3 BEGIN ----
        }
    }
}

我在 GitHub 我的存储库中发布了示例代码和自述文件。