在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)

Posted

技术标签:

【中文标题】在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)【英文标题】:Using blazor components outside of blazor app (eg. knockoutjs) 【发布时间】:2021-10-18 15:22:30 【问题描述】:

我正在做一个迁移项目。我是团队中唯一的 JS 开发人员,其余所有人都是 C# 开发人员。 我们正在寻求迁移用 .Net MVC Knockoutjs 编写的现有应用程序。 由于大多数外部团队都是 C# 开发人员,我们正在尝试 blazor。

由于整个应用程序重写需要时间,我们希望以 blazor 组件的形式逐个重写应用程序,并一次导出这些组件以在现有的 knockoutjs 应用程序中重用。

这将使我们能够从淘汰赛过渡到 blazor,同时继续支持和维护现有应用程序。

我将角度元素视为一种方式,但是,就像我提到的那样,我们想尝试一下 blazor。我很好奇我们是否可以将 blazor 组件导出到其他应用程序并允许它们之间的数据流。

感谢任何帮助/建议。

谢谢

【问题讨论】:

只需将每个淘汰页面替换为 blazor 页面?您可以单独执行这些操作;它们不必一次全部转换。 嗯,我的意思是,假设我在 Blazor 中创建了一个新的天气小部件,我想将该小部件作为组件添加到现有的淘汰赛应用程序中,并且从淘汰赛应用程序中,我应该能够搜索任何城市天气..所以数据应该在它们之间流动。 我怀疑是否有一条好的前进道路可以做到这一点。由于 Blazor 是 C#,它所做的很多工作都是服务器端的,而不是客户端的。 这种集成的最大问题是 Blazor 无法看到 DOM 的变化。如果没有 Blazor 跟踪的这些更改,所有电路都无法按预期工作。 Signalr 更新或 webassembly 更新在不一致的环境中应用的风险。从技术上讲,您可以做到,但最好在不混合技术的情况下管理页面。 @RobertHarvey,但是 Blazor WebAssembly 可以纯粹基于浏览器...也就是说,我也怀疑这个用例是否有一条很好的前进道路,但主要是因为 Blazor 有自己的方式做可能会干扰这项技术的事情。 【参考方案1】:

如果您想尝试一次用一个 blazor 组件替换 MVC 页面上的所有 javascript,您可以尝试这个过程,它对我有用。

首先,将您的 MVC 项目更新或转换为 .Net 5.0.402。 它可能适用于早期版本,但我尚未对其进行测试。

向您的 MVC 解决方案添加一个 blazor Web 程序集应用程序项目。 这是 Web 程序集组件项目。

在 MVC 视图中,在您希望呈现 blazor 组件的位置添加:

@using myawesomewasmprojectnamespace.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered"/>

<script src="_framework/blazor.webassembly.js"></script>

“@using”声明指的是 blazor Web 程序集应用程序项目 Pages 目录。 “typeof(Counter)”类型是指 Visual Studio 提供的默认 blazor Web 程序集应用程序项目中的 Counter.razor 组件。

我假设您将能够编写自己的 blazor 组件以与 Counter.razor 组件交换。

在 MVC 项目的 _Layout.cshtml 中,或 MVC 视图的 &lt;head&gt; 标记所在的任何位置,在其中包含 blazor 组件的每个页面的 &lt;head&gt; 标记中包含:

<base href="/"/>

将“Microsoft.AspNetCore.Components.WebAssembly.Server”包添加到您的 MVC 项目中。

在 MVC 依赖项、项目引用中添加对 blazor Web 程序集应用程序项目的引用。

在 MVC 应用 Startup.cs, 'public void Configure(IApplicationBuilder app, IWebHostEnvironment env)' 方法中,添加以下内容:

app.UseBlazorFrameworkFiles();

在 blazor Web 程序集应用程序项目 Program.cs 文件中,注释掉以下行以停止应用程序寻找“&lt;div id="app"&gt;&lt;/div&gt;

//builder.RootComponents.Add<App>("#app");

最后,从 blazor Web 程序集应用程序项目的 wwwroot 目录中删除图标,因为它会与 MVC 冲突。

