Skip to content

Commit 0ff8c82

Browse files
authored
File deletion (#227)
* Re-factor. GetFile query was excessively complex so split up part into separate query. Also updated FileEntity to use Actor entity consistenly. * Added application code for deleting file * Added Hangfire support * Added deletion after everyone has confirmed download * Added code to add service owner to database * Added corresponding field to File * Add logic to trigger Hangfire jobs for deleting file on all confirmed downloaded and file initialized * Removed unused return value * Formatting * Consolidated naming * Formatting * Fix test data * Known issue in Serilog: serilog/serilog-aspnetcore#289 and we get around it by not using BootstrapLogger. We do not need it anyway * Try with joining the repeatable migration sripts together. Seems one fails to run if it is dependent on the other one when in a brand new environment. Should find better way to split up in more test scripts if we get big script. * Hangfire in memory during tests to avoid issues with concurrent initialization
1 parent 99f5b5b commit 0ff8c82

35 files changed

+260
-146
lines changed

Test/Altinn.Broker.Tests/Altinn.Broker.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<ItemGroup>
1313
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
15+
<PackageReference Include="Moq" Version="4.20.70" />
1516
<PackageReference Include="xunit" Version="2.6.2" />
1617
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
1718
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

Test/Altinn.Broker.Tests/Data/R__Prepare_File.sql

Lines changed: 0 additions & 4 deletions
This file was deleted.

Test/Altinn.Broker.Tests/Data/R__Prepare_ServiceOwner.sql

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
INSERT INTO broker.service_owner (service_owner_id_pk, service_owner_name, file_time_to_live)
2+
VALUES ('0192:991825827', 'Digitaliseringsdirektoratet Avd Oslo', '1 Days');
3+
4+
INSERT INTO broker.storage_provider (storage_provider_id_pk, service_owner_id_fk, created, storage_provider_type, resource_name)
5+
VALUES (DEFAULT, '0192:991825827', NOW(), 'Altinn3Azure', 'dummy-value');
6+
7+
INSERT INTO broker.file (file_id_pk, service_owner_id_fk, filename, checksum, sender_actor_id_fk, external_file_reference, created, storage_provider_id_fk, file_location, expiration_time)
8+
VALUES ('ed76ce89-3768-481a-bca1-4e4262d9098b', '0192:991825827', 'filename.txt', NULL, 1, 'external_reference', NOW(), 1, 'https://blob-storage-example', NOW() + INTERVAL '1 DAY')

Test/Altinn.Broker.Tests/FileControllerTests.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
using Altinn.Broker.Tests.Factories;
1010
using Altinn.Broker.Tests.Helpers;
1111

12-
using Microsoft.AspNetCore.Mvc.Testing;
12+
using Hangfire.Common;
13+
using Hangfire.States;
14+
15+
using Moq;
1316

1417
using Xunit;
1518

1619
namespace Altinn.Broker.Tests;
1720
public class FileControllerTests : IClassFixture<CustomWebApplicationFactory>
1821
{
19-
private readonly WebApplicationFactory<Program> _factory;
22+
private readonly CustomWebApplicationFactory _factory;
2023
private readonly HttpClient _senderClient;
2124
private readonly HttpClient _recipientClient;
2225
private readonly JsonSerializerOptions _responseSerializerOptions;
@@ -77,6 +80,11 @@ public async Task NormalFlow_WhenAllIsOK_Success()
7780
Assert.NotNull(confirmedFileDetails);
7881
Assert.True(confirmedFileDetails.FileStatus == FileStatusExt.AllConfirmedDownloaded);
7982
Assert.Contains(confirmedFileDetails.RecipientFileStatusHistory, recipient => recipient.RecipientFileStatusCode == RecipientFileStatusExt.DownloadConfirmed);
83+
84+
// Confirm that it has been enqueued for deletion
85+
_factory.HangfireBackgroundJobClient?.Verify(jobClient => jobClient.Create(
86+
It.Is<Job>(job => (job.Method.DeclaringType != null) && job.Method.DeclaringType.Name == "DeleteFileCommandHandler" && ((Guid)job.Args[0] == Guid.Parse(fileId))),
87+
It.IsAny<EnqueuedState>()));
8088
}
8189

8290
[Fact]

Test/Altinn.Broker.Tests/Helpers/CustomWebApplicationFactory.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using Hangfire;
2+
using Hangfire.MemoryStorage;
3+
14
using Microsoft.AspNetCore.Authentication;
25
using Microsoft.AspNetCore.Authentication.JwtBearer;
36
using Microsoft.AspNetCore.Hosting;
@@ -7,8 +10,11 @@
710
using Microsoft.IdentityModel.JsonWebTokens;
811
using Microsoft.IdentityModel.Tokens;
912

13+
using Moq;
14+
1015
public class CustomWebApplicationFactory : WebApplicationFactory<Program>
1116
{
17+
internal Mock<IBackgroundJobClient>? HangfireBackgroundJobClient;
1218
protected override void ConfigureWebHost(
1319
IWebHostBuilder builder)
1420
{
@@ -39,6 +45,11 @@ protected override void ConfigureWebHost(
3945
}
4046
};
4147
});
48+
services.AddHangfire(config =>
49+
config.UseMemoryStorage()
50+
);
51+
HangfireBackgroundJobClient = new Mock<IBackgroundJobClient>();
52+
services.AddSingleton(HangfireBackgroundJobClient.Object);
4253
});
4354
}
4455
}

