Skip to content

Commit a6c163f

Browse files
Merge pull request #222523 from Y-Sindo/isolated
Add c# isolated worker for quick start sample
2 parents 719a173 + 5281bfa commit a6c163f

4 files changed

+171
-74
lines changed

articles/azure-signalr/signalr-quickstart-azure-functions-csharp.md

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,26 @@ ms.service: signalr
66
ms.devlang: csharp
77
ms.topic: quickstart
88
ms.custom: devx-track-csharp, mode-other
9-
ms.date: 03/30/2022
9+
ms.date: 12/28/2022
1010
ms.author: lianwei
1111
---
1212

1313
# Quickstart: Create an app showing GitHub star count with Azure Functions and SignalR Service via C#
1414

1515
In this article, you'll learn how to use SignalR Service and Azure Functions to build a serverless application with C# to broadcast messages to clients.
1616

17+
# [In-process](#tab/in-process)
18+
1719
> [!NOTE]
1820
> You can get the code mentioned in this article from [GitHub](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/QuickStartServerless/csharp).
1921
22+
# [Isolated process](#tab/isolated-process)
23+
24+
> [!NOTE]
25+
> You can get the code mentioned in this article from [GitHub](https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/QuickStartServerless/csharp-isolated).
26+
27+
---
28+
2029
## Prerequisites
2130

2231
The following prerequisites are needed for this quickstart:
@@ -37,6 +46,8 @@ You'll need the Azure Functions Core Tools for this step.
3746
1. Create an empty directory and change to the directory with the command line.
3847
1. Initialize a new project.
3948

49+
# [In-process](#tab/in-process)
50+
4051
```bash
4152
# Initialize a function project
4253
func init --worker-runtime dotnet
@@ -45,8 +56,22 @@ You'll need the Azure Functions Core Tools for this step.
4556
dotnet add package Microsoft.Azure.WebJobs.Extensions.SignalRService
4657
```
4758

59+
# [Isolated process](#tab/isolated-process)
60+
61+
```bash
62+
# Initialize a function project
63+
func init --worker-runtime dotnet-isolated
64+
65+
# Add extensions package references to the project
66+
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Http
67+
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.SignalRService
68+
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Timer
69+
```
70+
4871
1. Using your code editor, create a new file with the name *Function.cs*. Add the following code to *Function.cs*:
4972

