您是否也有想在浏览器中实时的编辑代码并且渲染的想法? - tokengo
source link: https://www.cnblogs.com/hejiale010426/p/17064106.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
不知道是否有人跟我一样想在浏览器上直接可以动态的编译blazor
的一些组件库?而不是通过引用NuGet
以后才能查看到效果,并且在使用别人的组件的时候可以在动态的调整组件的一些样式
不说了开始正文:
本文我们将使用Masa
提供的一个组件实现动态编译github.com直通车 ,执行环境将在WebAssembly
中执行,为什么使用WebAssembly
而不是Server
呢?首先我们需要先了解这俩种模式的执行原理
WebAssembly:
Blazor WebAssembly
是Blazor WebAssembly
,用于使用 .NET 生成交互式客户端 Web 应用。Blazor WebAssembly
使用无插件或将代码重新编译为其他语言的开放式 Web 标准。Blazor WebAssembly
适用于所有新式 Web 浏览器,包括移动浏览器。
Server:
-
Blazor Server
在ASP.NET Core
应用中支持在服务器上托管 Razor 组件。 可通过 SignalR 连接处理 UI 更新。运行时停留在服务器上并处理:
- 执行应用的 C# 代码。
- 将 UI 事件从浏览器发送到服务器。
- 将 UI 更新应用于服务器发送回的已呈现的组件。
由于编译是完全可操作的,存在安全问题,在Server的模式下用户编译的环境就是服务器的环境,这样用户就可以通过动态编译代码实现操作侵入安全,问题很严重,如果有心人使用对于安全影响过于严重,不建议在Server中使用动态编译
实现我们来创建一个空的WebAssembly项目
mkdir compileRazor
cd compileRazor
dotnet new blazorwasm-empty
使用vs打开项目添加Masa.Blazor.Extensions.Languages.Razor ,将一下代码添加到项目文件中
<PackageReference Include="Masa.Blazor.Extensions.Languages.Razor" Version="0.0.1" />
修改Program.cs
文件的代码
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using compileRazor;
using Masa.Blazor.Extensions.Languages.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
var app = builder.Build();
// 初始化RazorCompile
RazorCompile.Initialized(await GetReference(app.Services), await GetRazorExtension());
await app.RunAsync();
// 添加程序集引用
async Task<List<PortableExecutableReference>?> GetReference(IServiceProvider services)
{
#region WebAsembly
// need to add Service
var httpClient = services.GetService<HttpClient>();
var portableExecutableReferences = new List<PortableExecutableReference>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
//你需要通过网络获取程序集,应为无法通过程序集目录获取
var stream = await httpClient!.GetStreamAsync($"_framework/{assembly.GetName().Name}.dll");
if (stream.Length > 0)
{
portableExecutableReferences?.Add(MetadataReference.CreateFromStream(stream));
}
}
catch (Exception e) // There may be a 404
{
Console.WriteLine(e.Message);
}
}
#endregion
// 由于WebAssembly和Server返回portableexecutablerreference机制不同,需要分开处理
return portableExecutableReferences;
}
async Task<List<RazorExtension>> GetRazorExtension()
{
var razorExtension = new List<RazorExtension>();
foreach (var asm in typeof(Program).Assembly.GetReferencedAssemblies())
{
razorExtension.Add(new AssemblyExtension(asm.FullName, AppDomain.CurrentDomain.Load(asm.FullName)));
}
return razorExtension;
}
修改Pages\Index.razor
的代码
@page "/"
@using Masa.Blazor.Extensions.Languages.Razor;
<button class="button" @onclick="Run">刷新</button>
<div class="input-container">
<textarea @bind="Code" type="text" class="input-box" placeholder="请输入执行代码" >
</textarea>
</div>
@if (ComponentType != null)
{
<DynamicComponent Type="ComponentType"></DynamicComponent>
}
@code{
private string Code = @"<body>
<div id='app'>
<header>
<h1>Doctor Who™ Episode Database</h1>
</header>
<nav>
<a href='main-list'>Main Episode List</a>
<a href='search'>Search</a>
<a href='new'>Add Episode</a>
</nav>
<h2>Episodes</h2>
<ul>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
<footer>
Doctor Who is a registered trademark of the BBC.
https://www.doctorwho.tv/
</footer>
</div>
</body>";
private Type? ComponentType;
private void Run()
{
ComponentType = RazorCompile.CompileToType(new CompileRazorOptions()
{
Code = Code // TODO: 在WebAssembly下保证ConcurrentBuild是false 因为Webassembly不支持多线程
});
StateHasChanged();
}
}
<style>
.button{
width: 100%;
font-size: 22px;
background-color: cornflowerblue;
border: 0px;
margin: 5px;
border-radius: 5px;
height: 40px;
}
.input-container {
width: 500px;
margin: 0 auto;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
.input-box {
width: 100%;
height: 100px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 14px;
}
</style>
然后启动程序效果如图:
首次编译会比较慢,在WebAssembly
下还可以因为电脑问题造成卡顿,如果是需要提供开发效率可以使用Server调试,在Server调试的话是比WebAssembly
快很多,而且WebAssembly
还没有做Aot,性能不会太好
来自token的分享
技术交流群:737776595
推荐一个超级好用的Blazor UI
组件 MASA Blazor 开源协议 MIT
商用完全没问题
本文作者:tokengo
本文链接:https://www.cnblogs.com/hejiale010426/p/17064106.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK