Learned a small backend project on Bilibili, then found that the file upload design is quite good. Let's implement and explain it.
Preface
Design of .NET File Upload Service
The project structure is as follows: I'm sorry, but I can't translate images. Please provide the text you'd like translated. Based on Strategy + Factory Pattern to Implement File Upload Service
Enumeration
Create it in the Model layer.
public enum UploadMode
Please provide the content you would like translated to English.
Local = 1, // Local upload
Qiniu = 2 // Qiniu Cloud Upload
}
Please provide the content you would like translated to English.
# Step 1: Create File Policy and Factory
Create a `FileStrategy` folder in the Service layer, and under this folder, create `Strategy`, `QiNiuStrategy`, `LocalStrategy`, `FileFactory`, and `FileContext`.
class
## Strategy File Operation Abstract Class
```C#
/// <summary>
/// File operation abstract class
/// </summary>
```java
public abstract class Strategy
Please provide the content you would like translated to English.
public abstract Task<string> Upload(List<IFormFile> formFiles);
} Please provide the content you would like translated to English.
LocalStrategy Local Strategy
Inherit the Strategy file operation abstract class and implement its methods.
To be implemented next is this method.
```java
public class LocalStrategy extends Strategy {
}
Please provide the content you would like translated to English.
public override async Task<string> Upload(List<IFormFile> formFiles)
Please provide the content you would like translated to English. throw new NotImplementedException(); } } Sure, please provide the content you would like translated to English.
QiNiuStrategy Qiniu Cloud Strategy
The same as above
```java
public class QiNiuStrategy extends Strategy {
}
Please provide the content you would like translated to English.
public override async Task<string> Upload(List<IFormFile> formFiles)
Please provide the content you would like translated to English. throw new NotImplementedException(); } } Sure, please provide the content you would like translated to English.
FileContext Context
In the Strategy pattern, call specific strategies through the context.
The advantage here is that if I use new LocalStrategy, it will be a local upload service, and if I use new QiNiuStrategy, it will be the Qiniu Cloud upload. For more details, see the design of the factory below.
/// <summary>
Context, used to invoke the specific strategy.
/// </summary>
```java
public class FileContext
Please provide the content you would like translated to English.
private Strategy _strategy;
private List
public async Task<string> ContextInterface()
Please provide the content you would like translated to English. return await _strategy.Upload(_formFiles); } } Sure, please provide the content you would like translated to English.
FileFactory Factory
By having the factory responsible for object instantiation. The purpose of enumeration comes into play, using the enumeration to determine which object to instantiate.
///
public class FileFactory
Please provide the content you want to translate.
public static Strategy createStrategy(UploadMode mode)
Please provide the content you would like translated to English.
switch (mode)
Please provide the content you would like translated to English.
case UploadMode.Qiniu:
return new QiNiuStrategy();
case UploadMode.Local:
return new LocalStrategy();
default:
return new QiNiuStrategy();
}
}
}
Please provide the content you would like translated to English.
Step 2: Integrate with the Service Layer
Create the IFileService interface in the Interface layer.
Here, you need to install the Http NuGet package; otherwise, there will be no IFormFile. I downloaded Microsoft.AspNetCore.Http/2.2.2.
```java
public interface IFileService
Please provide the content you would like translated.
Task
```java
public class FileService implements IFileService {
Please provide the content you would like translated to English.
public async Task<string> Upload(List<IFormFile> files, UploadMode mode)
Please provide the content you would like translated to English.
FileContext fileContext = new FileContext(FileFactory.CreateStrategy(mode), files);
return await fileContext.ContextInterface();
}
}
Please provide the content you would like translated to English.
The above calls a specific strategy through the context, creates a specific class through the factory, and the factory uses the passed-in enumeration as a parameter (constructor argument). The upload logic can be completed through the ContextInterface of the context.
The benefits of strategy + factory are that in the future, if you need to modify or upload files, you only need to change and supplement the strategy. This means that if you want to add a new upload policy, you just need to create a strategy class and then instantiate it in the factory class; there is no need to touch the Service layer.
Implementation of Local Upload Functionality
Implement the upload method in the local strategy class.
Note that var filePath = $"{AppContext.BaseDirectory}/wwwroot"; saves the file in the wwwroot directory under the bin directory.
```java
public class LocalStrategy extends Strategy {
}
Please accurately translate the following content into English (do not explain, just output the translation):
public override async Task<string> Upload(List<IFormFile> formFiles)
Please provide the content you would like translated to English.
var res = await Task.Run(() =>
Please provide the content you would like translated to English.
// Store multiple file paths
List
var filePath = $"{AppContext.BaseDirectory}/wwwroot";
var fileName = $"/{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";
if (!Directory.Exists(filePath)) Please provide the content you would like translated to English. Directory.CreateDirectory(filePath); }
using (var stream = System.IO.File.Create(filePath + fileName))
Please provide the content you would like translated to English. formFile.CopyTo(stream); } result.Add(fileName); } } return String.Join(",", result); }); return res; } }
Please provide the content you would like translated to English.
# Implementation of Qiniu Cloud Upload Functionality
Register for Qiniu Cloud: https://www.qiniu.com/
Retrieve key information from the personal center, install the SDK, and write the upload logic.
Install the `Qiniu` NuGet package in the Service layer.
"ak, sk are the secret keys for Qiniu Cloud, which can be viewed in your personal center."
```c#
```java
public class QiNiuStrategy extends Strategy {
}
Please provide the content you would like translated to English.
public override async Task<string> Upload(List<IFormFile> formFiles)
Please provide the content you would like translated to English. //First upload to the local machine, then upload to Qiniu Cloud. After the upload is complete, the file on the local machine can be deleted.
var res = await Task.Run(() =>
Please provide the content you would like translated to English.
Mac mac = new Mac("ak", "sk");
List
var filePath_temp = $"{AppContext.BaseDirectory}/Images_temp";
var fileName = $"{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";
if (!System.IO.Directory.Exists(filePath_temp)) Please provide the content you would like translated to English. Directory.CreateDirectory(filePath_temp); }
using (var stream = System.IO.File.Create($"{filePath_temp}/{fileName}"))
Please provide the content you would like translated to English. formFile.CopyTo(stream); } // Upload file name string key = fileName; // Local file path string filePath = $"/"; // Bucket name string Bucket = "pl-static"; // Set upload policy PutPolicy putPolicy = new PutPolicy(); // Set the target space for upload putPolicy.Scope = Bucket; // Expiration time of the upload policy (unit: seconds) //putPolicy.setExpires(3600); // After the file upload is complete, how many days it will be automatically deleted //putPolicy.DeleteAfterDays = 1; // Generate upload token string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString()); Config config = new Config(); // Set upload area
config.Zone = Zone.ZONE_CN_East;
// Set HTTP or HTTPS upload config.UseHttps = true; config.UseCdnDomains = true;
config.ChunkSize = ChunkUnit.U512K;
// Form upload FormUploader target = new FormUploader(config); HttpResult httpResult = target.UploadFile(filePath, key, token, null); result.Add(fileName); //Delete backup folder Directory.Delete(filePath_temp, true); } } return String.Join(",", result); }); return res; } } Sure, please provide the content you would like translated to English. Implementation of the Controller If mode is 1, the local upload logic code will be executed; if mode is 2, the Qiniu Cloud upload service code will be executed.
[Route("api/[controller]/[action]")]
[ApiController]
```csharp
public class FileController : ControllerBase
Please provide the content you would like translated to English. private readonly IFileService _fileService;
public FileController(IFileService fileService)
Please provide the content you would like translated to English.
_fileService = fileService;
}
///
public async Task<ApiResult> UploadFile(List<IFormFile> files, UploadMode mode)
Please provide the content you would like translated to English. return ResultHelper.Success(await _fileService.Upload(file, mode)); } } Sure, please provide the content you would like translated to English.
Test
I'm sorry, but I can't translate images. Please provide the text you'd like translated instead. I'm sorry, but I can't translate images. Please provide the text you'd like translated instead. The returned image path can be modified according to your needs. Go to the bin directory to check if the image has been uploaded successfully. I'm sorry, but I can't translate images. Please provide the text you'd like translated instead.
Summary
The above content is the design for a file upload service. If there are other file upload requirements, such as chunked resumable uploads or uploading to other service providers, just add new policies and complete the logic code; it is still quite convenient for designing a file upload service.