SignalR Бессерверный Отчет О ходе выполнения

#signalr #azure-signalr

Вопрос:

Я пытаюсь создать тестовое приложение, чтобы моя HTML-страница могла отправлять сообщение длительно работающему методу функции Azure через SignalR, а длительно работающая функция может использовать SignalR для отправки отчета о ходе работы обратно на HTML-страницу.

Кто-нибудь знает, как это сделать? Я использую .NET Core 3.1 для функции и службы Azure SignalR в бессерверном режиме. Я посмотрел в Интернете, но, похоже, все дело в чате, в то время как я бы подумал, что это довольно распространенное требование.

Это то, что у меня есть до сих пор…

 using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace AzureSignalRFunctionTest
{
    public static class Function1
    {
        // Input Binding
        [FunctionName("negotiate")]
        public static SignalRConnectionInfo Negotiate(
            [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
            [SignalRConnectionInfo(HubName = "TestHub")] SignalRConnectionInfo connectionInfo)
        {
            return connectionInfo;
        }

        // Trigger Binding
        [FunctionName("longrunningtask")]
        public static void LongRunningTask([SignalRTrigger("longrunningtask", "messages", "SendMessage")] InvocationContext invocationContext, [SignalRParameter] string message, ILogger logger)
        {
            logger.LogInformation($"Receive {message} from {invocationContext.ConnectionId}.");

            // what to put here?
            //var clients = invocationContext.GetClientsAsync().Resu<

            //ReportProgress(invocationContext.ConnectionId, "Progress", ...);
            
            // Simulate Long running task
            System.Threading.Thread.Sleep(30000);
             
            // ReportProgress etc
        
        }

        // Output Binding
        [FunctionName("reportprogress")]
        public static Task ReportProgress(string connectionId, string message,
            [SignalR(HubName = "TestHub")] IAsyncCollector<SignalRMessage> signalRMessages)
        {
            return signalRMessages.AddAsync(
                new SignalRMessage
                {
                    ConnectionId = connectionId,
                    Target = "reportProgress",
                    Arguments = new[] { message }
                });
        }

    }
}
 

Ответ №1:

Ответ состоял в том, чтобы сделать это:

 using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

namespace MyAzureFunction
{
    public class TestHub : ServerlessHub
    {
        // Input Binding
        [FunctionName("negotiate")]
        public SignalRConnectionInfo Negotiate(
            [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
            [SignalRConnectionInfo(HubName="testhub")]SignalRConnectionInfo connectionInfo, ILogger logger)
        {
            logger.LogInformation($"ConnectionInfo: {connectionInfo.Url} {connectionInfo.AccessToken} {req.Path} {req.Query}");

            return connectionInfo;
        }

        // Trigger Binding
        [FunctionName("longrunningtask")]
        public async Task LongRunningTask(
            [SignalRTrigger] InvocationContext invocationContext,
            string message, ILogger logger)
        {
            logger.LogInformation($"Receive {message} from {invocationContext.ConnectionId}.");

            await Clients.Client(invocationContext.ConnectionId).SendAsync("reportProgress", message   " has started.");

            System.Threading.Thread.Sleep(10000);

            await Clients.Client(invocationContext.ConnectionId).SendAsync("reportProgress", message   " has ended.");
        }
    }
}
 

Html выглядел так:

 <h2>SignalR</h2>

<div id="messages"></div>

<form>
    <button type="submit" id="submitbtn">Submit</button>
</form>

@section Scripts {

    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.19/signalr.min.js"></script>
    <script>
        let messages = document.querySelector('#messages');
        const apiBaseUrl = 'https://myazurefunction.azurewebsites.net';
        const connection = new signalR.HubConnectionBuilder()
            .withUrl(apiBaseUrl   '/api')
            .configureLogging(signalR.LogLevel.Information)
            .build();

        connection.on('reportProgress', (message) => {
            document.getElementById("messages").innerHTML = message;
        });

        function onConnected(connection) {
            document.getElementById('submitbtn').addEventListener('click', function (event) {
                connection.send('longrunningtask', 'this is my message');
                event.preventDefault();
            });
        }

        connection.start()
            .then(function () {
                onConnected(connection)
            })
            .catch(console.error);
    </script>

}
 

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