Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo fornece diretrizes para a criação de APIs baseadas em SignalR.
Usar parâmetros de objeto personalizados para garantir a compatibilidade com versões anteriores
Adicionar parâmetros a um SignalR método de hub (no cliente ou no servidor) é uma alteração significativa. Isso significa que os clientes/servidores mais antigos receberão erros quando tentarem invocar o método sem o número apropriado de parâmetros. No entanto, adicionar propriedades a um parâmetro de objeto personalizado não é uma alteração significativa. Isso pode ser usado para criar APIs compatíveis que são resilientes a alterações no cliente ou no servidor.
Por exemplo, considere uma API do lado do servidor como a seguinte:
public int GetTotalLength(string param1)
{
return param1.Length;
}
O cliente JavaScript chama esse método usando invoke da seguinte maneira:
connection.invoke("GetTotalLength", "value1");
Se posteriormente você adicionar um segundo parâmetro ao método de servidor, os clientes mais antigos não fornecerão esse valor de parâmetro. Por exemplo:
public int GetTotalLength(string param1, string param2)
{
return param1.Length + param2.Length;
}
Quando o cliente antigo tentar invocar esse método, ele receberá um erro como este:
Microsoft.AspNetCore.SignalR.HubException: Failed to invoke 'GetTotalLength' due to an error on the server.
No servidor, você verá uma mensagem de log como esta:
System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 2.
O cliente antigo enviou apenas um parâmetro, mas a API do servidor mais recente exigia dois parâmetros. Usar objetos personalizados como parâmetros oferece mais flexibilidade. Vamos reprojetar a API original para usar um objeto personalizado:
public class TotalLengthRequest
{
public string Param1 { get; set; }
}
public int GetTotalLength(TotalLengthRequest req)
{
return req.Param1.Length;
}
Agora, o cliente usa um objeto para chamar o método:
connection.invoke("GetTotalLength", { param1: "value1" });
Em vez de adicionar um parâmetro, adicione uma propriedade ao TotalLengthRequest objeto:
public class TotalLengthRequest
{
public string Param1 { get; set; }
public string Param2 { get; set; }
}
public int GetTotalLength(TotalLengthRequest req)
{
var length = req.Param1.Length;
if (req.Param2 != null)
{
length += req.Param2.Length;
}
return length;
}
Quando o cliente antigo envia um único parâmetro, a propriedade extra Param2 será deixada null. Você pode detectar uma mensagem enviada por um cliente mais antigo verificando o Param2 para null e aplicando um valor padrão. Um novo cliente pode enviar ambos os parâmetros.
connection.invoke("GetTotalLength", { param1: "value1", param2: "value2" });
A mesma técnica funciona para métodos definidos no cliente. Você pode enviar um objeto personalizado do lado do servidor:
public async Task Broadcast(string message)
{
await Clients.All.SendAsync("ReceiveMessage", new
{
Message = message
});
}
No lado do cliente, você acessa a Message propriedade em vez de usar um parâmetro:
connection.on("ReceiveMessage", (req) => {
appendMessageToChatWindow(req.message);
});
Se mais tarde você decidir adicionar o remetente da mensagem ao conteúdo, adicione uma propriedade ao objeto:
public async Task Broadcast(string message)
{
await Clients.All.SendAsync("ReceiveMessage", new
{
Sender = Context.User.Identity.Name,
Message = message
});
}
Os clientes mais antigos não estarão esperando o Sender valor, portanto, eles o ignorarão. Um novo cliente pode aceitá-lo atualizando para ler a nova propriedade:
connection.on("ReceiveMessage", (req) => {
let message = req.message;
if (req.sender) {
message = req.sender + ": " + message;
}
appendMessageToChatWindow(message);
});
Nesse caso, o novo cliente também é tolerante a um servidor antigo que não fornece o Sender valor. Como o servidor antigo não fornecerá o Sender valor, o cliente verifica se ele existe antes de acessá-lo.