后端实现下载功能

原理是获取图片的二进制byte[],转成MemoryStream流,加入到响应头header和响应体Body中供前端访问下载

Controller.cs 文件

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Threading.Tasks;
using BaseService.Common;
using BaseService.Domain.Shared.Common;
using Tzkj.AspNetCore.ActionResults;
using Tzkj.Core.Constants;
using Tzkj.Core.Enums;
using Volo.Abp;
using BaseService.Controllers;
using System.Net;
using Tzkj.Superhard.Domain.Shared.Volo.Abp.Users;

namespace BaseService.HttpApi.Common;

[Area("base")]
[Route("api/base/storage")]
public class StorageController : BaseServiceController
{
    private readonly IStorageAppService _storageAppService;

    public StorageController(IStorageAppService storageAppService)
    {
        _storageAppService = storageAppService;
    }
    /// <summary>
    /// 上传文件
    /// </summary>
    /// <param name="contentType">RoleCert:角色认证资料;Promotion:宣传视频;Page:cms文章</param>
    /// <param name="fileType">1:doc/docx/pdf;2:图片".png", ".jpg", ".jpeg";3:视频 ".mp4", ".avi", ".wmv";4:压缩包 .rar</param>
    /// <param name="file">上传文件</param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    [HttpPost("upload")]
    [RequestFormLimits(MultipartBodyLengthLimit = BlobStoringConstants.Upload.MultipartBodyLengthLimit)]
    [RequestSizeLimit(BlobStoringConstants.Upload.MaxRequestBodySize)]
    public async Task<string> UpdateAsync([FromForm]string contentType,[FromForm] AllowUploadFileType fileType, IFormFile file)
    {
        var storageContentType = StorageContentType.FromValue(contentType);
        if((int)fileType==0)
            throw new UserFriendlyException("请提供要上传的文件类型!");
        using var memoryStream = new MemoryStream();
        await file.CopyToAsync(memoryStream);

        return await _storageAppService.UploadAsync(file.FileName,memoryStream,storageContentType,fileType);
    }

    [HttpPost("download")]
    public async Task<MultiFileResult> DownloadAsync(string storageName)
    {
        var bytes = await _storageAppService.DownloadAsync(storageName);
        var fileName = Path.GetFileName(storageName);
        return new MultiFileResult(bytes, fileName);
    }

        /// <summary>
        /// 下载会员证书(这样也可以)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("download-memberCard")]
        public async Task<MultiFileResult> DownloadMeberCardAsync(Guid id)
        {
            var bytes = await _companyInfoService.GetMemberCardUrlAsync(id);
            //var fileName = Path.GetFileName(storageName);
            var fileName = "memberCard.jpeg";
            return new MultiFileResult(bytes, fileName);
        }


    [HttpDelete]
    public async Task DeleteAsync(string storageName)
    {
        await _storageAppService.DeleteAsync(storageName);
    }
    [HttpGet]
    public Task<string> GetStorageFullUrl(string storageName)
    {
        return Task.FromResult(_storageAppService.GetMinioStorageFullUrl(storageName));
    }
}

还有中情况pemkey类型的文件可以直接File打开二进制下载

/// <summary>
/// 获取授权请求文件
/// </summary>
/// <returns></returns>
[HttpGet("/auth-apply-file")]
public IActionResult DownloadAuthRequestFileAsync(string versionId,string appId)
{
    byte[] data = _sdkACLService.GetAuthApplyInfo(versionId,appId);
    var contentDisposition = new System.Net.Mime.ContentDisposition
    { 
        FileName = "AuthApplyInfo.pemkey"
    };
    Response.Headers.Add("Content-Disposition", contentDisposition.ToString());

    return File(data, "text/plain");
}

 StorageAppService.cs文件

using System;
using System.Collections.Generic;
using BaseService.Domain.Shared.Common;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Tzkj.BlobStorings;
using Tzkj.BlobStorings.Abstractions;
using Tzkj.Core.Constants;
using Tzkj.Core.Enums;
using Volo.Abp.Application.Services;
using Volo.Abp.BlobStoring;
using Volo.Abp.Validation;
using Volo.Abp;

