Skip to content

Commit a314e55

Browse files
committed
Update to leave the net 6 version only
1 parent 3463a71 commit a314e55

File tree

1 file changed

+12
-256
lines changed

1 file changed

+12
-256
lines changed

articles/azure-web-pubsub/tutorial-build-chat.md

Lines changed: 12 additions & 256 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ Copy the fetched **ConnectionString** and it will be used later in this tutorial
4747

4848
# [C#](#tab/csharp)
4949

50-
* [ASP.NET Core 3.1 or above](/aspnet/core)
51-
52-
# [C# .NET 6](#tab/net6)
53-
5450
* [ASP.NET Core 6](/aspnet/core)
5551

5652
# [JavaScript](#tab/javascript)
@@ -72,134 +68,6 @@ In this tutorial, we'll build a real-time chat web application. In a real web ap
7268

7369
# [C#](#tab/csharp)
7470

75-
We'll use [ASP.NET Core](/aspnet/core) to host the web pages and handle incoming requests.
76-
77-
First let's create an empty ASP.NET Core app.
78-
79-
1. Create web app
80-
81-
```bash
82-
dotnet new web
83-
dotnet add package Microsoft.Azure.WebPubSub.AspNetCore --version 1.0.0-beta.3
84-
```
85-
86-
2. Then add `app.UseStaticFiles();` before `app.UseRouting();` in `Startup.cs` to support static files. Remove the default `endpoints.MapGet` inside `app.UseEndpoints`.
87-
88-
```csharp
89-
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
90-
{
91-
if (env.IsDevelopment())
92-
{
93-
app.UseDeveloperExceptionPage();
94-
}
95-
96-
app.UseStaticFiles();
97-
app.UseRouting();
98-
99-
app.UseEndpoints(endpoints =>
100-
{
101-
});
102-
}
103-
```
104-
105-
3. Also create an HTML file and save it as `wwwroot/index.html`, we'll use it for the UI of the chat app later.
106-
107-
```html
108-
<html>
109-
<body>
110-
<h1>Azure Web PubSub Chat</h1>
111-
</body>
112-
</html>
113-
```
114-
115-
You can test the server by running `dotnet run --urls http://localhost:8080` and access http://localhost:8080/index.html in browser.
116-
117-
You may remember in the [publish and subscribe message tutorial](./tutorial-pub-sub-messages.md) the subscriber uses an API in Web PubSub SDK to generate an access token from connection string and use it to connect to the service. This is usually not safe in a real world application as connection string has high privilege to do any operation to the service so you don't want to share it with any client. Let's change this access token generation process to a REST API at server side, so client can call this API to request an access token every time it needs to connect, without need to hold the connection string.
118-
119-
1. Install dependencies.
120-
121-
```bash
122-
dotnet add package Microsoft.Extensions.Azure
123-
```
124-
125-
2. Add a `SampleChatHub` class to handle hub events. And DI the service middleware and service client inside `ConfigureServices()`. Don't forget to replace `<connection_string>` with the one of your services.
126-
127-
```csharp
128-
public void ConfigureServices(IServiceCollection services)
129-
{
130-
services.AddWebPubSub(o => o.ServiceEndpoint = new ServiceEndpoint("<connection_string>"))
131-
.AddWebPubSubServiceClient<SampleChatHub>();
132-
}
133-
134-
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
135-
{
136-
if (env.IsDevelopment())
137-
{
138-
app.UseDeveloperExceptionPage();
139-
}
140-
141-
app.UseStaticFiles();
142-
app.UseRouting();
143-
144-
app.UseEndpoints(endpoints =>
145-
{
146-
});
147-
}
148-
149-
private sealed class SampleChatHub : WebPubSubHub
150-
{
151-
}
152-
```
153-
154-
`AddWebPubSubServiceClient<THub>()` is used to inject the service client `WebPubSubServiceClient<THub>`, with which we can use in negotiation step to generate client connection token and in hub methods to invoke service REST APIs when hub events are triggered.
155-
156-
3. Add a `/negotiate` API to the server inside `app.UseEndpoints` to generate the token.
157-
158-
```csharp
159-
app.UseEndpoints(endpoints =>
160-
{
161-
endpoints.MapGet("/negotiate", async context =>
162-
{
163-
var id = context.Request.Query["id"];
164-
if (id.Count != 1)
165-
{
166-
context.Response.StatusCode = 400;
167-
await context.Response.WriteAsync("missing user id");
168-
return;
169-
}
170-
var serviceClient = context.RequestServices.GetRequiredService<WebPubSubServiceClient<SampleChatHub>>();
171-
await context.Response.WriteAsync(serviceClient.GetClientAccessUri(userId: id).AbsoluteUri);
172-
});
173-
});
174-
```
175-
176-
This token generation code is similar to the one we used in the [publish and subscribe message tutorial](./tutorial-pub-sub-messages.md), except we pass one more argument (`userId`) when generating the token. User ID can be used to identify the identity of client so when you receive a message you know where the message is coming from.
177-
178-
You can test this API by running `dotnet run --urls http://localhost:8080` and accessing `http://localhost:8080/negotiate?id=<user-id>` and it will give you the full url of the Azure Web PubSub with an access token.
179-
180-
4. Then update `index.html` to include the following script to get the token from server and connect to service.
181-
182-
```html
183-
<html>
184-
<body>
185-
<h1>Azure Web PubSub Chat</h1>
186-
</body>
187-
188-
<script>
189-
(async function () {
190-
let id = prompt('Please input your user name');
191-
let res = await fetch(`/negotiate?id=${id}`);
192-
let url = await res.text();
193-
let ws = new WebSocket(url);
194-
ws.onopen = () => console.log('connected');
195-
})();
196-
</script>
197-
</html>
198-
```
199-
200-
If you are using Chrome, you can test it by opening the home page, input your user name. Press F12 to open the Developer Tools window, switch to **Console** table and you'll see `connected` being printed in browser console.
201-
202-
# [C# .NET 6](#tab/net6)
20371
We'll use [ASP.NET Core 6](/aspnet/core) to host the web pages and handle incoming requests.
20472

