如何解决C#:如何在 Blazor Wasm Hosted 中将动态 Razor 组件从服务器发送到客户端?
我想在 Blazor wasm 托管项目中呈现动态剃刀组件。这些组件是使用 IDynamicComponent
接口在 Razor 类库中创建的。 Blazor 服务器端加载 dll 并将它们存储到 IEnumerable<Type>
中。问题是我无法通过 SignalR 将 System.Type
的各个组件发送到客户端并转换为 IDynamicComponent
。
IDynamicComponent.cs
public interface IDynamicComponent
{
IDictionary<Type,Type> InjectableDependencies { get; }
IDictionary<string,string> Parameters { get; }
string Name { get; }
Type Component { get;}
}
组件示例
MyComponent.cs
public class MyComponent : IDynamicComponent
{
public IDictionary<Type,Type> InjectableDependencies => new Dictionary<Type,Type>();
public IDictionary<string,string> Parameters => new Dictionary<string,string>();
public string Name => "Example1";
public Type Component => typeof(Component1);
}
Component1.razor
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Blazor 服务器端 加载组件
public IEnumerable<Type> Components { get; private set; }
// Loads the dlls and stores the components in the 'IEnumerable<Type>'
public void LoadComponents(string path)
{
var components = new List<Type>();
var assemblies = LoadAssemblies(path);
foreach (var asm in assemblies)
{
var types = GetTypesWithInterface(asm);
foreach (var typ in types) components.Add(typ);
}
Components = components;
}
// Gets the component by name
public IDynamicComponent GetComponentByName(string name)
{
return Components.Select(x => (IDynamicComponent)Activator.CreateInstance(x))
.SingleOrDefault(x => x.Name == name);
}
服务器端的 SignalR 函数
// Sends a component to client via SignalR when requested.
public async Task GetPlugin()
{
// Converting component of System.Type to object to send to client
string typeName = Component.FullName;
Type type = GetTypeFrom(typeName);
object obj = Activator.CreateInstance(type);
string component = JsonConvert.SerializeObject(obj);
await myHub.Clients.All.SendAsync("Plugin",component);
}
private Type GetTypeFrom(string valueType)
{
var type = Type.GetType(valueType);
if (type != null)
return type;
try
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//To speed things up,we check first in the already loaded assemblies.
foreach (var assembly in assemblies)
{
type = assembly.GetType(valueType);
if (type != null)
break;
}
if (type != null)
return type;
var loadedAssemblies = assemblies.ToList();
foreach (var loadedAssembly in assemblies)
{
foreach (AssemblyName referencedAssemblyName in loadedAssembly.GetReferencedAssemblies())
{
var found = loadedAssemblies.All(x => x.GetName() != referencedAssemblyName);
if (!found)
{
try
{
var referencedAssembly = Assembly.Load(referencedAssemblyName);
type = referencedAssembly.GetType(valueType);
if (type != null)
break;
loadedAssemblies.Add(referencedAssembly);
}
catch
{
//We will ignore this,because the Type might still be in one of the other Assemblies.
}
}
}
}
}
catch (Exception exception)
{
//throw my custom exception
}
if (type == null)
{
//throw my custom exception.
}
return type;
}
客户端的 SignalR
尝试将对象强制转换为 IDynamicComponent
时发生错误。
public IDynamicComponent Component;
hubConnection.On<string>("Plugin",(component) =>
{
object obj = JsonConvert.DeserializeObject<object>(component);
Console.WriteLine(obj.ToString());
// Casting object to 'IDynamicComponent' to be able to render
Component = (IDynamicComponent)obj; // Error occurs here
UpdateBlazorUIEvent?.Invoke();
});
浏览器控制台输出
{
"InjectableDependencies": {},"Parameters": {},"Name": "Counter","Component": "PluginOne.Component1,PluginOne,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null",}
Specified cast is not valid.
如何将组件 (System.Type
) 成功发送到客户端并转换为 IDynamicComponent
以呈现 UI?
解决方法
您不能通过 Json 传递 Types
。这正是错误所说的 - 不支持“System.Type”实例的序列化和反序列化。
您需要使用反射以字符串形式获取实际的完全限定类名称,通过 IDynamicComponent
传递它,例如 myassembly.myclass
,然后在另一端获取对象的新实例。
代码看起来像:
// In Code
var myclass = typeof(myComponent).AssemblyQualifiedName;
// Out code
var assembly = Assembly.GetExecutingAssembly();
var mytype = assembly.GetTypes().First(item => item.Name.Equals(className));
var myclass = Activator.CreateInstance(type);
传递泛型类型 object
也存在类似的问题。最近咬了我!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。