73+
# [In-process](#tab/in-process)
74+
5075
```csharp
5176
using System;
5277
using System.IO;
@@ -59,15 +84,15 @@ You'll need the Azure Functions Core Tools for this step.
5984
using Microsoft.Azure.WebJobs.Extensions.Http;
6085
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
6186
using Newtonsoft.Json;
62-
87+
6388
namespace CSharp
6489
{
6590
public static class Function
6691
{
6792
private static HttpClient httpClient = new HttpClient();
6893
private static string Etag = string.Empty;
6994
private static string StarCount = "0";
70-
95+
7196
[FunctionName("index")]
7297
public static IActionResult GetHomePage([HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req, ExecutionContext context)
7398
{
@@ -78,15 +103,15 @@ You'll need the Azure Functions Core Tools for this step.
78103
ContentType = "text/html",
79104
};
80105
}
81-
106+
82107
[FunctionName("negotiate")]
83-
public static SignalRConnectionInfo Negotiate(
108+
public static SignalRConnectionInfo Negotiate(
84109
[HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
85110
[SignalRConnectionInfo(HubName = "serverless")] SignalRConnectionInfo connectionInfo)
86111
{
87112
return connectionInfo;
88113
}
89-
114+
90115
[FunctionName("broadcast")]
91116
public static async Task Broadcast([TimerTrigger("*/5 * * * * *")] TimerInfo myTimer,
92117
[SignalR(HubName = "serverless")] IAsyncCollector<SignalRMessage> signalRMessages)
@@ -104,15 +129,15 @@ You'll need the Azure Functions Core Tools for this step.
104129
var result = JsonConvert.DeserializeObject<GitResult>(await response.Content.ReadAsStringAsync());
105130
StarCount = result.StarCount;
106131
}
107-
132+
108133
await signalRMessages.AddAsync(
109134
new SignalRMessage
110135
{
111136
Target = "newMessage",
112137
Arguments = new[] { $"Current star count of https://github.com/Azure/azure-signalr is: {StarCount}" }
113138
});
114139
}
115-
140+
116141
private class GitResult
117142
{
118143
[JsonRequired]
@@ -123,6 +148,75 @@ You'll need the Azure Functions Core Tools for this step.
123148
}
124149
```
125150
151+
# [Isolated process](#tab/isolated-process)
152+
153+
```csharp
154+
using System.Net;
155+
using System.Net.Http.Json;
156+
using System.Text.Json.Serialization;
157+
using Microsoft.Azure.Functions.Worker;
158+
using Microsoft.Azure.Functions.Worker.Http;
159+
160+
namespace csharp_isolated;
161+
162+
public class Functions
163+
{
164+
private static readonly HttpClient HttpClient = new();
165+
private static string Etag = string.Empty;
166+
private static int StarCount = 0;
167+
168+
[Function("index")]
169+
public static HttpResponseData GetHomePage([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req)
170+
{
171+
var response = req.CreateResponse(HttpStatusCode.OK);
172+
response.WriteString(File.ReadAllText("content/index.html"));
173+
response.Headers.Add("Content-Type", "text/html");
174+
return response;
175+
}
176+
177+
[Function("negotiate")]
178+
public static HttpResponseData Negotiate([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
179+
[SignalRConnectionInfoInput(HubName = "serverless")] string connectionInfo)
180+
{
181+
var response = req.CreateResponse(HttpStatusCode.OK);
182+
response.Headers.Add("Content-Type", "application/json");
183+
response.WriteString(connectionInfo);
184+
return response;
185+
}
186+
187+
[Function("broadcast")]
188+
[SignalROutput(HubName = "serverless")]
189+
public static async Task<SignalRMessageAction> Broadcast([TimerTrigger("*/5 * * * * *")] TimerInfo timerInfo)
190+
{
191+
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/azure/azure-signalr");
192+
request.Headers.UserAgent.ParseAdd("Serverless");
193+
request.Headers.Add("If-None-Match", Etag);
194+
var response = await HttpClient.SendAsync(request);
195+
if (response.Headers.Contains("Etag"))
196+
{
197+
Etag = response.Headers.GetValues("Etag").First();
198+
}
199+
if (response.StatusCode == HttpStatusCode.OK)
200+
{
201+
var result = await response.Content.ReadFromJsonAsync<GitResult>();
202+
if (result != null)
203+
{
204+
StarCount = result.StarCount;
205+
}
206+
}
207+
return new SignalRMessageAction("newMessage", new object[] { $"Current star count of https://github.com/Azure/azure-signalr is: {StarCount}" });
208+
}
209+
210+
private class GitResult
211+
{
212+
[JsonPropertyName("stargazers_count")]
213+
public int StarCount { get; set; }
214+
}
215+
}
216+
```
217+
218+
---
219+
126220
The code in *Function.cs* has three functions:
127221
- `GetHomePage` is used to get a website as client.
128222
- `Negotiate` is used by the client to get an access token.
@@ -166,6 +260,11 @@ You'll need the Azure Functions Core Tools for this step.
166260
</ItemGroup>
167261
```
168262
263+
1. Azure Functions requires a storage account to work. You can install and run the [Azure Storage Emulator](../storage/common/storage-use-azurite.md). **Or** you can update the setting to use your real storage account with the following command:
264+
```bash
265+
func settings add AzureWebJobsStorage "<storage-connection-string>"
266+
```
267+
169268
1. It's almost done now. The last step is to set a connection string of the SignalR Service to Azure Function settings.
170269
171270
1. Confirm the SignalR Service instance was successfully created by searching for its name in the search box at the top of the portal. Select the instance to open it.
@@ -188,11 +287,8 @@ You'll need the Azure Functions Core Tools for this step.
188287
func start
189288
```
190289
191-
After the Azure function is running locally, open `http://localhost:7071/api/index` and you can see the current star count. If you star or unstar in the GitHub, you'll get a star count refreshing every few seconds.
290+
After the Azure function is running locally, open `http://localhost:7071/api/index`, and you can see the current star count. If you star or unstar in the GitHub, you'll get a star count refreshing every few seconds.
192291
193-
> [!NOTE]
194-
> SignalR binding needs Azure Storage, but you can use a local storage emulator when the function is running locally.
195-
> If you got the error `There was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid.` You need to download and enable [Storage Emulator](../storage/common/storage-use-emulator.md)
196292
197293
[!INCLUDE [Cleanup](includes/signalr-quickstart-cleanup.md)]
198294