20573
First let's create an empty ASP.NET Core app.
@@ -210,15 +78,14 @@ First let's create an empty ASP.NET Core app.
21078
dotnet new web
21179
dotnet add package Microsoft.Azure.WebPubSub.AspNetCore --version 1.0.0-beta.3
21280
```
213-
2. Remove the default `app.MapGet("/", () => "Hello World!");` in `Program.cs` and by replacing it by the following code snippet.
81+
2. Replace the default app.MapGet() in Program.cs with following code snippet.
21482

21583
``` csharp
21684
if (app.Environment.IsDevelopment())
21785
{
21886
app.UseDeveloperExceptionPage();
21987
}
22088
221-
app.UseDefaultFiles();
22289
app.UseStaticFiles();
22390
app.UseRouting();
22491
@@ -247,17 +114,7 @@ You may remember in the [publish and subscribe message tutorial](./tutorial-pub-
247114
dotnet add package Microsoft.Extensions.Azure
248115
```
249116
250-
2. Create a file `SampleChatHub.cs` for the `SampleChatHub` class to handle hub events with the following content.
251-
252-
```csharp
253-
using Microsoft.Azure.WebPubSub.AspNetCore;
254-
255-
sealed class SampleChatHub : WebPubSubHub
256-
{
257-
}
258-
```
259-
260-
3. Then update the `Program.cs` file to add DI for the service middleware and service client inside. Don't forget to replace `<connection_string>` with the one of your services.
117+
2. Add a `SampleChatHub` class to handle hub events. Add DI for the service middleware and service client. Don't forget to replace `<connection_string>` with the one of your services.
261118
262119
```csharp
263120
using Microsoft.Azure.WebPubSub.AspNetCore;
@@ -283,7 +140,11 @@ You may remember in the [publish and subscribe message tutorial](./tutorial-pub-
283140
{
284141
});
285142
286-
app.Run();
143+
app.Run();
144+
145+
sealed class SampleChatHub : WebPubSubHub
146+
{
147+
}
287148
```
288149
289150
`AddWebPubSubServiceClient<THub>()` is used to inject the service client `WebPubSubServiceClient<THub>`, with which we can use in negotiation step to generate client connection token and in hub methods to invoke service REST APIs when hub events are triggered.
@@ -324,7 +185,7 @@ You may remember in the [publish and subscribe message tutorial](./tutorial-pub-
324185
let id = prompt('Please input your user name');
325186
let res = await fetch(`/negotiate?id=${id}`);
326187
let url = await res.text();
327-
let ws = new WebSocket(url);
188+
let ws = new WebSocket(url);+
328189
ws.onopen = () => console.log('connected');
329190
})();
330191
</script>
@@ -626,40 +487,10 @@ Events are delivered to server in the form of Webhook. Webhook is served and exp
626487
Azure Web PubSub follows [CloudEvents](./reference-cloud-events.md) to describe the event data.
627488
628489
# [C#](#tab/csharp)
629-
Here we're using Web PubSub middleware SDK, there is already an implementation to parse and process CloudEvents schema, so we don't need to deal with these details. Instead, we can focus on the inner business logic in the hub methods.
630-
631-
1. Add event handlers inside `UseEndpoints`. Specify the endpoint path for the events, let's say `/eventhandler`.
632-
```csharp
633-
app.UseEndpoints(endpoints =>
634-
{
635-
endpoints.MapWebPubSubHub<SampleChatHub>("/eventhandler/{*path}");
636-
});
637-
```
638-
639-
2. Go the `SampleChatHub` we created in previous step. Add a constructor to work with `WebPubSubServiceClient<SampleChatHub>` so we can use to invoke service. And override `OnConnectedAsync()` method to respond when `connected` event is triggered.
640-
```csharp
641-
private sealed class SampleChatHub : WebPubSubHub
642-
{
643-
private readonly WebPubSubServiceClient<SampleChatHub> _serviceClient;
644490
645-
public SampleChatHub(WebPubSubServiceClient<SampleChatHub> serviceClient)
646-
{
647-
_serviceClient = serviceClient;
648-
}
649-
650-
public override async Task OnConnectedAsync(ConnectedEventRequest request)
651-
{
652-
await _serviceClient.SendToAllAsync($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
653-
}
654-
}
655-
```
656-
657-
In the above code, we use the service client to broadcast a notification message to all of whom is joined.
658-
659-
# [C# .NET 6](#tab/net6)
660491
Here we're using Web PubSub middleware SDK, there is already an implementation to parse and process CloudEvents schema, so we don't need to deal with these details. Instead, we can focus on the inner business logic in the hub methods.
661492
662-
1. Add event handlers inside `UseEndpoints`. Specify the endpoint path for the events, let's say `/eventhandler`.
493+
1. Add event handlers inside `UseEndpoints`. Specify the endpoint path for the events, let's say `/eventhandler`. The `UseEndpoints` should look like follows:
663494
```csharp
664495
app.UseEndpoints(endpoints =>
665496
{
@@ -682,9 +513,6 @@ Here we're using Web PubSub middleware SDK, there is already an implementation t
682513
2. Go the `SampleChatHub` we created in previous step. Add a constructor to work with `WebPubSubServiceClient<SampleChatHub>` so we can use to invoke service. And override `OnConnectedAsync()` method to respond when `connected` event is triggered.
683514
684515
```csharp
685-
using Microsoft.Azure.WebPubSub.AspNetCore;
686-
using Microsoft.Azure.WebPubSub.Common;
687-
688516
sealed class SampleChatHub : WebPubSubHub
689517
{
690518
private readonly WebPubSubServiceClient<SampleChatHub> _serviceClient;
@@ -802,80 +630,8 @@ Besides system events like `connected` or `disconnected`, client can also send m
802630
803631
# [C#](#tab/csharp)
804632
805-
Implement the `OnMessageReceivedAsync()` method in `SampleChatHub`.
806-
807-
1. Handle message event.
808-
809-
```csharp
810-
private sealed class SampleChatHub : WebPubSubHub
811-
{
812-
private readonly WebPubSubServiceClient<SampleChatHub> _serviceClient;
813-
814-
public SampleChatHub(WebPubSubServiceClient<SampleChatHub> serviceClient)
815-
{
816-
_serviceClient = serviceClient;
817-
}
818-
819-
public override async Task OnConnectedAsync(ConnectedEventRequest request)
820-
{
821-
await _serviceClient.SendToAllAsync($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
822-
}
823-
824-
public override async ValueTask<UserEventResponse> OnMessageReceivedAsync(UserEventRequest request, CancellationToken cancellationToken)
825-
{
826-
await _serviceClient.SendToAllAsync($"[{request.ConnectionContext.UserId}] {request.Data}");
827-
828-
return request.CreateResponse($"[SYSTEM] ack.");
829-
}
830-
}
831-
```
832-
833-
This event handler uses `WebPubSubServiceClient.SendToAllAsync()` to broadcast the received message to all clients. You can see in the end we returned `UserEventResponse`, which contains a message directly to the caller and make the WebHook request success. If you have extra logic to validate and would like to break this call, you can throw an exception here. The middleware will deliver the exception message to service and service will drop current client connection.
834-
835-
2. Update `index.html` to add the logic to send message from user to server and display received messages in the page.
836-
837-
```html
838-
<html>
839-
840-
<body>
841-
<h1>Azure Web PubSub Chat</h1>
842-
<input id="message" placeholder="Type to chat...">
843-
<div id="messages"></div>
844-
<script>
845-
(async function () {
846-
let id = prompt('Please input your user name');
847-
let res = await fetch(`/negotiate?id=${id}`);
848-
let url = await res.text();
849-
let ws = new WebSocket(url);
850-
ws.onopen = () => console.log('connected');
851-
852-
let messages = document.querySelector('#messages');
853-
ws.onmessage = event => {
854-
let m = document.createElement('p');
855-
m.innerText = event.data;
856-
messages.appendChild(m);
857-
};
858-
859-
let message = document.querySelector('#message');
860-
message.addEventListener('keypress', e => {
861-
if (e.charCode !== 13) return;
862-
ws.send(message.value);
863-
message.value = '';
864-
});
865-
})();
866-
</script>
867-
</body>
868-
869-
</html>
870-
```
871-
872-
You can see in the above code we use `WebSocket.send()` to send message and `WebSocket.onmessage` to listen to message from service.
873-
874-
Now run the server using `dotnet run --urls http://localhost:8080` and open multiple browser instances to access http://localhost:8080/index.html, then you can chat with each other.
875-
876-
The complete code sample of this tutorial can be found [here][code-csharp].
633+
Implement the OnMessageReceivedAsync() method in SampleChatHub.
877634
878-
# [C# .NET 6](#tab/net6)
879635
1. Handle message event.
880636
881637
```csharp
@@ -945,7 +701,7 @@ The complete code sample of this tutorial can be found [here][code-csharp].
945701
946702
Now run the server using `dotnet run --urls http://localhost:8080` and open multiple browser instances to access http://localhost:8080/index.html, then you can chat with each other.
947703
948-
The complete code sample of this tutorial can be found [here][code-csharp-net6].
704+
The complete code sample of this tutorial can be found [here][code-csharp-net6], the ASP.NET Core 3.1 version [here][code-csharp].
949705
950706
# [JavaScript](#tab/javascript)
951707
@@ -1180,4 +936,4 @@ Check other tutorials to further dive into how to use the service.
1180936
[code-js]: https://github.com/Azure/azure-webpubsub/tree/main/samples/javascript/chatapp/
1181937
[code-java]: https://github.com/Azure/azure-webpubsub/tree/main/samples/java/chatapp/
1182938
[code-csharp]: https://github.com/Azure/azure-webpubsub/tree/main/samples/csharp/chatapp/
1183-
[code-csharp-net6]: https://github.com/Azure/azure-webpubsub/tree/main/samples/csharp/chatapp/
939+
[code-csharp-net6]: https://github.com/Azure/azure-webpubsub/tree/main/samples/csharp/chatapp-net6/

0 commit comments

Comments
 (0)