[ASP.NET Core] Try SignalR 1
Tags: webpack, typescript, aspnetcore, signalr
Published: 2021-03-13 04:22:40

## Intro
This time, I will try ASP.NET Core SignalR.

I copied a sample project from tutorials.

* [Get started with ASP.NET Core SignalR | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-5.0&tabs=visual-studio)

### Environments
* .NET 5.0.103

#### For authentications
* Microsoft.EntityFrameworkCore ver.5.0.4
* Npgsql.EntityFrameworkCore.PostgreSQL ver.5.0.2
* Microsoft.AspNetCore.Identity.EntityFrameworkCore ver.5.0.4

#### package.json
```json
{
    "dependencies": {
        "@microsoft/signalr": "^5.0.4",
        "ts-loader": "^8.0.17",
        "tsc": "^1.20150623.0",
        "typescript": "^4.2.3",
        "webpack": "^5.24.4",
        "webpack-cli": "^4.5.0"
    }
}
```
## SignalR + Webpack + TypeScript
### Failed
Because when I don't use JavaScript frameworks or Blazor, I use Webpack and TypeScript to write client-side codes.

So I changed the sample code to fit my develop environments.
(I just changed from the JavaScript code to TypeScript)

But I got an exception.

```
Uncaught TypeError: Cannot read property 'HubConnectionBuilder' of undefined
    at init (main.page.ts:9)
    at eval (main.page.ts:34)
    at Object../ts/main.page.ts (mainPage.js:259)
    at __webpack_require__ (mainPage.js:282)
    at mainPage.js:322
    at mainPage.js:325
    at webpackUniversalModuleDefinition (mainPage.js:17)
    at mainPage.js:18
```

### Resolve
I took two mistakes.

#### webpack.config.js
The first one was about "webpack.config.js".

I wrote like below.

#### webpack.config.js
```js
var path = require('path');
module.exports = {
    mode: 'development',
    entry: {
        'mainPage': './ts/main.page.ts',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolve: {
        extensions: [ '.tsx', '.ts', '.js' ]
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'wwwroot/js'),
        library: 'Page',
        libraryTarget: 'umd'
    }
};
```

I had to add "devtool: "eval-source-map""

#### webpack.config.js
```js
var path = require('path');
module.exports = {
    mode: 'development',
    entry: {
        'mainPage': './ts/main.page.ts',
    },
    module: {
...
    },
    resolve: {
        extensions: [ '.tsx', '.ts', '.js' ]
    },
    devtool: "eval-source-map",
    output: {
...
    }
};
```

#### Import '@microsoft/signalr'
The second one was about import "@microsoft/signalr".
I wrote TS code like below.

#### main.page.ts
```ts
import signalR from '@microsoft/signalr';

function init() {
    const connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
...
}
init();
```

But I had to change like below.

#### main.page.ts
```ts
import * as signalR from '@microsoft/signalr';

function init() {
    const connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
...
}
init();
```

Now I can send or receive messages through SignalR.

* [Use ASP.NET Core SignalR with TypeScript and Webpack | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-typescript-webpack?view=aspnetcore-5.0&tabs=visual-studio)

## Authentications
Because the sample doesn't have authentications, everyone can join the chat.
How can I require signing in?

First, I added codes for ASP.NET Core Identity.

* [【.NET 5】【ASP.NET Core Identity】SignIn with custom user](https://dev.to/masanori_msl/net-5-asp-net-core-identity-signin-with-custom-user-56fe)

After that, I only needed adding "[Authorize]" attribute into "ChatHub" class.

#### ChatHub.cs
```cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;

namespace SignalrSample.Hubs
{
    [Authorize]
    public class ChatHub : Hub
    {
...
    }
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4fp544yr44bjzywuruv.png)

* [Authentication and authorization in ASP.NET Core SignalR | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-5.0)

## Distinguish between clients
The sample sends messages to all clients.

#### ChatHub.cs
```cs
...
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
...
```

If I don't want to send to myself, what shall I do?

SignalR can distinguish clients.
So I just need changing like below.

#### ChatHub.cs
```cs
...
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.Others.SendAsync("ReceiveMessage", user, message);
        }
    }
...
```

## Resources
* [Introduction to ASP.NET Core SignalR | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-5.0)
* [Get started with ASP.NET Core SignalR | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-5.0&tabs=visual-studio)
* [Use ASP.NET Core SignalR with TypeScript and Webpack | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-typescript-webpack?view=aspnetcore-5.0&tabs=visual-studio-code)