-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SignalR] Add Strongly typed serverless hub (#25075)
# All SDK Contribution checklist: This checklist is used to make sure that common guidelines for a pull request are followed. - [x] **Please open PR in `Draft` mode if it is:** - Work in progress or not intended to be merged. - Encountering multiple pipeline failures and working on fixes. - [ ] If an SDK is being regenerated based on a new swagger spec, a link to the pull request containing these swagger spec changes has been included above. - [x] **I have read the [contribution guidelines](https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md).** - [x] **The pull request does not introduce [breaking changes](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-change-rules.md).** ### [General Guidelines and Best Practices](https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#general-guidelines) - [x] Title of the pull request is clear and informative. - [x] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### [Testing Guidelines](https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#testing-guidelines) - [x] Pull request includes test coverage for the included changes.
- Loading branch information
Showing
16 changed files
with
400 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
...ft.Azure.WebJobs.Extensions.SignalRService/samples/Sample01_StronglyTypedHub.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Strongly Typed Serverless Hub | ||
|
||
Strongly typed serverless hub is a programming model which allows you to define your SignalR client methods in an interface, and the RPC implementation will be done by SignalR. | ||
|
||
This sample demonstrates how to create a strongly typed serverless hub and invoke SignalR client methods in it. To see more details on serverless hub, please go [here](https://docs.microsoft.com/azure/azure-signalr/signalr-concept-serverless-development-config#class-based-model). | ||
|
||
## Define a strongly typed serverless hub class | ||
|
||
Let's say you want to invoke a SignalR client method `ReceiveMessage` with a string parameter when a HTTP request comes. | ||
|
||
Firstly you need to define an interface for the client method. | ||
|
||
```C# Snippet:StronglyTypedHub_ClientMethodInterface | ||
public interface IChatClient | ||
{ | ||
Task ReceiveMessage(string message); | ||
} | ||
``` | ||
|
||
Then you creates a strongly typed hub with the interface: | ||
|
||
```C# Snippet:StronglyTypedHub | ||
public class StronglyTypedHub : ServerlessHub<IChatClient> | ||
{ | ||
[FunctionName(nameof(Broadcast))] | ||
public async Task Broadcast([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest _, string message) | ||
{ | ||
await Clients.All.ReceiveMessage(message); | ||
} | ||
} | ||
``` | ||
|
||
## Call client methods | ||
|
||
The code snippet above defines a method in the hub, which broadcasts the message to all the clients once triggered by HTTP request. |
4 changes: 4 additions & 0 deletions
4
...oft.Azure.WebJobs.Extensions.SignalRService/src/Config/IInternalServiceHubContextStore.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Threading.Tasks; | ||
using Microsoft.Azure.SignalR; | ||
using Microsoft.Azure.SignalR.Management; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService | ||
{ | ||
internal interface IInternalServiceHubContextStore : IServiceHubContextStore | ||
{ | ||
AccessKey[] AccessKeys { get; } | ||
|
||
ValueTask<ServiceHubContext<T>> GetAsync<T>(string hubName) where T : class; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
...Microsoft.Azure.WebJobs.Extensions.SignalRService/src/TriggerBindings/ServerlessHubOfT.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using System.Threading.Tasks; | ||
using Azure.Core.Pipeline; | ||
using Microsoft.AspNetCore.SignalR; | ||
using Microsoft.Azure.SignalR.Management; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService | ||
{ | ||
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "https://github.com/Azure/azure-sdk-for-net/issues/17164")] | ||
public abstract class ServerlessHub<T> where T : class | ||
{ | ||
private static readonly Lazy<JwtSecurityTokenHandler> JwtSecurityTokenHandler = new(() => new JwtSecurityTokenHandler()); | ||
private readonly ServiceHubContext<T> _hubContext; | ||
|
||
/// <summary> | ||
/// Gets an object that can be used to invoke methods on the clients connected to this hub. | ||
/// </summary> | ||
public IHubClients<T> Clients => _hubContext.Clients; | ||
|
||
/// <summary> | ||
/// Get the group manager of this hub. | ||
/// </summary> | ||
public GroupManager Groups => _hubContext.Groups; | ||
|
||
/// <summary> | ||
/// Get the user group manager of this hub. | ||
/// </summary> | ||
public UserGroupManager UserGroups => _hubContext.UserGroups; | ||
|
||
/// <summary> | ||
/// Get the client manager of this hub. | ||
/// </summary> | ||
public ClientManager ClientManager => _hubContext.ClientManager; | ||
|
||
protected ServerlessHub(ServiceHubContext<T> serviceHubContext = null) | ||
{ | ||
if (serviceHubContext is null) | ||
{ | ||
serviceHubContext = ((IInternalServiceHubContextStore)StaticServiceHubContextStore.Get()).GetAsync<T>(GetType().Name).Result; | ||
} | ||
_hubContext = serviceHubContext; | ||
} | ||
|
||
/// <summary> | ||
/// Gets client endpoint access information object for SignalR hub connections to connect to Azure SignalR Service | ||
/// </summary> | ||
protected async Task<SignalRConnectionInfo> NegotiateAsync(NegotiationOptions options) | ||
{ | ||
var negotiateResponse = await _hubContext.NegotiateAsync(options).ConfigureAwait(false); | ||
return new SignalRConnectionInfo | ||
{ | ||
Url = negotiateResponse.Url, | ||
AccessToken = negotiateResponse.AccessToken | ||
}; | ||
} | ||
|
||
/// <summary> | ||
/// Get claim list from a JWT. | ||
/// </summary> | ||
protected static IList<Claim> GetClaims(string jwt) | ||
{ | ||
if (jwt.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
jwt = jwt.Substring("Bearer ".Length).Trim(); | ||
} | ||
return JwtSecurityTokenHandler.Value.ReadJwtToken(jwt).Claims.ToList(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
...gnalr/Microsoft.Azure.WebJobs.Extensions.SignalRService/tests/Samples/StronglyTypedHub.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Azure.WebJobs.Extensions.Http; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests.Samples | ||
{ | ||
#region Snippet:StronglyTypedHub | ||
public class StronglyTypedHub : ServerlessHub<IChatClient> | ||
{ | ||
[FunctionName(nameof(Broadcast))] | ||
public async Task Broadcast([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest _, string message) | ||
{ | ||
await Clients.All.ReceiveMessage(message); | ||
} | ||
} | ||
#endregion | ||
|
||
#region Snippet:StronglyTypedHub_ClientMethodInterface | ||
public interface IChatClient | ||
{ | ||
Task ReceiveMessage(string message); | ||
} | ||
#endregion | ||
} |
12 changes: 12 additions & 0 deletions
12
...oft.Azure.WebJobs.Extensions.SignalRService/tests/Trigger/StronglyTypedHub/IChatClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests | ||
{ | ||
public interface IChatClient | ||
{ | ||
Task ReceiveMessage(string message); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...nsions.SignalRService/tests/Trigger/StronglyTypedHub/StronglyTypedHubContextStoreTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Linq; | ||
using Microsoft.Azure.SignalR.Management; | ||
using Microsoft.Azure.SignalR.Tests.Common; | ||
using Xunit; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests.Trigger.StronglyTypedHub | ||
{ | ||
public class StronglyTypedHubContextStoreTests | ||
{ | ||
[Fact] | ||
public void GetStronglyTypedHubContextFact() | ||
{ | ||
var serviceManager = new ServiceManagerBuilder().WithOptions(o => o.ConnectionString = FakeEndpointUtils.GetFakeConnectionString(1).Single()).BuildServiceManager(); | ||
var hubContext = new ServiceHubContextStore(null, serviceManager).GetAsync<IChatClient>(GetType().Name).Result; | ||
} | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
...tensions.SignalRService/tests/Trigger/StronglyTypedHub/StronglyTypedServerlessHubTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.Azure.SignalR.Management; | ||
using Microsoft.Azure.SignalR.Tests.Common; | ||
using Xunit; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.SignalRService.Tests | ||
{ | ||
public class StronglyTypedServerlessHubTests | ||
{ | ||
[Fact] | ||
public async Task NegotiateAsync() | ||
{ | ||
var serviceManager = new ServiceManagerBuilder().WithOptions(o => o.ConnectionString = FakeEndpointUtils.GetFakeConnectionString(1).Single()).BuildServiceManager(); | ||
var hubContext = await serviceManager.CreateHubContextAsync<IChatClient>("hubName", default); | ||
var myHub = new TestStronglyTypedHub(hubContext); | ||
var connectionInfo = await myHub.Negotiate("user"); | ||
Assert.NotNull(connectionInfo); | ||
} | ||
} | ||
} |
Oops, something went wrong.