这会将“计数器”组件添加到您的 MVC 视图中。

要将不同的组件添加到不同的视图,请将其插入:

@using myawesomewasmprojectnamespace.Pages

<component type="typeof(Myawsomecomponentnamecompletelydifferentfromanymvccontrolleroractionname)" render-mode="WebAssemblyPrerendered"/>

<script src="_framework/blazor.webassembly.js"></script>

然后使用以下命令启动您的 blazor 组件:

@page "/myawsomecomponentnamecompletelydifferentfromanymvccontrolleroractionname"

这花了我很长时间才整理出来,如果它不适合你,请告诉我。

【讨论】:

您好,非常感谢您的回复。我能够在完全不同的框架之外运行 blazor 组件!我刚看到这个回复。 不用担心。如果不出意外,下次我忘记如何做时,我总是可以查找我的答案。不过我很想看看你的解决方案。 是的,我将我的解决方案添加为答案,然后您就可以完成它! :) 太棒了。我可能会使用它。我的答案现在给了我一大堆其他问题。 我添加了我的答案,请随意通过,上述工作流程对我们非常有效,我们很快就会上线。【参考方案2】:

在做了大量研究并阅读了大量微软文档之后,我能够在不同的框架(在我的例子中是淘汰赛 mvc)中在 blazor 之外运行单独的 blazor 组件,

首先,我在 Visual Studio 中针对 .net 5.0 初始化了一个新的 Blazor Webassmebly 项目。

为简单起见,让我们从 blazor 引导应用程序中获取计数器组件。

步骤 - 1 将要导出的组件导入为可重用组件,如下所示 -

第 2 步 - 修改 MainLayout.razor 以加载组件

第 3 步 - 这是至关重要的一步。在您的 Counter 组件中,您应该添加以下代码行,这里我们将使用 DotNetObjectReference 设置组件的引用

注入 @inherits LayoutComponentBase @inject IJSRuntime js

在您的组件代码部分 -

 private int currentCount = 0;

    private DotNetObjectReference<Counter> jsToDotNetBridgeReference;
    protected override async Task OnInitializedAsync()
    
        jsToDotNetBridgeReference = DotNetObjectReference.Create(this);
        await js.InvokeVoidAsync("SetDotNetReference", jsToDotNetBridgeReference);
    


    [JSInvokable]
    private void IncrementCount()
    
        currentCount++;
    

[JSInvokable] 标识符帮助 dotnet 将此函数识别为从 JavaScript 调用的东西。

Step - 4 修改 Program.cs 和 index.html

修改您的 index.html 并将您的 div id 更改为 counter

接下来修改您的 program.cs 以在 html 中查找计数器 id。

第 5 步 - 将 dotnetreference 设置为 javascript 窗口对象

在 index.html 的 script 标签下添加以下脚本 -

window.SetDotNetReference = function (pDotNetReference) 
        DotNetReference = pDotNetReference;
    

这就是您在 blazor webassembly 应用程序上所要做的一切。

第 6 步 - 将您的 blazor 应用程序发布到文件夹。我现在使用默认位置。发布后,您将看到以下文件和文件夹,我们对 _framework 文件夹感兴趣。

发布完成后,将 _framework 文件夹复制到其他应用程序的根目录,如下所示 -

第 7 步 - 转到您想要的框架,现在我将使用淘汰赛 mvc 应用程序。

在您的 layout.cshtml 文件中添加对 blazor 库的引用,如下所示

<script src="~/_framework/blazor.webassembly.js" autostart="false"></script>

保留 autostart = false 是确保 Blazor 组件在不需要时不会加载的好方法。

第 8 步 - 创建 BlazorInterop.js

在您的框架项目中创建一个 js 文件,我喜欢将其命名为 BlazorInterop.js(可以是任何名称),然后在您的 layout.cshtml 中像这样引用它

<script src="~/BlazorInterop.js?" type="text/javascript"></script>

在 BlazorInterop.js 中,您将编写要从您的 blazor 应用程序中的主机应用程序执行的函数。像这样-

       IncrementCounter = function () 
    Blazor.start().then(()=> 
        DotNetReference.invokeMethodAsync('IncrementCounter');
    )
   