namespace BaseService.Common;

[RemoteService(IsEnabled = false)]
public class StorageAppService : ApplicationService, IStorageAppService
{
    private readonly IBlobContainer<MinioContainer> _blobContainer;
    private readonly MinioOptions _minioOptions;
    public StorageAppService(IOptions<MinioOptions> options, IBlobContainer<MinioContainer> blobContainer)
    {
        _blobContainer = blobContainer;
        _minioOptions = options.Value;
    }
    [DisableValidation]
    public async Task<string> UploadAsync(string physicalFileName, Stream fileStream, StorageContentType contentType, AllowUploadFileType allowUploadFileType)
    {
        FileUploadHelper.VerifyStreamedFile(physicalFileName, fileStream,allowUploadFileType, BlobStoringConstants.Upload.MultipartBodyLengthLimit);

        var fileExt = Path.GetExtension(physicalFileName);
        var relativeUri = FileUploadHelper.GetRelativeUri(new List<string>{contentType.Value,allowUploadFileType.ToString()}, $"{Path.GetFileNameWithoutExtension(physicalFileName)}_{GuidGenerator.Create()}", fileExt);

        await _blobContainer.SaveAsync(relativeUri, fileStream, true);
        var fullUri = GetMinioStorageFullUrl(relativeUri);
        return fullUri;
    }

    public Task<byte[]> DownloadAsync(string storageName)
    {
        return _blobContainer.GetAllBytesOrNullAsync(storageName);
    }

    public Task DeleteAsync(string storageName)
    {
        return _blobContainer.DeleteAsync(storageName);
    }

    /// <summary>
    /// 获取存储对象访问地址
    /// </summary>
    /// <param name="storageName"></param>
    /// <returns></returns>
    public string GetMinioStorageFullUrl(string storageName)
    {
        storageName = storageName.TrimStart('/');
        var endpoint = _minioOptions.OutSideEndpoint.Split(':');
        var host = endpoint[0];
        var port = endpoint.Length > 1 ? endpoint[1] : "80";
        var builder = new UriBuilder("http", host,Convert.ToInt32(port));
        var paths=new List<string> { _minioOptions.BucketName,"host",storageName};
        builder.Path = Path.Combine(paths.ToArray());
        return builder.ToString();
    }
}

MultiFileResult.cs文件

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Volo.Abp;
using Volo.Abp.Http;

namespace Tzkj.AspNetCore.ActionResults;

public class MultiFileResult : ActionResult
{
    private readonly byte[] _fileBytes;
    private readonly string _fileNameWithExt;

    public MultiFileResult(byte[] fileBytes, string fileNameWithExt)
    {
        _fileBytes = fileBytes;
        _fileNameWithExt = fileNameWithExt;
    }
    public override async Task ExecuteResultAsync(ActionContext context)
    {
        context.HttpContext.Response.ContentType = GetMimeType(_fileNameWithExt);
        using var stream = new MemoryStream(_fileBytes);

        context.HttpContext.Response.Headers.Add("Content-Disposition", (StringValues)new string[1]
        {
            "attachment; filename=" + WebUtility.UrlEncode(_fileNameWithExt)
        });
        await stream.CopyToAsync(context.HttpContext.Response.Body);
    }

    private string GetMimeType(string fileNameWithExt)
    {
        var extName = Path.GetExtension(fileNameWithExt).ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(extName))
            throw new UserFriendlyException("缺少文件扩展名,未知文件类型");
        else if (extName.Equals(".doc"))
            return "application/msword";
        else if (extName.Equals(".docx"))
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        else if (extName.Equals(".pdf"))
            return MimeTypes.Application.Pdf;
        else if (extName.Equals(".rar") ||
                 extName.Equals(".pkl"))
            return "application/octet-stream";
        else if (extName.Equals(".jpeg"))
            return MimeTypes.Image.Jpeg;
        throw new BusinessException("不支持的文件扩展名");


    }
}

 

 

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吱吱喔喔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值