|
| 1 | +# Azure WebJobs SignalR Service client library for .NET |
| 2 | + |
| 3 | +This extension provides functionality for accessing [Azure SignalR Service](https://aka.ms/signalr_service) from an Azure Function. |
| 4 | + |
| 5 | +# Getting started |
| 6 | + |
| 7 | +### Install the package |
| 8 | + |
| 9 | +Install the SignalR Service client with [NuGet](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.SignalRService/): |
| 10 | + |
| 11 | +```dotnetcli |
| 12 | +dotnet add package Microsoft.Azure.WebJobs.Extensions.SignalRService |
| 13 | +``` |
| 14 | + |
| 15 | +### Prerequisites |
| 16 | + |
| 17 | +- **Azure Subscription:** To use Azure services, including Azure SignalR Service, you'll need a subscription. If you do not have an existing Azure account, you may sign up for a [free trial](https://azure.microsoft.com/free/dotnet/) or use your [Visual Studio Subscription](https://visualstudio.microsoft.com/subscriptions/) benefits when you [create an account](https://account.windowsazure.com/Home/Index). |
| 18 | + |
| 19 | +- **Azure SignalR resource:** To use SignalR Service client library you'll also need a Azure SignalR resource. If you are not familiar with creating Azure resources, you may wish to follow the step-by-step guide for creating a SignalR resource using the Azure portal. There, you can also find detailed instructions for using the Azure CLI, Azure PowerShell, or Azure Resource Manager (ARM) templates to create a SignalR resource. |
| 20 | + |
| 21 | +To quickly create the needed SignalR resource in Azure and to receive a connection string for them, you can deploy our sample template by clicking: |
| 22 | + |
| 23 | +[](https://portal.azure.com/#create/Microsoft.Template/uri/https%3a%2f%2fraw.githubusercontent.com%2fAzure%2fazure-quickstart-templates%2fmaster%2fquickstarts%2fmicrosoft.signalrservice%2fsignalr%2fazuredeploy.json) |
| 24 | + |
| 25 | + |
| 26 | +### Authenticate the client |
| 27 | + |
| 28 | +In order for SignalR Service client to access SignalR resource, it will need to understand how to authenticate with it. The easiest means for doing so is to use a connection string which can be found in the [Azure Portal](https://portal.azure.com/) or by using the [Azure CLI](https://docs.microsoft.com/cli/azure) / [Azure PowerShell](https://docs.microsoft.com/powershell/azure/) snippet below. |
| 29 | + |
| 30 | +Azure CLI snippet: |
| 31 | +```bash |
| 32 | +az signalr key list -n <your-resource-name> -g <your-resource-group-name> --query primaryKey -o tsv |
| 33 | +``` |
| 34 | + |
| 35 | +Azure PowerShell snippet: |
| 36 | +```Powershell |
| 37 | +Get-AzSignalRKey -ResourceGroupName <your-resource-name> -Name <your-resource-name> |
| 38 | +``` |
| 39 | + |
| 40 | +The `ConnectionStringSetting` property of SignalR bindings (including `SignalRAttribute`, `SignalRConnectionInfoAttribute`, `SignalRTriggerAttribute` etc.) is used to specify the configuration property that stores the connection string. If not specified, the property `AzureSignalRConnectionString` is expected to contain the connection string. |
| 41 | + |
| 42 | +For local development, use the `local.settings.json` file to store the connection string: |
| 43 | + |
| 44 | +```json |
| 45 | +{ |
| 46 | + "Values": { |
| 47 | + "<connection_name>": "<connection string>" |
| 48 | + } |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +When deployed, use the [application settings](https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings) to set the connection string. |
| 53 | + |
| 54 | +<!--TODO#### Identity-based Will reference a ms doc link once it is ready--> |
| 55 | + |
| 56 | +## Key concepts |
| 57 | + |
| 58 | +### SignalR **Service** client vs SignalR client |
| 59 | +SignalR **Service** client |
| 60 | +: It means this library. It provides *SignalR server* functionalities in a serverless style. |
| 61 | + |
| 62 | +SignalR client |
| 63 | +: An opposite concept of *SignalR server*. See [ASP.NET Core SignalR clients](https://docs.microsoft.com/aspnet/core/signalr/client-features) for more information. |
| 64 | + |
| 65 | +### SignalR connection info input binding |
| 66 | + |
| 67 | +`SignalRConnectionInfo` input binding makes it easy to generate the token required for SignalR clients to initiate a connection to Azure SignalR Service. |
| 68 | + |
| 69 | +Please follow the [Azure SignalR Connection Info input binding tutorial](https://docs.microsoft.com/azure/azure-functions/functions-bindings-signalr-service-input?tabs=csharp) to learn more about SignalR Connection Info input binding. |
| 70 | + |
| 71 | +### SignalR output binding |
| 72 | + |
| 73 | +`SignalR` output binding allows : |
| 74 | +* send messages to all connections, to a connection, to a user, to a group. |
| 75 | +* add/remove connections/users in a group. |
| 76 | + |
| 77 | +Please follow the [Azure SignalR output binding](https://docs.microsoft.com/azure/azure-functions/functions-bindings-signalr-service-output?tabs=csharp) to learn more about SignalR output binding. |
| 78 | + |
| 79 | +### SignalR trigger |
| 80 | + |
| 81 | +The SignalR trigger allows a function to be executed when a message is sent to Azure SignalR Service. |
| 82 | + |
| 83 | +Please follow the [Azure SignalR trigger](https://docs.microsoft.com/azure/azure-functions/functions-bindings-signalr-service-trigger?tabs=csharp) to learn more about SignalR trigger. |
| 84 | + |
| 85 | +## Supported scenarios |
| 86 | +- Negotiate for a SignalR client. |
| 87 | +- Broadcast messages to all SignalR clients connected to a SignalR Service hub. |
| 88 | +- Send messages to a single user, or all the users in a group. |
| 89 | +- Manage group users like add/remove a single user in a group. |
| 90 | +<!-- TODO: Add this point in next PR |
| 91 | +Use multiple Azure SignalR Service instances for resiliency and disaster recovery in Azure Functions. See details in [Multiple SignalR service endpoint support](./docs/sharding.md). |
| 92 | +--> |
| 93 | + |
| 94 | +## Examples |
| 95 | + |
| 96 | +### Negotiation for SignalR client |
| 97 | + |
| 98 | +In order for a client to connect to SignalR, it needs to obtain the SignalR client hub URL and an access token. We call the process as "negotiation". |
| 99 | + |
| 100 | +```C# Snippet:BasicNegotiate |
| 101 | +[FunctionName("Negotiate")] |
| 102 | +public static SignalRConnectionInfo Negotiate( |
| 103 | + [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req, |
| 104 | + [SignalRConnectionInfo(HubName = "<hub_name>", UserId = "<user_id>")] SignalRConnectionInfo connectionInfo) |
| 105 | +{ |
| 106 | + return connectionInfo; |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +### Broadcast individual messages |
| 111 | + |
| 112 | +To broadcast messages to all the connections in a hub from a single Azure Function invocation you can apply the `SignalR` attribute to the function return value. The return value should be of type `SignalRMessage`. |
| 113 | + |
| 114 | +```C# Snippet:SendMessageWithReturnValueBinding |
| 115 | +[FunctionName("sendOneMessageWithReturnValueBinding")] |
| 116 | +[return: SignalR(HubName = "<hub_name>")] |
| 117 | +public static SignalRMessage SendMessage( |
| 118 | + [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req) |
| 119 | +{ |
| 120 | + return new SignalRMessage |
| 121 | + { |
| 122 | + Target = "<target>", |
| 123 | + Arguments = new[] { "<here_can_be_multiple_objects>" } |
| 124 | + }; |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +You can also use an `out` parameter of type `SignalRMessage`. |
| 129 | +```C# Snippet:SendMessageWithOutParameterBinding |
| 130 | +[FunctionName("messages")] |
| 131 | +public static void SendMessage( |
| 132 | + [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req, [SignalR(HubName = "<hub_name>")] out SignalRMessage message) |
| 133 | +{ |
| 134 | + message = new SignalRMessage |
| 135 | + { |
| 136 | + Target = "<target>", |
| 137 | + Arguments = new[] { "<here_can_be_multiple_objects>" } |
| 138 | + }; |
| 139 | +} |
| 140 | +``` |
| 141 | +### Broadcast multiple messages |
| 142 | + |
| 143 | +To broadcast multiple messages to all the connections in a hub from a single Azure Function invocation you can apply the `SignalR` attribute to the `IAsyncCollector<SignalRMessage>` parameter. |
| 144 | + |
| 145 | +```C# Snippet:SendMessageWithAsyncCollector |
| 146 | +[FunctionName("messages")] |
| 147 | +public static Task SendMessage( |
| 148 | + [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req, |
| 149 | + [SignalR(HubName = "<hub_name>")] IAsyncCollector<SignalRMessage> signalRMessages) |
| 150 | +{ |
| 151 | + return signalRMessages.AddAsync( |
| 152 | + new SignalRMessage |
| 153 | + { |
| 154 | + Target = "<target>", |
| 155 | + Arguments = new[] { "<here_can_be_multiple_objects>" } |
| 156 | + }); |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +### Sending messages to a connection, user or group |
| 161 | + |
| 162 | +To send messages to a connection, user or group, the function is similar to broadcasting messages above, except that you specify `ConnectionId`, `UserId` or `GroupName` in the properties of `SignalRMessage`. |
| 163 | + |
| 164 | +Here is an example to send messages to a user using return value binding. |
| 165 | + |
| 166 | +```C# Snippet:SendMessageToUser |
| 167 | +[FunctionName("messages")] |
| 168 | +[return: SignalR(HubName = "<hub_name>")] |
| 169 | +public static SignalRMessage SendMessageToUser( |
| 170 | + [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req) |
| 171 | +{ |
| 172 | + return new SignalRMessage |
| 173 | + { |
| 174 | + UserId = "<user_id>", |
| 175 | + Target = "<target>", |
| 176 | + Arguments = new[] { "<here_can_be_multiple_objects>" } |
| 177 | + }; |
| 178 | +} |
| 179 | +``` |
| 180 | +### SignalR client connection trigger |
| 181 | + |
| 182 | +To trigger a function when a SignalR client gets connected or disconnected, you can apply the `SignalRTrigger` attribute to the `InvocationContext` parameter. |
| 183 | + |
| 184 | +Here is an example to log the connection ID when a SignalR client is connected. Make sure the second paramater of `SignalRTrigger` constructor is `connections`, which stands for the category of the trigger is connections. The third |
| 185 | +```C# Snippet:ConnectedTrigger |
| 186 | +[FunctionName("SignalRTest")] |
| 187 | +public static void Run([SignalRTrigger("<hubName>", "connections", "connected")] InvocationContext invocationContext, ILogger logger) |
| 188 | +{ |
| 189 | + logger.LogInformation($"{invocationContext.ConnectionId} was connected."); |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +### SignalR client message trigger |
| 194 | + |
| 195 | +To trigger a function when a SignalR client sends a message, you can apply the `SignalRTrigger` attribute to the `InvocationContext` parameter, apply the `SignalRParameter` attribute to each parameter whose name matches the parameter name in your message. |
| 196 | + |
| 197 | +Here is an example to log the message content when a SignalR client sends a message with target "SendMessage". |
| 198 | +```C# Snippet:MessageTrigger |
| 199 | +[FunctionName("SignalRTest")] |
| 200 | +public static void Run([SignalRTrigger("SignalRTest", "messages", "SendMessage")] InvocationContext invocationContext, [SignalRParameter] string message, ILogger logger) |
| 201 | +{ |
| 202 | + logger.LogInformation($"Receive {message} from {invocationContext.ConnectionId}."); |
| 203 | +} |
| 204 | +``` |
| 205 | + |
| 206 | +## Troubleshooting |
| 207 | + |
| 208 | +* Please refer to [Monitor Azure Functions](https://docs.microsoft.com/azure/azure-functions/functions-monitoring) for function troubleshooting guidance. |
| 209 | +* [Troubleshooting guide for Azure SignalR Service](https://docs.microsoft.com/azure/azure-signalr/signalr-howto-troubleshoot-guide) |
| 210 | + |
| 211 | +## Next steps |
| 212 | + |
| 213 | +Read the [introduction to Azure Functions](https://docs.microsoft.com/azure/azure-functions/functions-overview) or [creating an Azure Function guide](https://docs.microsoft.com/azure/azure-functions/functions-create-first-azure-function) |
| 214 | + |
| 215 | +## Contributing |
| 216 | + |
| 217 | +See our [CONTRIBUTING.md][contrib] for details on building, |
| 218 | +testing, and contributing to this library. |
| 219 | + |
| 220 | +This project welcomes contributions and suggestions. Most contributions require |
| 221 | +you to agree to a Contributor License Agreement (CLA) declaring that you have |
| 222 | +the right to, and actually do, grant us the rights to use your contribution. For |
| 223 | +details, visit [cla.microsoft.com][cla]. |
| 224 | + |
| 225 | +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. |
| 226 | +For more information see the [Code of Conduct FAQ][coc_faq] |
| 227 | +or contact [[email protected]][coc_contact] with any |
| 228 | +additional questions or comments. |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | +<!-- LINKS --> |
| 233 | +[nuget]: https://www.nuget.org/ |
| 234 | + |
| 235 | +[contrib]: https://github.com/Azure/azure-sdk-for-net/tree/main/CONTRIBUTING.md |
| 236 | +[cla]: https://cla.microsoft.com |
| 237 | +[coc]: https://opensource.microsoft.com/codeofconduct/ |
| 238 | +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ |
| 239 | +[coc_contact]: mailto:[email protected] |
0 commit comments