articles/azure-signalr/signalr-quickstart-azure-functions-java.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ In this article, you'll use Azure SignalR Service, Azure Functions, and Java to
2222
- A code editor, such as [Visual Studio Code](https://code.visualstudio.com/)
2323
- An Azure account with an active subscription. If you don't already have an account, [create an account for free](https://azure.microsoft.com/free/?ref=microsoft.com&utm_source=microsoft.com&utm_medium=docs&utm_campaign=visualstudio).
2424
- [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools#installing). Used to run Azure Function apps locally.
25-
25+
2626
- The required SignalR Service bindings in Java are only supported in Azure Function Core Tools version 2.4.419 (host version 2.0.12332) or above.
2727
- To install extensions, Azure Functions Core Tools requires the [.NET Core SDK](https://dotnet.microsoft.com/download) installed. However, no knowledge of .NET is required to build Java Azure Function apps.
2828

@@ -52,13 +52,13 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
5252
| **groupId** | `com.signalr` | A value that uniquely identifies your project across all projects, following the [package naming rules](https://docs.oracle.com/javase/specs/jls/se6/html/packages.html#7.7) for Java. |
5353
| **artifactId** | `java` | A value that is the name of the jar, without a version number. |
5454
| **version** | `1.0-SNAPSHOT` | Choose the default value. |
55-
| **package** | `com.signalr` | A value that is the Java package for the generated function code. Use the default. |
55+
| **package** | `com.signalr` | A value that is the Java package for the generated function code. Use the default. |
5656

5757
1. Go to the folder `src/main/java/com/signalr` and copy the following code to *Function.java*:
5858

5959
```java
6060
package com.signalr;
61-
61+
6262
import com.google.gson.Gson;
6363
import com.microsoft.azure.functions.ExecutionContext;
6464
import com.microsoft.azure.functions.HttpMethod;
@@ -71,10 +71,10 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
7171
import com.microsoft.azure.functions.annotation.TimerTrigger;
7272
import com.microsoft.azure.functions.signalr.*;
7373
import com.microsoft.azure.functions.signalr.annotation.*;
74-
74+
7575
import org.apache.commons.io.IOUtils;
76-
77-
76+
77+
7878
import java.io.IOException;
7979
import java.io.InputStream;
8080
import java.net.URI;
@@ -84,24 +84,24 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
8484
import java.net.http.HttpResponse.BodyHandlers;
8585
import java.nio.charset.StandardCharsets;
8686
import java.util.Optional;
87-
87+
8888
public class Function {
8989
private static String Etag = "";
9090
private static String StarCount;
91-
91+
9292
@FunctionName("index")
9393
public HttpResponseMessage run(
9494
@HttpTrigger(
9595
name = "req",
9696
methods = {HttpMethod.GET},
9797
authLevel = AuthorizationLevel.ANONYMOUS)HttpRequestMessage<Optional<String>> request,
9898
final ExecutionContext context) throws IOException {
99-
99+
100100
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("content/index.html");
101101
String text = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
102102
return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "text/html").body(text).build();
103103
}
104-
104+
105105
@FunctionName("negotiate")
106106
public SignalRConnectionInfo negotiate(
107107
@HttpTrigger(
@@ -111,10 +111,10 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
111111
@SignalRConnectionInfoInput(
112112
name = "connectionInfo",
113113
hubName = "serverless") SignalRConnectionInfo connectionInfo) {
114-
114+
115115
return connectionInfo;
116116
}
117-
117+
118118
@FunctionName("broadcast")
119119
@SignalROutput(name = "$return", hubName = "serverless")
120120
public SignalRMessage broadcast(
@@ -132,10 +132,10 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
132132
GitResult result = gson.fromJson(res.body(), GitResult.class);
133133
StarCount = result.stargazers_count;
134134
}
135-
135+
136136
return new SignalRMessage("newMessage", "Current start count of https://github.com/Azure/azure-signalr is:".concat(StarCount));
137137
}
138-
138+
139139
class GitResult {
140140
public String stargazers_count;
141141
}
@@ -169,7 +169,7 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
169169
| | - main
170170
| | | - java
171171
| | | | - com
172-
| | | | | - signalr
172+
| | | | | - signalr
173173
| | | | | | - Function.java
174174
| | | - resources
175175
| | | | - content
@@ -183,7 +183,7 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
183183
184184
```html
185185
<html>
186-
186+
187187
<body>
188188
<h1>Azure SignalR Serverless Sample</h1>
189189
<div id="messages"></div>
@@ -198,15 +198,17 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
198198
connection.on('newMessage', (message) => {
199199
document.getElementById("messages").innerHTML = message;
200200
});
201-
201+
202202
connection.start()
203203
.catch(console.error);
204204
</script>
205205
</body>
206-
206+
207207
</html>
208208
```
209209
210+
1. Azure Functions requires a storage account to work. You can install and run the [Azure Storage Emulator](../storage/common/storage-use-azurite.md).
211+
210212
1. You're almost done now. The last step is to set a connection string of the SignalR Service to Azure Function settings.
211213
212214
1. Search for the Azure SignalR instance you deployed earlier using the **Search** box in Azure portal. Select the instance to open it.
@@ -234,10 +236,6 @@ Make sure you have Azure Function Core Tools, Java (version 11 in the sample), a
234236
235237
After Azure Function is running locally, go to `http://localhost:7071/api/index` and you'll see the current star count. If you star or "unstar" in the GitHub, you'll get a star count refreshing every few seconds.
236238
237-
> [!NOTE]
238-
> SignalR binding needs Azure Storage, but you can use local storage emulator when the Function is running locally.
239-
> If you got some error like `There was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid.` You need to download and enable [Storage Emulator](../storage/common/storage-use-emulator.md)
240-
241239
[!INCLUDE [Cleanup](includes/signalr-quickstart-cleanup.md)]
242240
243241
Having issues? Try the [troubleshooting guide](signalr-howto-troubleshoot-guide.md) or [let us know](https://aka.ms/asrs/qsjava).

0 commit comments

Comments
 (0)