Как я могу вызвать мой концентратор на моем контроллере (SignalR)? - PullRequest
0 голосов
/ 02 февраля 2020

Каждый раз, когда что-то публикуется и затем добавляется в базу данных, я хочу, чтобы это отображалось в моем Index.cs html. Прямо сейчас я делаю, как показано ниже. Однако эта опция не работает:

 [HttpPost]
    public async Task<IActionResult> PostIgnicoes([FromBody] Ignicoes ignicao)
    {
        **var hub = new MyHub();**
        if (ignicao.Latitude == null)
       {
        return BadRequest(ModelState);
    }
    else
    {
        if (ignicao.Longitude == null)
        {
            return BadRequest(ModelState);
        }
        else
        {
            //if(ignicao.Estado == null)
            //{
            //    return BadRequest(ModelState);
            //}

        }
    }

    _context.Ignicoes.Add(ignicao);


    **await hub.PostMarker();**
    await _context.SaveChangesAsync();


    return CreatedAtAction("GetIgnicoes", new { id = ignicao.Id }, ignicao);
}

Но каждый раз, когда я что-то публикую, выдается ошибка 500, что означает, что я ничего не могу опубликовать. Почему это происходит?

Ответы [ 2 ]

1 голос
/ 02 февраля 2020

Так я понял, что SignalR работает. Это может быть нечто большее, но создание чего-то похожего на то, что я объяснил ниже, позволило мне встраивать уведомления в реальном времени в приложение, которое я сейчас создаю.

Hub

The Hub для включения событий, отправляемых сервером, не нужно определять какие-либо методы. В основном это ловушка для других компонентов SignalR, которые вы подключаете. Итак, давайте создадим в основном пустой Hub, который я назову MapHub:

using Microsoft.AspNetCore.SignalR;

namespace YourApplicationNamespace
{
    public class MapHub : Hub
    {
    }
}

Вот и все. Кажется странным, но давайте продолжим.

IHubContext<T>

Это именно то, что вы будете использовать для отправки уведомления зарегистрированным клиентам. Вы должны зарегистрировать это в своем стартапе (или там, где настроен ваш DI-контейнер). Это делается для вас, когда вы используете что-то похожее на:

app.UseEndpoints(endpoints => {
    endpoints.MapHub<MapHub>("/notify"); 
});

"/notify" - это конечная точка, которую я собираюсь использовать для этого концентратора. Это то, что SignalR будет использовать для регистрации клиентов.

Затем обновите свой контроллер и добавьте IHubContext<MapHub> в качестве зависимости:

public class MapsController : Controller
{
    private readonly IHubContext<MapHub> hubContext;

    public MapsController(IHubContext<MapHub> hubContext)
    {
        this.hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
    }

    // ... the rest of your code

}

Как только это будет сделано, вы измените свое действие.

Уведомить клиентов для получения данных

Вместо вызова

**await hub.PostMarker();**

вы сделаете что-то вроде этого:

[HttpPost]
public async Task<IActionResult> PostIgnicoes([FromBody] Ignicoes ignicao)
{
    if (ignicao.Latitude == null)
    {
        return BadRequest(ModelState);
    }
    else
    {
        if (ignicao.Longitude == null)
        {
            return BadRequest(ModelState);
        }
    }

    _context.Ignicoes.Add(ignicao);

    await _context.SaveChangesAsync();

    // THIS IS THE NEW SIGNALR CODE
    await hubContext.Clients.All.SendAsync("getMarkers");

    return CreatedAtAction("GetIgnicoes", new { id = ignicao.Id }, ignicao);
}

Обратите внимание, что вы не не используйте напрямую Hub - этот класс предназначен в первую очередь для битов, которые подключены для вас через расширение .MapHub в Startup и код JavaScript, о котором мы еще не говорили.

Clients.All.SendAsync("getMarkers") сообщает SignalR отправить уведомление всем зарегистрированным клиентам и запускает событие getMarkers (определено ниже).

Настройка клиента

Я собираюсь Предположим, у вас уже есть клиентские скрипты SignalR, загруженные и загруженные на странице. Приведенный ниже код показывает, как я настраиваю свое соединение:

try {
    const connection = new signalR.HubConnectionBuilder()
        .withUrl('/notify')
        .withAutomaticReconnect()
        .configureLogging(signalR.LogLevel.Warning)
        .build();

    connection.on('getMarkers', function () {
        // ADD CODE HERE TO REQUEST NEW MARKERS
    });

    connection.start().then(function () {
        console.log("Hub connected");
    });
}
catch (err) {
    console.error(err);
}

Это более или менее готовый ie -резак из учебников по SignalR в Microsoft Docs. Ключевой частью является

    connection.on('getMarkers', function () {
        // ADD CODE HERE
    });

Вот так вы настраиваете «слушающую» конечную точку для ваших клиентов, которая является конечной точкой, называемой hubContext.Clients.All.SendAsync("getMarkers") (в моем примере). То, что вы делаете в // ADD CODE HERE, зависит от вас. Мой экземпляр использует функцию $ .load jQuery для перезагрузки боковой панели на моей странице.

1 голос
/ 02 февраля 2020

В SignalR Hub - это, по сути, набор «методов», которые клиент может вызывать. Так что это интерфейс, с которым работает клиент, точно так же, как контроллер будет работать для веб-API.

Если вы хотите вызывать методы на клиентах, то использование концентратора не является правильным подходом. Вместо этого вы хотите использовать IHubContext. Вам нужно будет вставить это в ваш контроллер.

public class HomeController : Controller
{
    private readonly IHubContext<MyHub> _hubContext;

    public HomeController(IHubContext<MyHub> hubContext)
    {
        _hubContext = hubContext;
    }

    [HttpPost]
    public async Task<IActionResult> PostIgnicoes([FromBody] Ignicoes ignicao)
    {
        //…

        await _hubContext.Clients.All.SendAsync("PostMarker");
        await _context.SaveChangesAsync();

        //…
    }
}

Для получения более подробной информации, ознакомьтесь с документацией по отправке сообщений извне концентратора . Это также можно сделать с помощью строго типизированных хабов , чтобы избежать необходимости вызова нетипизированных методов, передавая их имя в виде строки.

...