#c# #signalr
#c# #signalr
Вопрос:
У меня есть следующий код:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class SignalRHub : Attribute
{
public readonly string Route;
public SignalRHub(string Route)
{
this.Route = Route;
}
}
[SignalRHub("hubpath")]
public class TestHub : Hub
{
...
}
Это определяет концентратор SignalR с атрибутом для определения пути.
Я хочу динамически регистрировать концентраторы с атрибутом SignalRHub, поэтому у меня есть следующий код для поиска всех концентраторов:
// find all hubs
var Hubs =
from Assemblies in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
from Types in Assemblies.GetTypes()
let Attributes = Types.GetCustomAttributes(typeof(SignalRHub), true)
where Attributes?.Length > 0
select new { Type = Types };
var HubsList = Hubs.ToList();
и затем я хочу их зарегистрировать, но здесь у меня проблема:
foreach (var H in HubsList)
{
// get the route attribute
var Route = string.Empty;
var Attributes = Attribute.GetCustomAttributes(H.Type);
foreach (var Attribute in Attributes)
{
if (Attribute is SignalRHub A)
{
Route = A.Route;
break;
}
}
// register the hub
if (string.IsNullOrEmpty(Route))
{
Logging.Warn($"[Hub] {H.Type.Name} does not have a path, skipping");
}
else
{
Logging.Info($"[Hub] Registering {H.Type.Name} with path {Route}");
Application.UseSignalR(R => R.MapHub<H>(Route)); <- this won't compile
}
MapHub требует, чтобы T производился от Hub; поскольку H имеет тип TestHub, это должно быть нормально, но этот синтаксис не работает.
Как я могу заставить это работать?
Комментарии:
1. используйте тип вместо переменной, например
Application.UseSignalR(R => R.MapHub<Hub>(Route));
2. Вы должны искать нестандартную систему MapHub, принимающую 2 параметра. Тип и маршрут
3. Не отвечая прямо на вопрос, но, похоже, вы пытаетесь использовать полиморфизм странным образом. Было бы лучше обернуть каждый атрибут в класс about, который знает, как его отправлять, и ваша функция будет вызывать только метод отправки / маршрута атрибута. Тогда ответственность за выбор правильной оболочки атрибута ложится на создателя атрибута.
4. означает ли это, что использование типа, производного от (hub), нормально, и мне не нужно использовать реальный тип? @AndriyShevchenko, не существует универсального вызова MapHub
5. @DrPhil, я не понимаю; можете ли вы указать на пример этого?
Ответ №1:
Мое решение (использует отражение)
using System;
using System.Reflection;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections;
//somewhere in your code
private static readonly MethodInfo mapperMethodInfo =
typeof(HubRouteBuilder).GetMethod(
"MapHub",
new Type [] {
typeof(PathString)
},
null
);
// in your mapping code
// replace this:
Application.UseSignalR(R => R.MapHub<H>(Route));
// with this
Application.UseSignalR(R =>
{
// pay attention to use of H.Type, R and Route variables
mapperMethodInfo.MakeGenericMethod(H.Type).Invoke(R, new object [] { Route });
});
Ответ №2:
Компилятор недоволен, потому что вы используете переменную экземпляра в качестве универсального типа.
Поскольку переменная экземпляра H указывает на экземпляр концентратора, который вы можете заменить:
Application.UseSignalR(R => R.MapHub<H>(Route))
Автор::
Application.UseSignalR(R => R.MapHub<Hub>(Route))
Комментарии:
1. это не может работать, потому что тип ‘hub’ не может быть создан.
2. Здесь нет экземпляра концентратора (абстрактного класса), ваш TestHub наследует класс Hub, который делает его концентратором. Универсальные типы C # — это типы, не ссылающиеся на экземпляры.