#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>
}
Если вы отойдете от вызывающей страницы и вернетесь во время работы приложения-функции, он не покажет конечный результат. Если это требование, а не просто индикатор выполнения, то я думаю, что ответ заключается в аутентификации с помощью идентификатора пользователя, а затем отправке сообщений на этот идентификатор пользователя.