Desenvolvimento das Funções do Azure e configuração com o Azure SignalR Service

Os aplicativos do Azure Functions podem usar as associações do Serviço Azure SignalR para adicionar recursos em tempo real. Os aplicativos cliente usam SDKs de cliente disponíveis em vários idiomas para se conectar ao Serviço Azure SignalR e receber mensagens em tempo real.

Este artigo descreve os conceitos para desenvolver e configurar um aplicativo do Azure Function integrado ao Serviço SignalR.

Configuração do Serviço SignalR

O Serviço Azure SignalR pode ser configurado em diferentes modos. Quando usado com o Azure Functions, o serviço deve ser configurado no modo sem servidor .

No portal do Azure, localize a página Configurações do seu recurso do Serviço SignalR. Defina o modo Serviço como Sem Servidor.

Modo de serviço SignalR

Desenvolvimento de Funções do Azure

Um aplicativo em tempo real sem servidor criado com o Azure Functions e o Serviço Azure SignalR requer pelo menos duas Funções do Azure:

  • Uma negotiate função que o cliente chama para obter um token de acesso do Serviço SignalR válido e uma URL de ponto de extremidade.
  • Uma ou mais funções que lidam com mensagens enviadas do Serviço SignalR para clientes.

Função de negociação

Um aplicativo cliente requer um token de acesso válido para se conectar ao Serviço Azure SignalR. Um token de acesso pode ser anônimo ou autenticado em um ID de usuário. Os aplicativos do Serviço SignalR sem servidor exigem um ponto de extremidade HTTP nomeado negotiate para obter um token e outras informações de conexão, como a URL do ponto de extremidade do Serviço SignalR.

Use uma Função do Azure acionada por HTTP e a SignalRConnectionInfo associação de entrada para gerar o objeto de informações de conexão. A função deve ter uma rota HTTP que termina em /negotiate.

Com o modelo baseado em classe em C#, você não precisa da SignalRConnectionInfo vinculação de entrada e pode adicionar declarações personalizadas muito mais facilmente. Para obter mais informações, consulte Experiência de negociação em modelo baseado em classe.

Para obter mais informações sobre a função, consulte Desenvolvimento do negotiate Azure Functions.

Para saber como criar um token autenticado, consulte Usando a autenticação do Serviço de Aplicativo.

Manipular mensagens enviadas do Serviço SignalR

Use a SignalRTrigger associação para manipular mensagens enviadas do Serviço SignalR. Você pode ser notificado quando os clientes enviarem mensagens ou se conectarem ou desconectarem.

Para obter mais informações, consulte a referência de vinculação de gatilho do Serviço SignalR.

Você também precisa configurar seu ponto de extremidade de função como um ponto de extremidade upstream para que o serviço acione a função quando houver uma mensagem de um cliente. Para obter mais informações sobre como configurar pontos de extremidade upstream, consulte Pontos de extremidade upstream.

Nota

O Serviço SignalR não suporta a StreamInvocation mensagem de um cliente no Modo sem Servidor.

Enviar mensagens e gerenciar a associação ao grupo

Use a SignalR associação de saída para enviar mensagens para clientes conectados ao Serviço Azure SignalR. Você pode transmitir mensagens para todos os clientes ou enviá-las para um subconjunto de clientes. Por exemplo, envie mensagens apenas para clientes autenticados com um ID de usuário específico ou apenas para um grupo específico.

Os usuários podem ser adicionados a um ou mais grupos. Você também pode usar a SignalR associação de saída para adicionar ou remover usuários de/para grupos.

Para obter mais informações, consulte a referência de vinculação de SignalR saída.

SignalR Hubs

SignalR tem um conceito de hubs. Cada conexão de cliente e cada mensagem enviada do Azure Functions tem como escopo um hub específico. Você pode usar hubs como uma maneira de separar suas conexões e mensagens em namespaces lógicos.

Modelo baseado em classe

O modelo baseado em classe é dedicado para C#.

