在上一篇文章中,我们介绍了“Blazor WebAssembly和Blazor Server的区别”。
你应该注意到,两种托管模式下的counter.razor实现完全相同。
这说明,同一Blazor组件既可以运行在Blazor WebAssembly模式下,也可以运行在Blazor Server模式下。从重用性上考虑,这种做法也是非常有必要的。
但是,有时又需要区分Blazor组件到底在何种托管模式下运行。比如WebAssembly模式下组件就不能传递机密数据。
那么,如何实现呢?
思考
我首先想到的方法,定义一个接口并分别实现,然后在运行时访问接口实例进行判断。例如:
public interface IIsWasm
{
bool IsWasm { get; }
}
//Blazor WebAssembly项目
public class BlazorWebAssemblyImpl: IIsWasm
{
public bool IsWasm => true;
}
//Blazor Server项目
public class BlazorServerImpl: IIsWasm
{
public bool IsWasm => false;
}
但是,转念一想,微软肯定已经用类似方式实现了Blazor常用接口,否则组件共享从何谈起,你觉得呢?
现在,我们只需要找到这些接口中的一个就行了!
发现
那么,首先从启动入口找起吧!
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
很幸运,刚开始查看WebAssemblyHostBuilder的实现,就看到这样一句:
var builder = new WebAssemblyHostBuilder(DefaultWebAssemblyJSRuntime.Instance);
DefaultWebAssemblyJSRuntime
这命名方式,不就明摆着告诉我们,它只在WebAssembly模式下才有的吗!
咦,你不觉得这名字有点眼熟?
让我们看下,它到底继承的什么接口!
一路沿源码找下去:
internal sealed class DefaultWebAssemblyJSRuntime : WebAssemblyJSRuntime
public abstract class WebAssemblyJSRuntime : JSInProcessRuntime, IJSUnmarshalledRuntime
public abstract class JSInProcessRuntime : JSRuntime, IJSInProcessRuntime
public abstract partial class JSRuntime : IJSRuntime, IDisposable
IJSRuntime
抓到你了!
这不就是JavaScript互操作要用到的接口吗?Blazor Server肯定也实现了这个接口。
验证
让我们看看2种模式下的实现:
@page "/"
@inject IJSRuntime JS
<p>@JS.GetType()</p>
哦了,确实是不同实现!
那么,你以后只需要判断IJSRuntime
实例的Type,就可以知道当前是运行在哪种模式了:
@page "/"
@inject IJSRuntime JS
<p>@IsWasm</p>
@code {
private bool IsWasm => JS.GetType().ToString()
.Contains("DefaultWebAssemblyJSRuntime");
}
结论
在本文中,我们发现,可以使用IJSRuntime
实例来判断当前运行在何种Blazor模式下。
不过,肯定还有其他方式可以实现。如果你知道,欢迎到公众号后台留言指教。
如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!