src/Altinn.Broker.Application/Altinn.Broker.Application.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
</ItemGroup>
1515

1616
<ItemGroup>
17+
<PackageReference Include="Hangfire.Core" Version="1.8.6" />
1718
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
1819
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
1920
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />

src/Altinn.Broker.Application/ConfirmDownloadCommand/ConfirmDownloadCommandHandler.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
using Altinn.Broker.Application;
22
using Altinn.Broker.Application.ConfirmDownloadCommand;
3+
using Altinn.Broker.Application.DeleteFileCommand;
34
using Altinn.Broker.Core.Application;
45
using Altinn.Broker.Core.Domain.Enums;
56
using Altinn.Broker.Core.Repositories;
67

8+
using Hangfire;
9+
710
using Microsoft.Extensions.Logging;
811

912
using OneOf;
@@ -14,14 +17,16 @@ public class ConfirmDownloadCommandHandler : IHandler<ConfirmDownloadCommandRequ
1417
private readonly IFileRepository _fileRepository;
1518
private readonly IFileStatusRepository _fileStatusRepository;
1619
private readonly IActorFileStatusRepository _actorFileStatusRepository;
20+
private readonly IBackgroundJobClient _backgroundJobClient;
1721
private readonly ILogger<ConfirmDownloadCommandHandler> _logger;
1822