O modelo baseado em classe fornece uma melhor experiência de programação, que pode substituir as ligações de entrada e saída do SignalR, com os seguintes recursos:

  • Negociação mais flexível, envio de mensagens e experiência de gestão de grupos.
  • Mais funcionalidades de gerenciamento são suportadas, incluindo fechar conexões, verificar se existe uma conexão, usuário ou grupo.
  • Hub fortemente tipado
  • Nome do hub unificado e configuração da cadeia de conexão em um só lugar.

O código a seguir demonstra como escrever ligações SignalR no modelo baseado em classe:

Em primeiro lugar, defina seu hub derivado de uma classe ServerlessHub:

[SignalRConnection("AzureSignalRConnectionString")]
public class Functions : ServerlessHub
{
    private const string HubName = nameof(Functions); // Used by SignalR trigger only

    public Functions(IServiceProvider serviceProvider) : base(serviceProvider)
    {
    }

    [Function("negotiate")]
    public async Task<HttpResponseData> Negotiate([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req)
    {
        var negotiateResponse = await NegotiateAsync(new() { UserId = req.Headers.GetValues("userId").FirstOrDefault() });
        var response = req.CreateResponse();
        response.WriteBytes(negotiateResponse.ToArray());
        return response;
    }

    [Function("Broadcast")]
    public Task Broadcast(
    [SignalRTrigger(HubName, "messages", "broadcast", "message")] SignalRInvocationContext invocationContext, string message)
    {
        return Clients.All.SendAsync("newMessage", new NewMessage(invocationContext, message));
    }

    [Function("JoinGroup")]
    public Task JoinGroup([SignalRTrigger(HubName, "messages", "JoinGroup", "connectionId", "groupName")] SignalRInvocationContext invocationContext, string connectionId, string groupName)
    {
        return Groups.AddToGroupAsync(connectionId, groupName);
    }
}

No arquivo Program.cs, registre seu hub sem servidor:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(b => b.Services
        .AddServerlessHub<Functions>())
    .Build();

Experiência de negociação em modelo class-based

Em vez de usar a ligação [SignalRConnectionInfoInput]de entrada SignalR, a negociação no modelo baseado em classe pode ser mais flexível. A classe ServerlessHub base tem um método NegotiateAsync, que permite aos usuários personalizar opções de negociação, como userId, claims, etc.

Task<BinaryData> NegotiateAsync(NegotiationOptions? options = null)

Envio de mensagens e gerenciamento de experiência em modelo baseado em classe

Você pode enviar mensagens, gerenciar grupos ou gerenciar clientes acessando os membros fornecidos pela classe ServerlessHubbase.

  • ServerlessHub.Clients para enviar mensagens aos clientes.
  • ServerlessHub.Groups para gerenciar conexões com grupos, como adicionar conexões a grupos, remover conexões de grupos.
  • ServerlessHub.UserGroups para gerenciar usuários com grupos, como adicionar usuários a grupos, remover usuários de grupos.
  • ServerlessHub.ClientManager para verificar a existência de conexões, fechar conexões, etc.

Hub fortemente tipado

O hub fortemente tipado permite que você use métodos fortemente tipados ao enviar mensagens para clientes. Para usar hub fortemente tipado no modelo baseado em classe, extraia métodos de cliente em uma interface Te torne sua classe de hub derivada de ServerlessHub<T>.

O código a seguir é um exemplo de interface para métodos de cliente.

public interface IChatClient
{
    Task newMessage(NewMessage message);
}

Em seguida, você pode usar os métodos fortemente tipados da seguinte maneira:

[SignalRConnection("AzureSignalRConnectionString")]
public class Functions : ServerlessHub<IChatClient>
{
    private const string HubName = nameof(Functions);  // Used by SignalR trigger only

    public Functions(IServiceProvider serviceProvider) : base(serviceProvider)
    {
    }

    [Function("Broadcast")]
    public Task Broadcast(
    [SignalRTrigger(HubName, "messages", "broadcast", "message")] SignalRInvocationContext invocationContext, string message)
    {
        return Clients.All.newMessage(new NewMessage(invocationContext, message));
    }
}

Nota

Você pode obter um exemplo de projeto completo do GitHub.

Nome do hub unificado e configuração da cadeia de conexão em um só lugar