第 9 步 - 在layput.cshtml 中使用id=counter 创建一个div

创建一个 id=counter 的 div,这将有助于 blazor appp 识别它应该像这样种植组件的 div -

 <div id="counter"> 

    </div>
    <button type="button" onClick="IncrementCounter"> Increment Counter </button>

为了从页面加载时立即查看 blazor 组件,设置 autostart=true 否则,如果您想按需加载组件,我在主机应用程序中添加了一个按钮,以表明您可以根据需要调用 blazor 函数一旦组件被加载。

在您的 blazor interop.js 中,Blazor.start 将启动 blazor 应用程序,然后 DotNetReference.invokeMethodAsync 将触发 blazor 内的函数,并且计数器应递增。

第 10 步 - 在 web.config 中的 mvc 应用程序中添加 mime 类型,以便像这样提供静态内容 -

 <staticContent>
      <remove fileExtension=".wasm"/>
      <mimeMap fileExtension=".wasm" mimeType="application/wasm"/>
      <remove fileExtension=".dat"/>
      <mimeMap fileExtension=".dat" mimeType="application/dat"/>
      <remove fileExtension=".br"/>
      <mimeMap fileExtension=".br" mimeType="application/br"/>
      <remove fileExtension=".gz"/>
      <mimeMap fileExtension=".gz" mimeType="application/gz"/>
      <remove fileExtension=".blat"/>
      <mimeMap fileExtension=".blat" mimeType="application/blat"/>
      <remove fileExtension=".pdb"/>
      <mimeMap fileExtension=".pdb" mimeType="application/pdb"/>
      <remove fileExtension=".dll"/>
      <mimeMap fileExtension=".dll" mimeType="application/octet-stream"/>
      <remove fileExtension=".json"/>
      <mimeMap fileExtension=".json" mimeType="application/json"/>
    </staticContent>

完成了! 启动您的淘汰赛应用程序,您将能够看到该组件。

这基本上是我们在 mvc 淘汰应用程序中加载 blazor 组件所需发生的事情,这种方法也应该适用于任何其他框架,但是我不确定是否添加 mime 类型以在诸如 angulr 之类的框架中提供静态内容,反应等,但我相信一定有某种方式。我没有研究过。

可能会遇到一些错误,因此我将留下一些我在整个过程中提到的文档。

从 JS 调用 .Net 方法 https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0

从 .net 调用 JS 方法

https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-6.0

如何正确使用 blazor.start

https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/startup?view=aspnetcore-6.0

我花了很多时间来整理,这个特定的工作流程对我们很有效,并计划在月底发布生产版本。

这有助于我们在 Blazor 中为我们的应用程序开发新功能,从而在无需获取新资源的情况下推进新技术。

【讨论】:

【参考方案3】:

从 .NET 6 开始提供的一种可能性是通过调用 JSComponentConfigurationExtensions.RegisterForJavaScript 使 Blazor 组件可用于从 JavaScript 实例化。

我也处于想将现有 JS 应用程序逐步迁移到 Blazor 的情况。但是,它是一个 Angular 应用程序。为了评估可能的解决方案,我创建了一个演示迁移项目。有关代码和说明,请参阅我的 BlazorInAngularDemo github project 以及 working demo。但正如已经说过的,它专门针对 Angular。但也许一些想法,尤其是 README 文件中的一些想法,无论如何都可以帮助你。

【讨论】:

嗨,我能解决这个问题。我在这里发布了详细说明-medium.com/@kshitij.rangari92/…

以上是关于在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)的主要内容,如果未能解决你的问题,请参考以下文章

在 Blazor 组件之外设置 EventCallback<string>?

我可以在 blazor CSS 隔离之外制作外部样式吗?

除了 dbContext 之外,如何向 Blazor 中的服务添加参数?

服务器端 Blazor 与 MVC [关闭]

Blazor VS Vue

具有本机依赖关系的 Blazor .NET 6 无法构建为 Docker 映像