ASP.NET Core API: Returning Video File as stream and playing video stream in Angular Client Application
In this article, we explore an implementation that involves serving a video file from an ASP.NET Core API as a stream and playing it within an Angular client application. Our goal is to demonstrate how to create a stream response from the API and seamlessly deliver it to the client. During the development of server-side APIs, we often encounter scenarios where users need to download files in client applications. However, when dealing with large files, it’s more efficient to use streamed responses. For instance, if the file is a video, rather than downloading it to the client, we can directly play it in the video player within the client application.
In ASP.NET Core, the FileStreamResult
object is utilized to write stream data to the response. This approach allows sending binary content using a Stream
instance when returning a file as a FileStream.
Figure 1 illustrates the high-level implementation concept.
Figure 1: ASP.NET Core API returning Stream to Angular Client
Step 1: Create an ASP.NET Core API Project in Visual Studio 2022
- Open Visual Studio 2022.
- Create a new ASP.NET Core API project targeted to .NET 8.
- Name this project “StreamerAPI.”
- Within the project, add a new folder named “VideoServer.”
- Add a couple of video files to this folder. Ensure that the video file extensions are ‘.mp4’.
Step 2: Create a StreamController in the Controllers Folder
- In the Controllers folder of your ASP.NET Core API project, add a new Empty API Controller named ‘StreamController’.
- Within this controller, we’ll define two action methods:
- GetFiles(): This method will return a list of all available videos in the ‘VideoServer’ folder.
- Get(): The Get() method will accept a file name from the client. Based on the received file name, it will read the corresponding video file from the ‘VideoServer’ folder and stream it as a response using the
FileStreamResult
object.
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace StreamerAPI.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class StreamController : ControllerBase { private readonly string _videoFolderPath = "VideoServer"; // Path to the video folder [HttpGet] [ActionName("files")] public IActionResult GetFiles() { // Logic to retrieve a list of video files in the folder var videoFiles = Directory.GetFiles(_videoFolderPath, "*.mp4"); var fileNames = new List<string>(); foreach (var file in videoFiles) { fileNames.Add(Path.GetFileName(file)); } return Ok(fileNames); } [HttpGet] [ActionName("video")] public IActionResult Get(string fileName) { var filePath = Path.Combine(_videoFolderPath, fileName); if (System.IO.File.Exists(filePath)) { // Stream the video file as a response var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); return new FileStreamResult(stream, "video/mp4"); } else { return NotFound($"Video file '{fileName}' not found."); } } } }
Step 3: Create an Angular Application
- Open the command prompt.
- Create a new Angular application by running the following command:
ng new ng-video-app
Step 4: Create an Angular Service for Video Handling
- In your Angular application, create a new Angular service named
VideoService
.- Within this service, write code to call the
StreamController
in your ASP.NET Core API and retrieve a list of video file names.- You can use this service to manage video-related functionality within your Angular app.
The code in Listing 2 shows an implementation of the VideoService.
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class VideoService { private url:string; constructor(private http:HttpClient) { this.url = "https://localhost:7212/api/Stream"; } getFiles():Observable<string[]> { let result:Observable<string[]>; result = this.http.get<string[]>(`${this.url}/files`); return result; } }
Listing 2: The VideoService
Step 5: Enhance AppComponent to Stream Video Files
- In your
app.component.ts
file, modify theAppComponent
class to include the following features:- Access the
getFiles()
method from theVideoService
. - Invoke the
getFiles()
method in thengOnInit()
lifecycle hook. - Declare a
videoPlayer
element reference using@ViewChild
. This reference will be used to interact with the HTML5 video element for playing videos. - Implement the
OnSelectedVideo()
method, which accepts the selected file as an input parameter. - Inside the
OnSelectedVideo()
method, create an HTTP URL to access theget()
method of the API for requesting the video stream. - Assign this URL to the
src
property of the video element. - Once done, the stream received from the API will be played in the video player within the browser.
- Access the
The code of the AppComponent is shown in Listing 3
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { VideoService } from './video.service'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent implements OnInit { @ViewChild("videoPlayer", { static: false }) videoPlayer!: ElementRef; files:string[]; message:string; fileName:string; constructor(private serv:VideoService){ this.files = []; this.message = ''; this.fileName = ''; } ngOnInit(): void { this.serv.getFiles() .subscribe({ next:(resp)=>{ this.files = resp }, error:(err)=>{ this.message = `Error Occurred : ${err}` } }); } onSelectedVideo(file:string):void { this.fileName = `https://localhost:7212/api/Stream/video?fileName=${file}`; this.videoPlayer.nativeElement.src = this.fileName; this.videoPlayer.nativeElement.play(); } }
Listing 3: The AppComponent
Step 6: Update the
app.component.html
FileReplace the existing code in your
app.component.html
file with the HTML snippet provided in Listing 4.
<h1>Video Library</h1> <div class="container"> <table class="table table-bordered"> <tbody> <tr> <td> <div> <ul> @for(file of files; track $index) { <li (click)="onSelectedVideo(file)">{{file}}</li> } </ul> </div> </td> <td> <video autoplay style="height: 300px;width: 400px;" controls #videoPlayer> <source type="video/mp4" /> </video> </td> </tr> </tbody> </table> </div>
Listing 4: The AppComponent's User Interface
Step 7: Configure HttpClient in Angular
If you’re using Angular 17 and need to configure the
HttpClient
for making HTTP calls, follow the instructions below:
- Locate the
app.config.ts
file in your Angular project.- Modify the code to use the
provideHttpClient
as demonstrated in Listing 5.- This configuration ensures that your Angular application can effectively use the
HttpClient
module for handling HTTP requests.
export const appConfig: ApplicationConfig = { providers: [provideRouter(routes), provideHttpClient() ] };
Listing: Registration for HttpClient
Once you run the API and Angular application, navigate to the URL http://localhost:4200 in your browser. The browser will display a list of video files retrieved from the API. When you select any video file, it will be played in the video player, as demonstrated in Figure 2.
Figure 2: The Result
Conclusion: The ASP.NET Core FileStreamResult is the best way to download the streamed response.