  • O nome da classe do hub sem servidor é usado automaticamente como HubName.
  • Você pode ter notado o SignalRConnection atributo usado em classes de hub sem servidor da seguinte maneira:
    [SignalRConnection("AzureSignalRConnectionString")]
    public class Functions : ServerlessHub<IChatClient>
    
    Ele permite que você personalize onde está a cadeia de conexão para o hub sem servidor. Se estiver ausente, o valor AzureSignalRConnectionString padrão será usado.

Importante

Os gatilhos SignalR e os hubs sem servidor são independentes. Portanto, o nome da classe de hub sem servidor e SignalRConnection atributo não altera as configurações de gatilhos SignalR, mesmo que você use gatilhos SignalR dentro do hub sem servidor.

Desenvolvimento de clientes

Os aplicativos cliente SignalR podem usar o SDK do cliente SignalR em um dos vários idiomas para se conectar e receber facilmente mensagens do Serviço SignalR do Azure.

Configurando uma conexão de cliente

Para se conectar ao Serviço SignalR, um cliente deve concluir uma negociação de conexão bem-sucedida que consiste nestas etapas:

  1. Faça uma solicitação ao ponto de extremidade HTTP discutido negotiate acima para obter informações de conexão válidas
  2. Conectar-se ao Serviço SignalR usando a URL do ponto de extremidade do serviço e o token de acesso obtido do negotiate ponto de extremidade

Os SDKs do cliente SignalR já contêm a lógica necessária para executar o handshake de negociação. Passe a URL do ponto de extremidade de negociação, menos o negotiate segmento, para o SDK HubConnectionBuilder. Aqui está um exemplo em JavaScript:

const connection = new signalR.HubConnectionBuilder()
  .withUrl("https://my-signalr-function-app.azurewebsites.net/api")
  .build();

Por convenção, o SDK acrescenta /negotiate automaticamente à URL e a usa para iniciar a negociação.

Nota

Se você estiver usando o SDK JavaScript/TypeScript em um navegador, precisará habilitar o compartilhamento de recursos entre origens (CORS) em seu aplicativo de função.

Para obter mais informações sobre como usar o SDK do cliente SignalR, consulte a documentação do seu idioma:

Enviar mensagens de um cliente para o serviço

Se você tiver configurado upstream para seu recurso SignalR, poderá enviar mensagens de um cliente para o Azure Functions usando qualquer cliente SignalR. Aqui está um exemplo em JavaScript:

connection.send("method1", "arg1", "arg2");

Configuração do Azure Functions

Os aplicativos do Azure Function que se integram ao Serviço Azure SignalR podem ser implantados como qualquer aplicativo típico do Azure Function, usando técnicas como implantação contínua, implantação zip e execução a partir do pacote.

No entanto, há algumas considerações especiais para aplicativos que usam as associações do Serviço SignalR. Se o cliente for executado em um navegador, o CORS deverá ser habilitado. E se o aplicativo exigir autenticação, você poderá integrar o ponto de extremidade de negociação com a Autenticação do Serviço de Aplicativo.

Habilitando o CORS

O cliente JavaScript/TypeScript faz solicitação HTTP para a função de negociação para iniciar a negociação de conexão. Quando o aplicativo cliente é hospedado em um domínio diferente do aplicativo Azure Function, o compartilhamento de recursos entre origens (CORS) deve ser habilitado no aplicativo de função ou o navegador bloqueará as solicitações.

Localhost

Ao executar o aplicativo Função em seu computador local, você pode adicionar uma Host seção ao local.settings.json para habilitar o CORS. Host Na seção , adicione duas propriedades:

  • CORS - insira o URL base que é a origem do aplicativo cliente
  • CORSCredentials - defini-lo para true permitir solicitações "withCredentials"

Exemplo:

{
  "IsEncrypted": false,
  "Values": {
    // values
  },
  "Host": {
    "CORS": "http://localhost:8080",
    "CORSCredentials": true
  }
}

Nuvem - Azure Functions CORS

Para habilitar o CORS em um aplicativo do Azure Function, vá para a tela de configuração do CORS na guia Recursos da plataforma do seu aplicativo Function no portal do Azure.

Nota

A configuração do CORS ainda não está disponível no plano de Consumo do Linux do Azure Functions. Use o Gerenciamento de API do Azure para habilitar o CORS.

O CORS com Access-Control-Allow-Credentials deve estar habilitado para que o cliente SignalR chame a função de negociação. Para ativá-lo, marque a caixa de seleção.

Na seção Origens permitidas, adicione uma entrada com a URL base de origem do seu aplicativo Web.

Configurando o CORS

Nuvem - Gerenciamento de API do Azure

O Gerenciamento de API do Azure fornece um gateway de API que adiciona recursos aos serviços back-end existentes. Você pode usá-lo para adicionar CORS ao seu aplicativo de função. Oferece um nível de consumo com preço pago por ação e uma subvenção mensal gratuita.

Consulte a documentação do Gerenciamento de API para obter informações sobre como importar um aplicativo do Azure Function. Depois de importado, você pode adicionar uma política de entrada para habilitar o CORS com suporte a Access-Control-Allow-Credentials.

<cors allow-credentials="true">
  <allowed-origins>
    <origin>https://azure-samples.github.io</origin>
  </allowed-origins>
  <allowed-methods>
    <method>GET</method>
    <method>POST</method>
  </allowed-methods>
  <allowed-headers>
    <header>*</header>
  </allowed-headers>
  <expose-headers>
    <header>*</header>
  </expose-headers>
</cors>

Configure seus clientes SignalR para usar a URL de Gerenciamento de API.

Usando a autenticação do Serviço de Aplicativo

O Azure Functions tem autenticação incorporada, suportando fornecedores populares como o Facebook, Twitter, Conta Microsoft, Google e Microsoft Entra ID. Esse recurso pode ser integrado à associação para criar conexões com o SignalRConnectionInfo Serviço SignalR do Azure autenticado em uma ID de usuário. Seu aplicativo pode enviar mensagens usando a associação de SignalR saída direcionada a esse ID de usuário.

No portal do Azure, na guia Recursos da plataforma do seu aplicativo Function, abra a janela Configurações de autenticação/autorização. Siga a documentação da Autenticação do Serviço de Aplicativo para configurar a autenticação usando um provedor de identidade de sua escolha.

Uma vez configuradas, as solicitações HTTP autenticadas incluem x-ms-client-principal-name cabeçalhos contendo x-ms-client-principal-id o nome de usuário e o ID de usuário da identidade autenticada, respectivamente.

Você pode usar esses cabeçalhos em sua SignalRConnectionInfo configuração de vinculação para criar conexões autenticadas. Aqui está um exemplo de função de negociação C# que usa o x-ms-client-principal-id cabeçalho.

[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
    [SignalRConnectionInfo
        (HubName = "chat", UserId = "{headers.x-ms-client-principal-id}")]
        SignalRConnectionInfo connectionInfo)
{
    // connectionInfo contains an access key token with a name identifier claim set to the authenticated user
    return connectionInfo;
}

Em seguida, você pode enviar mensagens para esse usuário definindo a UserId propriedade de uma mensagem SignalR.

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message,
    [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage
        {
            // the message will only be sent to these user IDs
            UserId = "userId1",
            Target = "newMessage",
            Arguments = new [] { message }
        });
}

Para obter informações sobre outros idiomas, consulte a referência de ligações do Serviço Azure SignalR para o Azure Functions.

Próximos passos

Neste artigo, você aprenderá a desenvolver e configurar aplicativos do Serviço SignalR sem servidor usando o Azure Functions. Tente criar um aplicativo você mesmo usando um dos inícios rápidos ou tutoriais na página de visão geral do Serviço SignalR.