Я создал API в ядре .net с C#, который имеет набор элементов. В этой коллекции есть делегат, который срабатывает при добавлении (работе) нового элемента. Проблема в том, что я не могу заставить его работать, если не подпишусь на делегата от контроллера.
Текущий сценарий:
[HttpPost("welcome")]
public IActionResult Welcome([FromBody] MyClient newClient)
{
ClientsDataStore.Current.clients.Push(newClient);
return Ok(newClient);
}
Я создал класс MyClass:
public class MyClass
{
ILogger<MyClass> logger;
public MyClass(ILogger<MyClass> logger)
{
this.logger = logger;
ClientsDataStore.Current.clients.ElementAdded += ListenClients;
}
public async void ListenClients(object sender, MyClient e)
{
logger.LogDebug($"New client added");
if (e.VirtualMachine)
{
await ProcessVMAsync(e);
}
else
{
await ProcessDesktopAsync(e);
}
}
}
Я попытался зарегистрировать класс в public void ConfigureServices (службы IServiceCollection) следующим образом:
services.AddTransient<MyClass>();
В этом сценарии делегат никогда не запускается, но если я использую:
[HttpPost("welcome")]
public IActionResult Welcome([FromBody] MyClient newClient)
{
ClientsDataStore.Current.clients.ElementAdded += ListenClients;
ClientsDataStore.Current.clients.Push(newClient);
return Ok(newClient);
}
Затем запускается событие.
Я хотел бы знать, чего мне здесь не хватает, и как я мог это сделать.
ОБНОВИТЬ:
Я изменил подход к решению. У меня будет фоновая служба, проверяющая каждые 10 секунд, есть ли в коллекции новый элемент.
Вы знаете, что ваш класс выше никогда не будет освобожден, и у вас будет утечка памяти? События содержат ссылку на подписанный объект, и если вы не отмените подписку, для него всегда будет ссылка и, следовательно, он никогда не будет собираться сборщиком мусора. Также async avoid следует использовать НИКОГДА, за исключением обработчиков событий пользовательского интерфейса. И последнее, но не менее важное: MyClass никогда не разрешается и не создается экземпляр. Простая регистрация его в IoC не означает, что он будет создан. Он будет создан только тогда, когда это действительно необходимо в первый раз, а не раньше.
@HenkHolterman, что вы подразумеваете под «забудьте об использовании событий в asp.net»? Не рекомендуется?
Нет, asp.net не имеет состояния, а для событий требуется среда с отслеживанием состояния. Все, что вы используете, реконструируется при каждом новом запросе.
В любом случае, вы можете Разогрев использовать метод MyClass в методе Configure, но этот шаблон все равно грязный, и вы получите много проблем (MyClient является временным и будет удален в конце запроса, но вы используете async void, поэтому действие вашего контроллера не будет ждать конкуренции. Это приводит к завершению запроса, и все (одноразовые) переходные и ограниченные объекты будут удалены, что может произойти задолго до завершения вашего обратного вызова (или даже до его начала). Лучше используйте a слабосвязанный pub/sub или библиотека планирования (например, quart или hangfire)
@HenkHolterman: Что заставляет тебя так думать? ClientsDataStore кажется одноэлементным по шаблону, к которому он обращается (и не внедряется в MyClass). Шаблон singleton обычно включает вызов MyClass.Instance или MyClass.Current
Спасибо @Tseng. Не могли бы вы объяснить мне лучше об утечке памяти? Как решить проблему с асинхронная пустота? Пока я знаю, что все делегаты должны быть недействительными, не так ли? Насчет твоего Последний, но тем не менее важный (самое важное для меня ;) ) Заменил: services.AddTransient<Listeners>(); на: Listeners test1 = new Listeners(LoggerFactory); И вроде работает. Это лучший подход?
@Tseng - да, ClientsDataStore может быть синглтоном (статическим). Не должно быть, конечно.
@Tseng Вы правы, ClientsDataStore - это синглтон. Но у меня в памяти есть список клиентов, которые мне нужны, чтобы он был доступен с каждой конечной точки. Есть ли другой способ добиться этого?
Ответом будет внедрение ClientDataStore в контроллер с уже подключенным обработчиком событий.
Это звучит как хороший случай для шины событий. Вот пример, хотя он, возможно, немного устарел: scotthannen.org/blog/2016/04/01/event-bus-implementation.html. Или вы можете вводить функции/делегаты для выполнения непосредственно в свой класс. Эти функции могут быть статическими классами или методами классов, разрешенных контейнером.





Вы должны посмотреть время жизни объектов AddTransient и забыть об использовании событий в asp.net.