Do you have an idea to dynamically compile razor components in the browser?

blazorI don't know if anyone wants to dynamically compile some component libraries directly on the browser like me ? Instead of NuGetviewing the effect after reference, and when using other people's components, you can dynamically adjust some styles of the components

Not to mention the beginning of the text:

In this article, we will use Masaa component provided to implement dynamic compilation of github.com through-train , and the execution environment will WebAssemblybe executed in it. Why WebAssemblynot use Serverit? First of all, we need to understand the execution principles of these two modes

WebAssembly:

  • Blazor WebAssemblyYes Blazor WebAssembly, for building interactive client-side web applications using .NET. Blazor WebAssemblyUse open web standards without plug-ins or recompiling code into other languages. Blazor WebAssemblyWorks with all modern web browsers, including mobile browsers.

Server:

  • Blazor ServerHosting Razor components on the server is supported in ASP.NET Corethe app . UI updates can be handled over a SignalR connection.

    The runtime stays on the server and processes:

    • Execute the application's C# code.
    • Send UI events from browser to server.
    • Applies UI updates to rendered components sent back by the server.

Since the compilation is completely operable, there are security issues. In the Server mode, the user's compilation environment is the server environment, so that the user can dynamically compile the code to achieve operational intrusion security. The problem is very serious. Seriously, it is not recommended to use dynamic compilation in Server

Implementation Let's create an empty WebAssembly project

mkdir compileRazor
cd compileRazor
dotnet new blazorwasm-empty

Use vs to open the project and add Masa.Blazor.Extensions.Languages.Razor , add the following code to the project file

    <PackageReference Include="Masa.Blazor.Extensions.Languages.Razor" Version="0.0.1" />

Modify Program.csthe code of the file

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

modified Pages\Index.razorcode


@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&trade; 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>

Then the effect of starting the program is as shown in the figure:

The first compilation will be slower, WebAssemblyand it may be stuck due to computer problems. If you need to improve development efficiency, you can use Server debugging. Debugging on Server is WebAssemblymuch faster than that, and WebAssemblyit has not done Aot, so the performance will not be very good.

Sharing from token

Technical exchange group: 737776595

Recommend a super easy-to-use Blazor UIcomponent MASA Blazor open source protocol, MITcommercial use is no problem at all

おすすめ

転載: blog.csdn.net/xiaohucxy/article/details/128742415