19-
public ConfirmDownloadCommandHandler(IServiceOwnerRepository serviceOwnerRepository, IFileRepository fileRepository, IFileStatusRepository fileStatusRepository, IActorFileStatusRepository actorFileStatusRepository, ILogger<ConfirmDownloadCommandHandler> logger)
23+
public ConfirmDownloadCommandHandler(IServiceOwnerRepository serviceOwnerRepository, IFileRepository fileRepository, IFileStatusRepository fileStatusRepository, IActorFileStatusRepository actorFileStatusRepository, IBackgroundJobClient backgroundJobClient, ILogger<ConfirmDownloadCommandHandler> logger)
2024
{
2125
_serviceOwnerRepository = serviceOwnerRepository;
2226
_fileRepository = fileRepository;
2327
_fileStatusRepository = fileStatusRepository;
2428
_actorFileStatusRepository = actorFileStatusRepository;
29+
_backgroundJobClient = backgroundJobClient;
2530
_logger = logger;
2631
}
2732
public async Task<OneOf<ConfirmDownloadCommandResponse, Error>> Process(ConfirmDownloadCommandRequest request)
@@ -36,7 +41,7 @@ public async Task<OneOf<ConfirmDownloadCommandResponse, Error>> Process(ConfirmD
3641
{
3742
return Errors.FileNotFound;
3843
}
39-
if (!file.ActorEvents.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
44+
if (!file.RecipientCurrentStatuses.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
4045
{
4146
return Errors.FileNotFound;
4247
}
@@ -46,13 +51,12 @@ public async Task<OneOf<ConfirmDownloadCommandResponse, Error>> Process(ConfirmD
4651
}
4752

4853
await _actorFileStatusRepository.InsertActorFileStatus(request.FileId, ActorFileStatus.DownloadConfirmed, request.Consumer);
49-
var recipientStatuses = file.ActorEvents
50-
.Where(actorEvent => actorEvent.Actor.ActorExternalId != file.Sender && actorEvent.Actor.ActorExternalId != request.Consumer)
51-
.GroupBy(actorEvent => actorEvent.Actor.ActorExternalId)
52-
.Select(group => group.Max(statusEvent => statusEvent.Status))
53-
.ToList();
54-
bool shouldConfirmAll = recipientStatuses.All(status => status >= ActorFileStatus.DownloadConfirmed);
55-
await _fileStatusRepository.InsertFileStatus(request.FileId, FileStatus.AllConfirmedDownloaded);
54+
bool shouldConfirmAll = file.RecipientCurrentStatuses.Where(recipientStatus => recipientStatus.Actor.ActorExternalId != request.Consumer).All(status => status.Status >= ActorFileStatus.DownloadConfirmed);
55+
if (shouldConfirmAll)
56+
{
57+
await _fileStatusRepository.InsertFileStatus(request.FileId, FileStatus.AllConfirmedDownloaded);
58+
_backgroundJobClient.Enqueue<DeleteFileCommandHandler>((deleteFileCommandHandler) => deleteFileCommandHandler.Process(request.FileId));
59+
}
5660

5761
return new ConfirmDownloadCommandResponse();
5862
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Altinn.Broker.Core.Application;
2+
using Altinn.Broker.Core.Repositories;
3+
4+
using Microsoft.Extensions.Logging;
5+
6+
using OneOf;
7+
8+
namespace Altinn.Broker.Application.DeleteFileCommand;
9+
public class DeleteFileCommandHandler : IHandler<Guid, Task>
10+
{
11+
private readonly IFileRepository _fileRepository;
12+
private readonly IFileStatusRepository _fileStatusRepository;
13+
private readonly IServiceOwnerRepository _serviceOwnerRepository;
14+
private readonly IBrokerStorageService _brokerStorageService;
15+
private readonly ILogger<DeleteFileCommandHandler> _logger;
16+
17+
public DeleteFileCommandHandler(IFileRepository fileRepository, IFileStatusRepository fileStatusRepository, IServiceOwnerRepository serviceOwnerRepository, IBrokerStorageService brokerStorageService, ILogger<DeleteFileCommandHandler> logger)
18+
{
19+
_fileRepository = fileRepository;
20+
_fileStatusRepository = fileStatusRepository;
21+
_serviceOwnerRepository = serviceOwnerRepository;
22+
_brokerStorageService = brokerStorageService;
23+
_logger = logger;
24+
}
25+
26+
public async Task<OneOf<Task, Error>> Process(Guid fileId)
27+
{
28+
_logger.LogInformation("Deleting file with id {fileId}", fileId.ToString());
29+
var file = await _fileRepository.GetFile(fileId);
30+
if (file is null)
31+
{
32+
return Errors.FileNotFound;
33+
}
34+
var serviceOwner = await _serviceOwnerRepository.GetServiceOwner(file.ServiceOwnerId);
35+
if (serviceOwner is null)
36+
{
37+
return Errors.ServiceOwnerNotConfigured;
38+
}
39+
if (file.FileStatus >= Core.Domain.Enums.FileStatus.Deleted)
40+
{
41+
_logger.LogInformation("File has already been set to deleted");
42+
}
43+
44+
await _fileStatusRepository.InsertFileStatus(fileId, Core.Domain.Enums.FileStatus.Deleted);
45+
await _brokerStorageService.DeleteFile(serviceOwner, file);
46+
var recipientsWhoHaveNotDownloaded = file.RecipientCurrentStatuses.Where(latestStatus => latestStatus.Status <= Core.Domain.Enums.ActorFileStatus.DownloadConfirmed).ToList();
47+
foreach (var recipient in recipientsWhoHaveNotDownloaded)
48+
{
49+
_logger.LogError("Recipient {recipientExternalReference} did not download the file with id {fileId}", recipient.Actor.ActorExternalId, recipient.FileId.ToString());
50+
// TODO, send events
51+
}
52+
return Task.CompletedTask;
53+
}
54+
}

src/Altinn.Broker.Application/DownloadFileQuery/DownloadFileQueryHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public async Task<OneOf<DownloadFileQueryResponse, Error>> Process(DownloadFileQ
3636
{
3737
return Errors.FileNotFound;
3838
}
39-
if (!file.ActorEvents.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
39+
if (!file.RecipientCurrentStatuses.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
4040
{
4141
return Errors.FileNotFound;
4242
}

src/Altinn.Broker.Application/GetFileDetailsQuery/GetFileDetailsQueryHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public async Task<OneOf<GetFileDetailsQueryResponse, Error>> Process(GetFileDeta
3232
{
3333
return Errors.FileNotFound;
3434
}
35-
if (!file.ActorEvents.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
35+
if (file.Sender.ActorExternalId != request.Consumer &&
36+
!file.RecipientCurrentStatuses.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
3637
{
3738
return Errors.FileNotFound;
3839
}

src/Altinn.Broker.Application/GetFileOverviewQuery/GetFileOverviewQueryHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public async Task<OneOf<GetFileOverviewQueryResponse, Error>> Process(GetFileOve
3333
{
3434
return Errors.FileNotFound;
3535
}
36-
if (!file.ActorEvents.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
36+
if (file.Sender.ActorExternalId != request.Consumer &&
37+
!file.RecipientCurrentStatuses.Any(actorEvent => actorEvent.Actor.ActorExternalId == request.Consumer))
3738
{
3839
return Errors.FileNotFound;
3940
}

src/Altinn.Broker.Application/InitializeFileCommand/InitializeFileCommandHandler.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
using Altinn.Broker.Core.Application;
1+
using Altinn.Broker.Application.DeleteFileCommand;
2+
using Altinn.Broker.Core.Application;
23
using Altinn.Broker.Core.Domain.Enums;
34
using Altinn.Broker.Core.Repositories;
45
using Altinn.Broker.Core.Services;
56

7+
using Hangfire;
8+
69
using Microsoft.Extensions.Logging;
710

811
using OneOf;
@@ -15,15 +18,24 @@ public class InitializeFileCommandHandler : IHandler<InitializeFileCommandReques
1518
private readonly IFileStatusRepository _fileStatusRepository;
1619
private readonly IActorFileStatusRepository _actorFileStatusRepository;
1720
private readonly IResourceManager _resourceManager;
21+
private readonly IBackgroundJobClient _backgroundJobClient;
1822
private readonly ILogger<InitializeFileCommandHandler> _logger;
1923

20-
public InitializeFileCommandHandler(IServiceOwnerRepository serviceOwnerRepository, IFileRepository fileRepository, IFileStatusRepository fileStatusRepository, IActorFileStatusRepository actorFileStatusRepository, IResourceManager resourceManager, ILogger<InitializeFileCommandHandler> logger)
24+
public InitializeFileCommandHandler(
25+
IServiceOwnerRepository serviceOwnerRepository,
26+
IFileRepository fileRepository,
27+
IFileStatusRepository fileStatusRepository,
28+
IActorFileStatusRepository actorFileStatusRepository,
29+
IResourceManager resourceManager,
30+
IBackgroundJobClient backgroundJobClient,
31+
ILogger<InitializeFileCommandHandler> logger)
2132
{
2233
_serviceOwnerRepository = serviceOwnerRepository;
2334
_fileRepository = fileRepository;
2435
_fileStatusRepository = fileStatusRepository;
2536
_actorFileStatusRepository = actorFileStatusRepository;
2637
_resourceManager = resourceManager;
38+
_backgroundJobClient = backgroundJobClient;
2739
_logger = logger;
2840
}
2941

@@ -45,7 +57,7 @@ public async Task<OneOf<Guid, Error>> Process(InitializeFileCommandRequest reque
4557
}
4658
var fileId = await _fileRepository.AddFile(serviceOwner, request.Filename, request.SendersFileReference, request.SenderExternalId, request.RecipientExternalIds, request.PropertyList, request.Checksum);
4759
await _fileStatusRepository.InsertFileStatus(fileId, FileStatus.Initialized);
48-
var addRecipientEventTasks = request.RecipientExternalIds.Concat([request.SenderExternalId]).Select(recipientId => _actorFileStatusRepository.InsertActorFileStatus(fileId, ActorFileStatus.Initialized, recipientId));
60+
var addRecipientEventTasks = request.RecipientExternalIds.Select(recipientId => _actorFileStatusRepository.InsertActorFileStatus(fileId, ActorFileStatus.Initialized, recipientId));
4961
try
5062
{
5163
await Task.WhenAll(addRecipientEventTasks);
@@ -54,6 +66,8 @@ public async Task<OneOf<Guid, Error>> Process(InitializeFileCommandRequest reque
5466
{
5567
_logger.LogError("Failed when adding recipient initialized events.");
5668
}
69+
_backgroundJobClient.Schedule<DeleteFileCommandHandler>((deleteFileCommandHandler) => deleteFileCommandHandler.Process(fileId), serviceOwner.FileTimeToLive);
70+
5771
return fileId;
5872
}
5973
}

src/Altinn.Broker.Application/UploadFileCommand/UploadFileCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task<OneOf<Guid, Error>> Process(UploadFileCommandRequest request)
4545
{
4646
return Errors.FileNotFound;
4747
}
48-
if (request.Consumer != file.Sender)
48+
if (request.Consumer != file.Sender.ActorExternalId)
4949
{
5050
return Errors.FileNotFound;
5151
}

src/Altinn.Broker.Core/Domain/FileEntity.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ public class FileEntity
66
{
77
public Guid FileId { get; set; }
88
public string ServiceOwnerId { get; set; }
9-
public string Sender { get; set; } // Joined in
9+
public ActorEntity Sender { get; set; } // Joined in
1010
public string SendersFileReference { get; set; }
1111
public FileStatus FileStatus { get; set; }
1212
public DateTimeOffset FileStatusChanged { get; set; }
13-
public DateTimeOffset Uploaded { get; set; }
14-
public List<ActorFileStatusEntity> ActorEvents { get; set; } // Joined in
13+
public DateTimeOffset Created { get; set; }
14+
public DateTimeOffset ExpirationTime { get; set; }
15+
public List<ActorFileStatusEntity> RecipientCurrentStatuses { get; set; } // Joined in
1516
public StorageProviderEntity StorageProvider { get; set; }
1617
public string? FileLocation { get; set; }
1718
public string Filename { get; set; }

src/Altinn.Broker.Core/Domain/ServiceOwnerEntity.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ public class ServiceOwnerEntity
55
public string Id { get; set; }
66
public string Name { get; set; }
77
public StorageProviderEntity? StorageProvider { get; set; }
8+
public TimeSpan FileTimeToLive { get; set; }
89
}

src/Altinn.Broker.Core/Repositories/IFileStore.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public interface IFileStore
44
{
55
Task<Stream> GetFileStream(Guid fileId, string connectionString);
66
Task UploadFile(Stream filestream, Guid fileId, string connectionString);
7+
Task DeleteFile(Guid fileId, string connectionString);
78
Task<bool> IsOnline(string connectionString);
89
}
910
}

src/Altinn.Broker.Core/Repositories/IServiceOwnerRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Altinn.Broker.Core.Repositories;
44
public interface IServiceOwnerRepository
55
{
6-
Task InitializeServiceOwner(string sub, string name);
6+
Task InitializeServiceOwner(string sub, string name, TimeSpan fileTimeToLive);
77
Task<ServiceOwnerEntity?> GetServiceOwner(string sub);
88
Task InitializeStorageProvider(string sub, string resourceName, StorageProviderType storageType);
99
}

src/Altinn.Broker.Core/Services/IBrokerStorageService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public interface IBrokerStorageService
1414
Task UploadFile(ServiceOwnerEntity serviceOwnerEntity, FileEntity fileEntity, Stream stream);
1515

1616
Task<Stream> DownloadFile(ServiceOwnerEntity serviceOwnerEntity, FileEntity file);
17+
Task DeleteFile(ServiceOwnerEntity serviceOwnerEntity, FileEntity fileEntity);
1718
}

src/Altinn.Broker.Integrations/Azure/AzureBrokerStorageService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ public async Task<Stream> DownloadFile(ServiceOwnerEntity serviceOwnerEntity, Fi
3333
return await _fileStore.GetFileStream(fileEntity.FileId, connectionString);
3434
}
3535

36+
public async Task DeleteFile(ServiceOwnerEntity serviceOwnerEntity, FileEntity fileEntity)
37+
{
38+
var connectionString = await GetConnectionString(serviceOwnerEntity);
39+
await _fileStore.DeleteFile(fileEntity.FileId, connectionString);
40+
}
41+
3642
private async Task<string> GetConnectionString(ServiceOwnerEntity serviceOwnerEntity)
3743
{
3844
if (_hostEnvironment.IsDevelopment())

src/Altinn.Broker.Integrations/Azure/BlobService.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,12 @@ public async Task<bool> IsOnline(string connectionString)
5151
return false;
5252
}
5353
}
54+
55+
public async Task DeleteFile(Guid fileId, string connectionString)
56+
{
57+
var blobServiceClient = new BlobServiceClient(connectionString);
58+
var containerClient = blobServiceClient.GetBlobContainerClient("brokerfiles");
59+
BlobClient blobClient = containerClient.GetBlobClient(fileId.ToString());
60+
await blobClient.DeleteIfExistsAsync();
61+
}
5462
}

0 commit comments

Comments
 (0)