Skip to content

Commit 86c32d9

Browse files
authored
Merge pull request #104 from zackliu/eventgrid-sample
Event Grid integration sample
2 parents 8eaf219 + 25514ba commit 86c32d9

23 files changed

+1248
-0
lines changed
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
# Sample: Azure SignalR Service integration with Event Grid and Azure Function
2+
3+
A step by step tutorial to build a chat room with real-time online counting using Azure Functions, Event Grid, App Service Authentication, and SignalR Service.
4+
5+
- [Prerequisites](#prerequisites)
6+
- [Initialize the function app](#initialize-function-app)
7+
- [Deploy and run function app on Azure](#deploy-to-azure)
8+
- [Enable authentication on Azure](#enable-authentication)
9+
- [Build the sample locally](#build-locally)
10+
11+
<a name="prerequisites"></a>
12+
## Prerequisites
13+
14+
The following softwares are required to build this tutorial.
15+
16+
* [Node.js](https://nodejs.org/en/download/) (Version 10.x)
17+
* [.NET SDK](https://www.microsoft.com/net/download) (Version 2.x, required for Functions extensions)
18+
* [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) (Version 2)
19+
* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
20+
21+
### Create an Azure SignalR Service instance
22+
23+
No matter you want to build and test the Azure Functions app on Azure or locally. The app will access a SignalR Service instance in Azure that needs to be created ahead of time.
24+
25+
1. Create Azure SignalR Service using `az cli`
26+
27+
```bash
28+
az signalr create -n <signalr-name> -g <resource-group-name> --sku Free_F1
29+
```
30+
31+
For more details about creating Azure SignalR Service, see the [tutorial](https://docs.microsoft.com/en-us/azure/azure-signalr/signalr-quickstart-azure-functions-javascript#create-an-azure-signalr-service-instance).
32+
33+
1. After the instance is deployed, open it in the portal and locate its `Settings` page. Change the Service Mode setting to **Serverless**.
34+
35+
![signalr-serverless](media/signalr-serverless.png)
36+
37+
### Create a Storage account
38+
39+
An Azure Storage account is required by a function app using Event Grid trigger. You will also host the web page for the chat UI using the static websites feature of Azure Storage if you try to deploy the application to Azure.
40+
41+
- Create a storage with kind `StorageV2` using `az cli`
42+
43+
```bash
44+
az storage account create -n <storage-account-name> -g <resource-group-name> -l <location> --sku Standard_LRS --kind StorageV2
45+
```
46+
47+
<a name="initialize-function-app"></a>
48+
## Initialize the function app
49+
50+
- Git clone the project and open the folder with VS Code
51+
52+
```bash
53+
git clone [email protected]:aspnet/AzureSignalR-samples.git
54+
55+
cd AzureSignalR-samples/samples/EventGridIntegration/javascript
56+
```
57+
58+
### Configure application settings
59+
60+
When running and debugging the Azure Functions runtime locally, application settings are read from **local.settings.json**. Also, you can upload there settings to remote when you try to deploy Function App to Azure. Update this file with the connection string of the SignalR Service instance that you created earlier.
61+
62+
1. Open the file **local.settings.json** and update the settings.
63+
64+
```json
65+
{
66+
"IsEncrypted": false,
67+
"Values": {
68+
"AzureSignalRConnectionString": "<signalr-connection-string>",
69+
"WEBSITE_NODE_DEFAULT_VERSION": "10.14.1",
70+
"FUNCTIONS_WORKER_RUNTIME": "node",
71+
"AzureWebJobsStorage": "<Azure-storage-connection-string>",
72+
"AZURE_STORAGE_CONNECTION_STRING": "<Azure-storage-connection-string>"
73+
},
74+
"Host": {
75+
"LocalHttpPort": 7071,
76+
"CORS": "http://127.0.0.1:5500",
77+
"CORSCredentials": true
78+
}
79+
}
80+
```
81+
82+
- Replace `AzureSignalRConnectionString` with Azure SignalR Service connection string. Obtain the value from the **Keys** page in the Azure SignalR Service resource in the Azure portal; either the primary or secondary connection string can be used.
83+
84+
![Get SignalR Service key](media/signalr-get-key.png)
85+
86+
- Replace `AzureWebJobsStorage` and `AZURE_STORAGE_CONNECTION_STRING` with connection string of storage created previously. `AzureWebJobsStorage` is used by Event Grid trigger and the `AZURE_STORAGE_CONNECTION_STRING` is used by storage client in codes.
87+
88+
1. Save the file.
89+
90+
1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`) and select **Azure Functions: Initialize Project for Use with VSCode**.
91+
92+
1. Open the terminal and run `func extensions install` to install all the dependencies.
93+
94+
<a name="deploy-to-azure"></a>
95+
## Deploy and run function app on Azure
96+
97+
### Deploy function app to Azure
98+
99+
1. In the VS Code, install the [Azure Functions Extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions).
100+
101+
1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`) and select **Azure Functions: Deploy to Function App**.
102+
103+
1. When prompted, provide the following information.
104+
105+
| Name | Value |
106+
|---|---|
107+
| Folder to deploy | Select the main project folder |
108+
| Subscription | Select your subscription |
109+
| Function app | Select **Create New Function App** |
110+
| Function app name | Enter a unique name |
111+
| Resource group | Select the same resource group as the SignalR Service instance |
112+
| Storage account | Select the storage account you created earlier |
113+
114+
A new function app is created in Azure and the deployment begins. Wait for the deployment to complete.
115+
116+
### Upload function app local settings
117+
118+
1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).
119+
120+
1. Search for and select the **Azure Functions: Upload local settings** command.
121+
122+
1. When prompted, provide the following information.
123+
124+
| Name | Value |
125+
|---|---|
126+
| Local settings file | local.settings.json |
127+
| Subscription | Select your subscription |
128+
| Function app | Select the previously deployed function app |
129+
130+
Local settings are uploaded to the function app in Azure. If prompted to overwrite existing settings, select **Yes to all**.
131+
132+
### Configure static websites
133+
134+
We use **Static Website** to host the web page. Find the [document](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website) for more details.
135+
136+
1. Enable the static website feature
137+
138+
```bash
139+
az storage blob service-properties update --account-name <storage-account-name> --static-website --index-document index.html
140+
```
141+
142+
1. Get the url of function app
143+
144+
```bash
145+
hostname=$(az functionapp show -n <function-app-name> -g <resource-group-name> -o tsv --query defaultHostName)
146+
```
147+
148+
Replace the `apiBaseUrl` in `index.html` with the url `https://$(hostname)`
149+
150+
Upload the `index.html` to Azure Storage
151+
152+
```bash
153+
az storage blob upload-batch -s content -d \$web --account-name <storage-account-name>
154+
```
155+
156+
Get the primary url of website and save it for future use.
157+
158+
```bash
159+
az storage account show -n <storage-account-name> -g <resource-group-name> --query "primaryEndpoints.web" --output tsv
160+
```
161+
162+
### Subscribe Azure SignalR events
163+
164+
Subscribe to Azure SignalR OnConnected and OnDisconnected events and let Event Grid trigger be enabled.
165+
166+
1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).
167+
168+
1. Search for and select the **Azure Functions: Open in portal** command.
169+
170+
1. Select the Function `OnConnection` in the left panel. After the function shown, click `Add Event Grid subscription` and choose the Azure SignalR Service.
171+
![Add subscription](media/add-subscription.png)
172+
173+
1. Fill the page as shown below.
174+
![Subscribe Azure SignalR Service events](media/signalr-event-grid-subscribe.png)
175+
176+
### Enable function app cross origin resource sharing (CORS)
177+
178+
Although there is a CORS setting in **local.settings.json**, it is not propagated to the function app in Azure. You need to set it separately.
179+
180+
1. Open the function app in the Azure portal.
181+
182+
1. Under the **Platform features** tab, select **CORS**.
183+
184+
1. In the *Allowed origins* section, add an entry with the static website *primary endpoint* as the value (remove the trailing */*).
185+
186+
1. In order for the SignalR JavaScript SDK call your function app from a browser, support for credentials in CORS must be enabled. Select the "Enable Access-Control-Allow-Credentials" checkbox.
187+
188+
1. Click **Save** to persist the CORS settings.
189+
190+
### Try the application
191+
192+
1. In a browser, navigate to the storage account's primary web endpoint.
193+
194+
1. When you're connected, the online connection count is shown and you will get a welcome message.
195+
196+
1. Send public messages by entering them into the main chat box.
197+
198+
![Overview of the application](media/overview.png)
199+
200+
<a name="enable-authentication"></a>
201+
## Enable authentication on Azure
202+
203+
### Enable App Service Authentication
204+
205+
App Service Authentication supports authentication with Azure Active Directory, Facebook, Twitter, Microsoft account, and Google.
206+
207+
1. In the function app that was opened in the portal, locate the **Platform features** tab, select **Authentication/Authorization**.
208+
209+
1. Turn **On** App Service Authentication.
210+
211+
1. In **Action to take when request is not authenticated**, select "Allow Anonymous requests (no action)".
212+
213+
1. In **Allowed External Redirect URLs**, enter the URL of your storage account primary web endpoint that you previously noted.
214+
215+
1. Follow the documentation for the login provider of your choice to complete the configuration.
216+
217+
- [Azure Active Directory](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-aad)
218+
- [Facebook](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-facebook)
219+
- [Twitter](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-twitter)
220+
- [Microsoft account](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-microsoft)
221+
- [Google](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-google)
222+
223+
![Authentication](media/authentication.png)
224+
225+
### Update the web app
226+
227+
1. Open **index.html** and update the value of `isAuthNeeded` to `true`.
228+
229+
1. The application can be configured with authentication using Azure Active Directory, Facebook, Twitter, Microsoft account, or Google. Select the authentication provider that you will use by setting the value of `authProvider`.
230+
231+
1. Use **Azure Storage: Deploy to Static Website** command to upload the **index.html** to Azure Storage
232+
233+
### Update negotiate function
234+
235+
1. Update in `userId` in `negotiate/function.json` to `"{headers.x-ms-client-principal-name}"`
236+
237+
1. Deploy the function to Azure again
238+
239+
### Try the application with authentication
240+
241+
1. In a browser, navigate to the storage account's primary web endpoint.
242+
243+
1. Select **Login** to authenticate with your chosen authentication provider.
244+
245+
1. When you're connected, the online connection count is shown and you will get a welcome message.
246+
247+
1. Send public messages by entering them into the main chat box.
248+
249+
1. Send private messages by clicking on a username in the chat history. Only the selected recipient will receive these messages.
250+
251+
![Overview with auth](media/overview-with-auth.png)
252+
253+
<a name="build-locally"></a>
254+
## Build and run the sample locally
255+
256+
### Prerequisites
257+
258+
* [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) - serve web pages locally for testing
259+
* [ngrok](https://ngrok.com/) - Public URLs for exposing your local Event Grid trigger
260+
261+
### Create an ngrok endpoint
262+
263+
When running Event Grid trigger locally, you need a tool to proxy events to your local endpoint like [ngrok](https://ngrok.com/). For more details about running Event Grid trigger locally, go to the [document](https://docs.microsoft.com/en-us/azure/azure-functions/functions-debug-event-grid-trigger-local).
264+
265+
Download *ngrok.exe* from [ngrok](https://ngrok.com/), and run with the following command:
266+
267+
```
268+
ngrok http -host-header=localhost 7071
269+
```
270+
271+
The -host-header parameter is needed because the functions runtime expects requests from localhost when it runs on localhost. 7071 is the default port number when the runtime runs locally.
272+
273+
The command creates output like the following:
274+
275+
```
276+
Session Status online
277+
Version 2.2.8
278+
Region United States (us)
279+
Web Interface http://127.0.0.1:4040
280+
Forwarding http://263db807.ngrok.io -> localhost:7071
281+
Forwarding https://263db807.ngrok.io -> localhost:7071
282+
283+
Connections ttl opn rt1 rt5 p50 p90
284+
0 0 0.00 0.00 0.00 0.00
285+
```
286+
287+
You'll use the `https://{subdomain}.ngrok.io` URL for your Event Grid subscription.
288+
289+
### Run the Event Grid trigger function
290+
291+
The ngrok URL doesn't get special handling by Event Grid, so your function **must be running** locally when the subscription is created. If it isn't, the validation response doesn't get sent and the subscription creation fails.
292+
293+
### Create a subscription
294+
295+
Create an Event Grid subscription of SignalR Service, and give it your ngrok endpoint.
296+
297+
Use this endpoint pattern for Functions 2.x:
298+
299+
```
300+
https://{SUBDOMAIN}.ngrok.io/runtime/webhooks/eventgrid?functionName={FUNCTION_NAME}
301+
```
302+
303+
The `{FUNCTION_NAME}` parameter must be the name specified in the `FunctionName` attribute.
304+
305+
Here's an example to integrate with Azure SignalR Service using the Azure CLI:
306+
307+
```azurecli
308+
az eventgrid event-subscription create --resource-id <signalr-service-resource-id> --name <event-grid-subscription-name> --endpoint https://263db807.ngrok.io/runtime/webhooks/eventgrid?functionName=OnConnection
309+
```
310+
311+
## Run the client page and test
312+
313+
The chat application's UI is a simple single page application (SPA) created with the Vue JavaScript framework. It will be hosted separately from the function app. Locally, you will run the web interface using the Live Server VS Code extension.
314+
315+
1. Press **F5** to run the function app locally and attach a debugger.
316+
317+
1. With **index.html** open, start Live Server by opening the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`) and selecting **Live Server: Open with Live Server**. Live Server will open the application in a browser.
318+
- The `Host` section in **local.settings.json** configures the port and CORS settings for the local Functions host (this setting has no effect when running in Azure).
319+
320+
> [!NOTE]
321+
> Live Server is typically configured to serve content from `http://127.0.0.1:5500`. If you find that it is using a different URL or you are using a different HTTP server, change the `CORS` setting to reflect the correct origin.
322+
323+
1. The application opens. You will get a welcome message from `Function` and real-time connected connection counting. Also, you can broadcast message in the chat sample.

0 commit comments

Comments
 (0)