它有什么作用?

总结一下代码的作用,这是一个分步说明:

  1. 通过HTTP POST上传在网络浏览器中提交的文件。
  2. 将文件转换为字节数组。
  3. 将文件数据保存到本地文件系统、CDN获取其他你想存储的地方。

它实际上是做什么的?

让我们更深入地看一下代码。

  1. Home控制器下的Index视图显示一个输入字段,用于选择要上传的文件,以及一个Submit按钮以完成上传过程。 这是一个片段:
<form enctype =“ multipart/form-data” method =“ post”>
...
   <input multiple =“ multiple” name =“ files” type =“ file” />
...
   <input type =“ submit” value =“上传” />
...
</ form>
  1. 接下来,Home控制器的Post方法处理上载的文件。它设置为循环浏览多个上传的文件,并分别上传每个文件。
[HttpPost("UploadFiles")]
//OPTION A: 禁用Asp.Net Core的默认上载大小限制
[DisableRequestSizeLimit]
//OPTION B: 取消注释以设置指定的上载文件限制
//[RequestSizeLimit(40000000)] 
public async Task<IActionResult> Post(List<IFormFile> files)
{
    var uploadSuccess = false;
    string uploadedUri = null;

    foreach (var file in files)
    {
        if (file.Length <= 0)
        {
            continue;
        }

        await using var memoryStream = new MemoryStream();
        await file.CopyToAsync(memoryStream);
                
        // OPTION A: CDN
        //(uploadSuccess, uploadedUri) = await UploadToCDN(file.FileName, file.OpenReadStream());

        // OPTION B: LocalStorage   
        (uploadSuccess, uploadedUri) = await UploadToLocalStorage(file.FileName, memoryStream);

        TempData["uploadedUri"] = uploadedUri;
    }

    if (uploadSuccess)
        return View("UploadSuccess");
    else
        return View("UploadError");
}
private async Task<(bool, string)> UploadToLocalStorage(string filename, MemoryStream stream = null)
{
    if (stream == null)
    {
        return (false, null);
    }

    var rootPath = Path.Join(_env.ContentRootPath, FileUploadPath);
    if (!Directory.Exists(rootPath)) Directory.CreateDirectory(rootPath);

    var fileMd5 = BitConverter.ToString(System.Security.Cryptography.MD5.Create().ComputeHash(stream)).Replace("-", "");
    var imageName = $"img_{DateTime.UtcNow:yyyy_MM_dd}_{fileMd5}{Path.GetExtension(filename)}";

    var imageFullName = Path.Join(rootPath, imageName);
    if (!System.IO.File.Exists(imageFullName))
    {
        await System.IO.File.WriteAllBytesAsync(imageFullName, stream.ToArray());
    }

    return (true, imageName);
}
private async Task<(bool, string)> UploadToCDN(string filename, Stream stream = null)
{
    if (stream == null)
    {
        return (false, null);
    }
    using HttpContent content = new StreamContent(stream);

    content.Headers.Add(FileType, Path.GetExtension(filename).ToUpper());

    var client = _clientFactory.CreateClient(CDNClient);
    var response = await client.PostAsync("UpLoadForByte.ashx", content);
    if (response != null && response.IsSuccessStatusCode)
    {
        var responseStr = await response.Content.ReadAsStringAsync();
        if (responseStr.Equals("Error", StringComparison.CurrentCultureIgnoreCase))
        {
            return (false, "CDN服务器异常");
        }
        return (true, responseStr.Replace("http:", "https:"));
    }
    else
    {
        return (false, $"CDN服务器请求失败,{response.StatusCode}");
    }
}
  1. 然后我们测试结果如下: OPTION A:上传到CDN file

    OPTION B:存储到本地文件系统 file

  2. 关于CDN上传使用的是HttpClient,使用文档请参考 https://docs.microsoft.com/zh-cn/dotnet/api/system.net.http.ihttpclientfactory?view=dotnet-plat-ext-3.1