目录
使用Razor
服务你的Blazor
调试客户端(Edge版)
Blazor WebAssembly引起了人们极大的兴趣。开发人员最终能够使用他们选择的语言(例如C#)构建基于浏览器的单页应用程序(SPA)。在撰写本文时,Blazor WebAssembly处于预览状态。该团队计划在2020年5月发布该版本,以致力于增加功能并改善开发人员体验。Blazor WebAssembly项目的最大挑战之一是缺乏集成调试。
这里是正在缓慢演变的调试经验。同时,您可以遵循一些简单的步骤和做法来使生活更简单。
我遵循“最低公分母”的发展理念。我将可以在最广泛的范围内共享的东西拉到单独的组件中,并尝试使逻辑与框架实现脱钩。例如,我更喜欢使用Blazor MVVM模式,而不是将逻辑直接直接嵌入Razor组件内部。这使我可以使用Blazor,ASP.NET MVC,WPF甚至Xamarin(移动)项目之间共享的类库。下一个“层”是视图,使用Razor类库,用户界面(UI)也可以共享!
与其直接在Blazor项目中构建Razor组件,不如考虑将它们放在Razor类库中。Razor类库不限于本地组件;您还可以嵌入JavaScript,图像和其他共享资源。此博客文章中的代码全部包含在示例应用程序中:
JeremyLikness / AdvancedBlazor
首先,我创建了一个Razor类库并将其命名为BlazorApp.Shared。项目模板会生成一些默认文件,这些文件会被一些自定义组件覆盖。默认情况下,将嵌入一个JavaScript文件,该文件从提示中返回文本。
window.exampleJsFunctions = {
showPrompt: function (message) {
return prompt(message, 'Type anything here');
}
};
名为ExampleJsInterop的类提供了对JavaScript调用的包装。
public class ExampleJsInterop
{
public static ValueTask Prompt(IJSRuntime jsRuntime, string message)
{
// Implemented in exampleJsInterop.js
return jsRuntime.InvokeAsync(
"exampleJsFunctions.showPrompt",
message);
}
}
为了使在项目中的任何地方都可以轻松使用JavaScript互操作性,我向以下_Imports.razor代码添加了using语句:
@using Microsoft.JSInterop
接下来,我创建了一个名为Prompter.razor的组件,该组件在单击按钮时显示提示并更新一些文本。模板如下所示:
This Blazor component is defined in the BlazorApp.Shared package.
Prompt text: @Text
后面的代码使用JavaScript提示来检索文本并更新类的属性。
public string Text { get; set; } = "Click the button to change this.";
public async void GetText()
{
Text = await ExampleJsInterop.Prompt(JsRuntime, "Enter your text:");
StateHasChanged();
}
在此示例中,我使用模板生成的代码。与使用静态方法相比,更好的实现是为接口提供方法签名,并将实现注册为Startup类中的单例,然后在需要时将其注入。这将使单元测试更容易编写。
这个简单的组件的目的是说明如何编写自定义JavaScript并将其运送到共享库中。我创建了另一个名为ShowHost的组件,该组件显示的日期和托管(OS)平台,如System.Environment.OSVersion。您将在此博客文章的后面看到原因。模板:
Your environment is: @OS (last refreshed at: @Refresh)
后面的代码:
public string OS { get; set;} = "Not Set";
public string Refresh { get; set; } = "never";
protected override void OnInitialized()
{
DoRefresh();
}
public void DoRefresh()
{
OS = Environment.OSVersion.VersionString;
Refresh = DateTime.Now.ToString();
}
最后,我添加了一个Wrapper包装其他组件的控件,因此只需要在Blazor项目中删除一个组件即可。如果将来扩展该示例,则可以在Wrapper中嵌入其他组件,而无需更改托管项目。Wrapper组件有两个Prompter实例,以显示它可以在多个实例中正常工作。
Wrapper
Environment:
First prompt:
Second prompt:
Razor类库本身并没有做很多事情。它需要一个宿主项目。稍微加一点点,我创建的第一个项目是服务器端项目,而不是托管Blazor WebAssembly项目。
事实证明,Blazor具有几种不同的托管模式。尽管WebAssembly仍在预览中,但Blazor Server托管模型已准备好投入生产。您可以在官方文档中了解更多信息。我本人是WebAssembly的粉丝,但是有一些理由使使用服务器端项目有意义。首先,它可以引用Blazor WebAssembly使用的同一Razor类库。其次,它提供了完全集成的调试体验。只需设置您的断点,按F5键,就可以了!
在名为BlazorApp.Server的项目中,我添加了对BlazorApp.Shared的引用。接下来,我需要确保JavaScript文件已正确加载到我的应用程序中。幸运的是,Razor类库公开了一种非常简单的约定来访问嵌入式资源。相对于网页,您可以使用以下约定访问资源:_content/{assemblyname}/{filename}。要包含脚本,只需将以下script标记添加到_Host.cshtml:
这是一个手动步骤,必须对其他文件重复执行。Blazor团队有充分的理由不自动包含资源,例如资源的可能性和命名冲突。
接下来,我打开Index.razor并放入Wrapper组件:
@using BlazorApp.Shared
@page "/"
Hello, world!
Welcome to your new app.
为了调试“简便方法”,我在Prompter组件中StateHasChanged()的行上放置了一个断点,然后按F5键。我的应用程序使用操作系统版本(请注意是我的“服务器”或笔记本电脑版本)、日期和按钮进行渲染。
单击“输入文本”按钮之一将导致显示JavaScript提示,向我展示嵌入共享资源和JavaScript互操作性都在起作用。输入文本并单击“确定”后,将出现断点,并且我可以检查变量,修改属性,查看调用堆栈并执行我可能想要的几乎任何其他调试任务。现在代码看起来不错,是时候创建Blazor WebAssembly项目了!
创建名为BlazorApp.Client的Blazor WebAssembly项目后,我添加了对服务器端应用程序中使用的同一Razor类库(BlazorApp.Shared)的引用。我使用完全相同的约定来引用JavaScript,仅这次是将script标记放置在wwwroot下方的index.html中,而不是_Host.cshtml中。Index.razor修饰是相同的服务器端的版本。我将启动项目设置为客户端,然后按CTRL + F5启动它。结果看起来几乎相同……除了一个例外。您看到了吗?
万一您错过了它,“平台”将报告为Unix 1.0.0.0。这是因为该应用程序现在已完全通过WebAssembly在Mono的浏览器中运行。其余功能大致相同。
如果您现在需要调试应用程序该怎么办?如果打开调试控制台,您将看到以下消息:
Debugging hotkey: Shift+Alt+D (when application has focus)
很有可能是按下了组合键,结果出现了一个错误,说明了如何修复它。
如果您使用的是Chrome浏览器,那很好。请注意,您需要关闭所有现有的Chrome窗口,并且如果任务栏中有Chrome加速器,也请从中退出。
但是,如果您使用Edge,该怎么办?没问题!关闭所有打开的Edge实例,然后运行以下命令(我只是更改了路径以指向Edge安装,您的安装可能有所不同):
"%programfiles(x86)%\Microsoft\Edge Dev\Application\msedge.exe" --remote-debugging-port=9222 http://localhost:57955
不确定Edge安装的路径是什么?没问题。只需右键单击用于启动它的图标并进入属性。您应该看到带有路径的属性,或者带有“目标”属性的快捷方式选项卡,其中包含可执行文件的完整路径。
如果您的应用程序在其他端口上运行,请相应地更改URL。这应该再次启动该应用程序。按SHIFT + ALT + D组合键,将打开一个新标签,其中包含一些其他信息。这是我的样子:
您可以在file://下面扩展虚拟文件系统以浏览源代码,并将断点放在服务器端示例中使用的同一StateHasChanged()行上。跳回到主选项卡,单击提示,输入一些文本,然后单击“确定”。您应该看到“已在调试器中暂停”消息。转到调试选项卡,您现在可以看到已触发断点。可以在“范围”下展开右侧面板以检查变量和属性的值。
这就是魔术的结尾!
在此博客文章中,我们探讨了:
您可以从GitHub下拉项目:
JeremyLikness / AdvancedBlazor