Skip to content

Commit 6fcdea8

Browse files
authored
Add SignalR function extension (Azure#24039)
* The first commit of SignalR extension * Add ci.yml * fix * fix .gitignore * Remove Java code * Standardize `Directory.Build.props` and dependencies * Remove E2E tests Will add them later. * Remove js,java sample codes and rename directories * Rename .sln file * Rename `src/SignalRServiceExtension` to `src/Microsoft.Azure.WebJobs.Extensions.SignalRService` * Rename `test/SignalRServiceExtension.Tests` to `test/Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests` * Rename `test` to `tests` * Remove unused items in sln file * Fix Protocols.csproj * Many fix * Remove Serverless protocol projects and move other codes * Fix target frameworks * Try fix code in srcs The problem is the $(RequiredTargetFrameworks) is netstandard2.0. But I need .net core 3.1. * Add SignalR nuget source for dev * Fix test project * Fix nuget source problem * Update `Packages.Data.props` * Remove `Management` project from `ci.yml` * Add `service.projects` * Remove samples * Add version and CHANGELOG.md * Fix docs * Fix readme. Add comparison of concept **SignalR Service client** and **SignalR client** * Export public APIs * Fix code snippets in readme * Fix warnings for src/* * Fix warnings for test/* * Add XML doc for public types * Remove unused file * Add code snippet for message trigger * remove gitignore file
1 parent fe2c29d commit 6fcdea8

File tree

129 files changed

+8257
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+8257
-1
lines changed

eng/Packages.Data.props

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
<PackageReference Update="Azure.Security.KeyVault.Certificates" Version="4.2.0" />
9292
<PackageReference Update="Azure.Storage.Blobs" Version="12.10.0" />
9393
<PackageReference Update="Azure.Storage.Queues" Version="12.8.0" />
94-
94+
9595
<!-- Other approved packages -->
9696
<PackageReference Update="Microsoft.Azure.Amqp" Version="2.5.6" />
9797
<PackageReference Update="Microsoft.Identity.Client" Version="4.30.1" />
@@ -111,6 +111,9 @@
111111
<ItemGroup Condition="'$(IsClientLibrary)' == 'true' and $(MSBuildProjectName.StartsWith('Microsoft.'))">
112112
<PackageReference Update="CloudNative.CloudEvents" Version="2.0.0" />
113113
<PackageReference Update="CloudNative.CloudEvents.SystemTextJson" Version="2.0.0" />
114+
<PackageReference Update="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="3.0.0" Condition="'$(TargetFramework)' == 'netcoreapp3.1'" />
115+
<PackageReference Update="Microsoft.Azure.SignalR.Management" Version="1.11.1-preview1-10853" />
116+
<PackageReference Update="Microsoft.Azure.SignalR.Serverless.Protocols" Version="1.6.0" />
114117
<PackageReference Update="Microsoft.Azure.WebJobs" Version="3.0.30" />
115118
<PackageReference Update="Microsoft.Azure.WebJobs.Sources" Version="3.0.30" />
116119
<PackageReference Update="Microsoft.Spatial" Version="7.5.3" />
@@ -126,6 +129,7 @@
126129
<ItemGroup Condition="'$(IsExtensionClientLibrary)' == 'true'">
127130
<PackageReference Update="Microsoft.AspNetCore.DataProtection" Version="2.1.0" />
128131
<PackageReference Update="Microsoft.AspNetCore.Http" Version="2.1.22" />
132+
<PackageReference Update="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
129133
<PackageReference Update="Microsoft.Extensions.Azure" Version="1.1.1" />
130134
<PackageReference Update="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.0" />
131135
<PackageReference Update="Microsoft.Extensions.Configuration" Version="2.1.0" />
@@ -181,6 +185,7 @@
181185
<PackageReference Update="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.3" />
182186
<PackageReference Update="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.1.25" />
183187
<PackageReference Update="Microsoft.AspNetCore.Server.WebListener" Version="1.0.6" />
188+
<PackageReference Update="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="1.1.5" />
184189
<PackageReference Update="Microsoft.AspNetCore.Http" Version="2.1.22" />
185190
<PackageReference Update="Microsoft.Azure.Core.Spatial" Version="1.0.0" />
186191
<PackageReference Update="Microsoft.Azure.Core.NewtonsoftJson" Version="1.0.0" />
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Release History
2+
3+
## 1.7.0-beta.1 (Unreleased)
4+
5+
### Features Added
6+
7+
### Breaking Changes
8+
9+
### Bugs Fixed
10+
11+
### Other Changes
12+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project>
2+
<PropertyGroup>
3+
<IsClientLibrary>true</IsClientLibrary>
4+
</PropertyGroup>
5+
6+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
7+
8+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31717.71
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FFE2667E-131F-40CE-8851-AFAECFBF89BB}"
7+
ProjectSection(SolutionItems) = preProject
8+
Directory.Build.props = Directory.Build.props
9+
nuget.config = nuget.config
10+
EndProjectSection
11+
EndProject
12+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.WebJobs.Extensions.SignalRService", "src\Microsoft.Azure.WebJobs.Extensions.SignalRService.csproj", "{02A467BA-E3F2-408D-AD49-CB317C430C53}"
13+
EndProject
14+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests", "tests\Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests.csproj", "{D1F82C66-8DF4-4622-BED6-7B6F11DABBAD}"
15+
EndProject
16+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{25AE2C7A-FD10-4A94-A063-857C542B7D45}"
17+
ProjectSection(SolutionItems) = preProject
18+
api\Microsoft.Azure.WebJobs.Extensions.SignalRService.netcoreapp3.1.cs = api\Microsoft.Azure.WebJobs.Extensions.SignalRService.netcoreapp3.1.cs
19+
api\Microsoft.Azure.WebJobs.Extensions.SignalRService.netstandard2.0.cs = api\Microsoft.Azure.WebJobs.Extensions.SignalRService.netstandard2.0.cs
20+
EndProjectSection
21+
EndProject
22+
Global
23+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
24+
Debug|Any CPU = Debug|Any CPU
25+
Release|Any CPU = Release|Any CPU
26+
EndGlobalSection
27+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
28+
{02A467BA-E3F2-408D-AD49-CB317C430C53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29+
{02A467BA-E3F2-408D-AD49-CB317C430C53}.Debug|Any CPU.Build.0 = Debug|Any CPU
30+
{02A467BA-E3F2-408D-AD49-CB317C430C53}.Release|Any CPU.ActiveCfg = Release|Any CPU
31+
{02A467BA-E3F2-408D-AD49-CB317C430C53}.Release|Any CPU.Build.0 = Release|Any CPU
32+
{D1F82C66-8DF4-4622-BED6-7B6F11DABBAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{D1F82C66-8DF4-4622-BED6-7B6F11DABBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{D1F82C66-8DF4-4622-BED6-7B6F11DABBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
35+
{D1F82C66-8DF4-4622-BED6-7B6F11DABBAD}.Release|Any CPU.Build.0 = Release|Any CPU
36+
EndGlobalSection
37+
GlobalSection(SolutionProperties) = preSolution
38+
HideSolutionNode = FALSE
39+
EndGlobalSection
40+
GlobalSection(ExtensibilityGlobals) = postSolution
41+
SolutionGuid = {227AD9AE-1447-4D8C-A014-50ABEC8E005C}
42+
EndGlobalSection
43+
EndGlobal
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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+
[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](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+
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fsignalr%2FMicrosoft.Azure.WebJobs.Extensions.SignalRService%2FREADME.png)
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

Comments
 (0)