Skip to content

Commit 34dff26

Browse files
authored
Merge pull request #975 from TechnologyEnhancedLearning/Develop/Fixes/TD-5348-dev
Infastructure test for TD-5348
2 parents 51477d4 + 8daf583 commit 34dff26

File tree

2 files changed

+66
-11
lines changed

2 files changed

+66
-11
lines changed

LearningHub.Nhs.WebUI/Controllers/Api/ResourceController.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ namespace LearningHub.Nhs.WebUI.Controllers.Api
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Net.Http.Headers;
8+
using System.Threading;
59
using System.Threading.Tasks;
610
using LearningHub.Nhs.Models.Enums;
711
using LearningHub.Nhs.Models.Resource;
812
using LearningHub.Nhs.Models.Resource.Activity;
913
using LearningHub.Nhs.Models.Resource.Contribute;
1014
using LearningHub.Nhs.WebUI.Interfaces;
1115
using Microsoft.AspNetCore.Authorization;
16+
using Microsoft.AspNetCore.Http;
1217
using Microsoft.AspNetCore.Mvc;
1318
using Microsoft.Extensions.Configuration;
1419

@@ -60,6 +65,7 @@ public async Task<ActionResult> AcceptSensitiveContentAsync(int resourceVersionI
6065
/// <param name="fileName">File name.</param>
6166
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
6267
[HttpGet("DownloadResource")]
68+
[AllowAnonymous]
6369
public async Task<IActionResult> DownloadResource(string filePath, string fileName)
6470
{
6571
if (string.IsNullOrEmpty(fileName))
@@ -70,7 +76,15 @@ public async Task<IActionResult> DownloadResource(string filePath, string fileNa
7076
var file = await this.fileService.DownloadFileAsync(filePath, fileName);
7177
if (file != null)
7278
{
73-
return this.File(file.Content, file.ContentType, fileName);
79+
// Set response headers.
80+
this.Response.ContentType = file.ContentType;
81+
this.Response.ContentLength = file.ContentLength;
82+
var contentDisposition = new ContentDispositionHeaderValue("attachment") { FileNameStar = fileName };
83+
this.Response.Headers["Content-Disposition"] = contentDisposition.ToString();
84+
85+
// Stream the file in chunks with periodic flushes to keep the connection active.
86+
await this.StreamFileWithKeepAliveAsync(file.Content, this.Response.Body, this.HttpContext.RequestAborted);
87+
return this.Ok();
7488
}
7589
else
7690
{
@@ -105,7 +119,16 @@ public async Task<IActionResult> DownloadResourceAndRecordActivity(int resourceV
105119
ActivityStatus = ActivityStatusEnum.Completed,
106120
};
107121
await this.activityService.CreateResourceActivityAsync(activity);
108-
return this.File(file.Content, file.ContentType, fileName);
122+
123+
// Set response headers.
124+
this.Response.ContentType = file.ContentType;
125+
this.Response.ContentLength = file.ContentLength;
126+
var contentDisposition = new ContentDispositionHeaderValue("attachment") { FileNameStar = fileName };
127+
this.Response.Headers["Content-Disposition"] = contentDisposition.ToString();
128+
129+
// Stream the file in chunks with periodic flushes to keep the connection active.
130+
await this.StreamFileWithKeepAliveAsync(file.Content, this.Response.Body, this.HttpContext.RequestAborted);
131+
return this.Ok();
109132
}
110133
else
111134
{
@@ -584,5 +607,20 @@ public async Task<List<string>> GetObsoleteResourceFile(int resourceVersionId, b
584607
var result = await this.resourceService.GetObsoleteResourceFile(resourceVersionId, deletedResource);
585608
return result;
586609
}
610+
611+
/// <summary>
612+
/// Reads from the source stream in chunks and writes to the destination stream,
613+
/// flushing after each chunk to help keep the connection active.
614+
/// </summary>
615+
private async Task StreamFileWithKeepAliveAsync(Stream source, Stream destination, CancellationToken cancellationToken)
616+
{
617+
byte[] buffer = new byte[8192];
618+
int bytesRead;
619+
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
620+
{
621+
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
622+
await destination.FlushAsync(cancellationToken);
623+
}
624+
}
587625
}
588626
}

LearningHub.Nhs.WebUI/Services/FileService.cs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,37 @@ public async Task<ShareFileDownloadInfo> DownloadFileAsync(string filePath, stri
135135
{
136136
var file = directory.GetFileClient(fileName);
137137

138-
if (await file.ExistsAsync())
138+
var properties = await file.GetPropertiesAsync();
139+
long fileSize = properties.Value.ContentLength;
140+
141+
try
142+
{
143+
if (fileSize <= 900 * 1024 * 1024)
139144
{
140-
return await file.DownloadAsync();
145+
// For smaller files, download the entire file as a stream.
146+
var response = await file.DownloadAsync();
147+
return new FileDownloadResponse
148+
{
149+
Content = response.Value.Content,
150+
ContentType = properties.Value.ContentType,
151+
ContentLength = fileSize,
152+
};
141153
}
142-
}
143-
else if (await sourceDirectory.ExistsAsync())
144-
{
145-
var file = sourceDirectory.GetFileClient(fileName);
146-
147-
if (await file.ExistsAsync())
154+
else
148155
{
149-
return await file.DownloadAsync();
156+
// For large files, open a read stream
157+
return new FileDownloadResponse
158+
{
159+
Content = await file.OpenReadAsync(),
160+
ContentType = properties.Value.ContentType,
161+
ContentLength = fileSize,
162+
};
150163
}
151164
}
165+
catch (Exception ex)
166+
{
167+
throw new Exception($"Error downloading file: {ex.Message}");
168+
}
152169

153170
return null;
154171
}

0 commit comments

Comments
 (0)