Uploading and sending image messages with ASP.NET Core SignalR

This article shows how images could be uploaded using a file upload with a HTML form in an ASP.MVC Core view, and then sent to application clients using SignalR. The images are uploaded as an ICollection of IFormFile objects, and sent to the SignalR clients using a base64 string. Angular is used to implement the SignalR clients.

Code https://github.com/damienbod/AspNetCoreAngularSignalR


2021-01-25 Updated Angular 11.1.0 .NET 5, ngrx implementation
2019-07-30 Updated Angular 8.1.3, ASP.NET Core 3.0 Preview 7
2019-02-06 Updated Angular 7.2.4, latest NGRX, SignalR CORS fix
2018-12-12 Updated .NET Core 2.2, ASP.NET Core SignalR 1.1.0, Angular 7.1.3

Posts in this series

SignalR Server

The SignalR Hub is really simple. This implements a single method which takes an ImageMessage type object as a parameter.

using System.Threading.Tasks;
using AspNetCoreAngularSignalR.Model;
using Microsoft.AspNetCore.SignalR;

namespace AspNetCoreAngularSignalR.SignalRHubs
    public class ImagesMessageHub : Hub
        public Task ImageMessage(ImageMessage file)
            return Clients.All.SendAsync("ImageMessage", file);

The ImageMessage class has two properties, one for the image byte array, and a second for the image information, which is required so that the client application can display the image.

public class ImageMessage
	public byte[] ImageBinary { get; set; }
	public string ImageHeaders { get; set; }

In this example, SignalR is added to the ASP.NET Core application in the Startup class, but this could also be done directly in the kestrel server. The AddSignalR middleware is added and then each Hub explicitly with a defined URL in the Configure method.

public void ConfigureServices(IServiceCollection services)
    // ...

	var sqlConnectionString = Configuration.GetConnectionString("DefaultConnection");

	services.AddDbContext<NewsContext>(options =>
		), ServiceLifetime.Singleton




public void Configure(IApplicationBuilder app)




	app.UseEndpoints(endpoints =>

			name: "default",
			pattern: "{controller=Home}/{action=Index}/{id?}");

A File Upload ASP.NET Core MVC controller is implemented to support the file upload. The SignalR IHubContext interface is added per dependency injection for the type ImagesMessageHub. When files are uploaded, the IFormFile collection which contain the images are read to memory and sent as a byte array to the SignalR clients. Maybe this could be optimized.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using AspNetCoreAngularSignalR.Model;
using AspNetCoreAngularSignalR.SignalRHubs;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Net.Http.Headers;

namespace AspNetCoreAngularSignalR.Controllers
    public class FileUploadController : Controller
        private readonly IHubContext<ImagesMessageHub> _hubContext;

        public FileUploadController(IHubContext<ImagesMessageHub> hubContext)
            _hubContext = hubContext;

        public async Task<IActionResult> UploadFiles(FileDescriptionShort fileDescriptionShort)
            if (ModelState.IsValid)
                foreach (var file in fileDescriptionShort.File)
                    if (file.Length > 0)
                        using (var memoryStream = new MemoryStream())
                            await file.CopyToAsync(memoryStream);

                            var imageMessage = new ImageMessage
                                ImageHeaders = "data:" + file.ContentType + ";base64,",
                                ImageBinary = memoryStream.ToArray()

                            await _hubContext.Clients.All.SendAsync("ImageMessage", imageMessage);

            return Redirect("/FileClient/Index");

SignalR Angular Client

The Angular SignalR client uses the HubConnection to receive ImageMessage messages. Each message is pushed to the client array which is used to display the images. The @aspnet/signalr npm package is required to use the HubConnection.

import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@microsoft/signalr';
import * as signalR from '@microsoft/signalr';

import { ImageMessage } from '../imagemessage';

    selector: 'app-images-component',
    templateUrl: './images.component.html'

export class ImagesComponent implements OnInit {
    private _hubConnection: HubConnection | undefined;
    public async: any;
    message = '';
    messages: string[] = [];

    images: ImageMessage[] = [];

    constructor() {

    ngOnInit() {
        this._hubConnection = new signalR.HubConnectionBuilder()


        this._hubConnection.start().catch(err => {

        this._hubConnection.on('ImageMessage', (data: any) => {

The Angular template displays the images using the header and the binary data properties.

<div class="container-fluid">


   <a href="https://localhost:44324/FileClient/Index" target="_blank">Upload Images</a> 

    <div class="row" *ngIf="images.length > 0">
        <img *ngFor="let image of images;" 
        width="150" style="margin-right:5px" 
        [src]="image.imageHeaders + image.imageBinary">

File Upload

The images are uploaded using an ASP.NET Core MVC View which uses a multiple file input HTML control. This sends the files to the MVC Controller as a multipart/form-data request.

<form enctype="multipart/form-data" method="post" action="https://localhost:44324/api/FileUpload/files" id="ajaxUploadForm" novalidate="novalidate">

        <legend style="padding-top: 10px; padding-bottom: 10px;">Upload Images</legend>

        <div class="col-xs-12" style="padding: 10px;">
            <div class="col-xs-4">
            <div class="col-xs-7">
                <input type="file" id="fileInput" name="file" multiple>

        <div class="col-xs-12" style="padding: 10px;">
            <div class="col-xs-4">
                <input type="submit" value="Upload" id="ajaxUploadButton" class="btn">
            <div class="col-xs-7">




When the application is run, n instances of the clients can be opened. Then one can be used to upload images to all the other SignalR clients.

This soultion works good, but has many ways, areas which could be optimized for performance.










  1. […] Uploading and sending image messages with ASP.NET Core SignalR – Damien Bowden […]

  2. […] Uploading and sending image messages with ASP.NET Core SignalR (Damien Bowden) […]

  3. Kalpesh Chheda · · Reply

    Is it ok to send large images from Signalr?

    1. No, this has limits, but I did not try them. Also SignalR has open issues concerning large messages

      Where the limits are, I don’t know.
      Greetings Damien

    2. radcki · · Reply

      This is not ok as concept itself. For messages over few kilobytes I would generally use Signlr as way of saying “hey there is new thing you might like and this is where to get it” than “hey take this thing from me”.
      So you would transfer metadata only with signalr and make normal call to get actual byte array from server or (for example) create link to content – depending of user settings

      Think of smarphone notifications – you would not like to receive few megabates of data out of nowhere – you want to be notified and then decide if you want to fetch it or not.

  4. […] Uploading and sending image messages with ASP.NET Core SignalR […]

  5. […] Téléverser et envoyer des images avec ASP.NET Core SignalR. […]

  6. Why do you need the AddData function on ImageMessage class?

Leave a Reply to Kalpesh Chheda Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: