OSS配置
This commit is contained in:
parent
2d4e2c3c60
commit
e3261fe596
@ -3,7 +3,6 @@ using YD_Event.Core.Entities;
|
|||||||
using YD_Event.Core.Domain.Certificate;
|
using YD_Event.Core.Domain.Certificate;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using OnceMi.AspNetCore.OSS;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YD_Event.Core.Options;
|
using YD_Event.Core.Options;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
@ -18,6 +17,7 @@ using System.Linq;
|
|||||||
using QuestPDF.Fluent;
|
using QuestPDF.Fluent;
|
||||||
using QuestPDF.Helpers;
|
using QuestPDF.Helpers;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
|
using YD_Event.Application.File;
|
||||||
|
|
||||||
namespace YD_Event.Application.Certificate;
|
namespace YD_Event.Application.Certificate;
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Certificate> _certificateRepository;
|
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Certificate> _certificateRepository;
|
||||||
private readonly ISqlSugarRepository<CertificateTemplate> _templateRepository;
|
private readonly ISqlSugarRepository<CertificateTemplate> _templateRepository;
|
||||||
private readonly ISqlSugarRepository<CertificatePlaceholder> _placeholderRepository;
|
private readonly ISqlSugarRepository<CertificatePlaceholder> _placeholderRepository;
|
||||||
private readonly IOSSService _ossService;
|
private readonly FileService _fileService;
|
||||||
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
||||||
private readonly IIdGenerator _idGenerator;
|
private readonly IIdGenerator _idGenerator;
|
||||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||||
@ -42,7 +42,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
ISqlSugarRepository<YD_Event.Core.Entities.Certificate> certificateRepository,
|
ISqlSugarRepository<YD_Event.Core.Entities.Certificate> certificateRepository,
|
||||||
ISqlSugarRepository<CertificateTemplate> templateRepository,
|
ISqlSugarRepository<CertificateTemplate> templateRepository,
|
||||||
ISqlSugarRepository<CertificatePlaceholder> placeholderRepository,
|
ISqlSugarRepository<CertificatePlaceholder> placeholderRepository,
|
||||||
IOSSService ossService,
|
FileService fileService,
|
||||||
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
||||||
IIdGenerator idGenerator,
|
IIdGenerator idGenerator,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
@ -54,7 +54,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
_certificateRepository = certificateRepository;
|
_certificateRepository = certificateRepository;
|
||||||
_templateRepository = templateRepository;
|
_templateRepository = templateRepository;
|
||||||
_placeholderRepository = placeholderRepository;
|
_placeholderRepository = placeholderRepository;
|
||||||
_ossService = ossService;
|
_fileService = fileService;
|
||||||
_ossOptionsMonitor = ossOptionsMonitor;
|
_ossOptionsMonitor = ossOptionsMonitor;
|
||||||
_idGenerator = idGenerator;
|
_idGenerator = idGenerator;
|
||||||
_webHostEnvironment = webHostEnvironment;
|
_webHostEnvironment = webHostEnvironment;
|
||||||
@ -790,8 +790,8 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
if (!options.Enable)
|
if (!options.Enable)
|
||||||
{
|
{
|
||||||
// 本地存储
|
// 本地存储
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
string localDir = string.Concat(options.Bucket?.TrimEnd('/') ?? "", filePath);
|
||||||
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir);
|
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir.TrimStart('/'));
|
||||||
|
|
||||||
if (!Directory.Exists(absoluteDir))
|
if (!Directory.Exists(absoluteDir))
|
||||||
{
|
{
|
||||||
@ -804,7 +804,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
var request = _httpContextAccessor.HttpContext?.Request;
|
var request = _httpContextAccessor.HttpContext?.Request;
|
||||||
if (request != null)
|
if (request != null)
|
||||||
{
|
{
|
||||||
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir}{name}";
|
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir.TrimStart('/')}{name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
using var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
using var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
||||||
@ -815,12 +815,8 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// OSS 上传
|
// OSS 上传
|
||||||
string fileName = $"{filePath}{name}";
|
string fileName = $"{filePath.TrimStart('/')}{name}";
|
||||||
await _ossService.PutObjectAsync(options.Bucket, fileName, pdfStream);
|
finalUrl = await _fileService.UploadFileStreamAsync(fileName, pdfStream);
|
||||||
|
|
||||||
// 预测最终 URL
|
|
||||||
string bucketPrefix = (options.Provider == OSSProvider.Minio) ? $"/{options.Bucket}" : string.Empty;
|
|
||||||
finalUrl = $"{options.Domain.TrimEnd('/')}{bucketPrefix}{fileName}";
|
|
||||||
|
|
||||||
_logger.LogInformation("PDF文件上传到OSS: {FileName}", fileName);
|
_logger.LogInformation("PDF文件上传到OSS: {FileName}", fileName);
|
||||||
}
|
}
|
||||||
@ -858,30 +854,12 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
string extension = ".png";
|
string extension = ".png";
|
||||||
string finalUrl = string.Empty;
|
string finalUrl = string.Empty;
|
||||||
|
|
||||||
// 预测最终 URL
|
|
||||||
if (!options.Enable)
|
|
||||||
{
|
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
|
||||||
var request = _httpContextAccessor.HttpContext?.Request;
|
|
||||||
if (request != null)
|
|
||||||
{
|
|
||||||
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir}{name}{extension}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string bucketPrefix = (options.Provider == OSSProvider.Minio) ? $"/{options.Bucket}" : string.Empty;
|
|
||||||
string fileName = $"{filePath}{name}{extension}";
|
|
||||||
finalUrl = $"{options.Domain.TrimEnd('/')}{bucketPrefix}{fileName}";
|
|
||||||
}
|
|
||||||
|
|
||||||
qrStream.Position = 0;
|
qrStream.Position = 0;
|
||||||
|
|
||||||
if (!options.Enable)
|
if (!options.Enable)
|
||||||
{
|
{
|
||||||
// 本地存储
|
string localDir = string.Concat(options.Bucket?.TrimEnd('/') ?? "", filePath);
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir.TrimStart('/'));
|
||||||
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir);
|
|
||||||
|
|
||||||
if (!Directory.Exists(absoluteDir))
|
if (!Directory.Exists(absoluteDir))
|
||||||
{
|
{
|
||||||
@ -891,12 +869,18 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
string fullPath = Path.Combine(absoluteDir, $"{name}{extension}");
|
string fullPath = Path.Combine(absoluteDir, $"{name}{extension}");
|
||||||
using var fileStream2 = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
using var fileStream2 = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
||||||
await qrStream.CopyToAsync(fileStream2);
|
await qrStream.CopyToAsync(fileStream2);
|
||||||
|
|
||||||
|
var request = _httpContextAccessor.HttpContext?.Request;
|
||||||
|
if (request != null)
|
||||||
|
{
|
||||||
|
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir.TrimStart('/')}{name}{extension}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// OSS 上传
|
// OSS 上传
|
||||||
string fileName = $"{filePath}{name}{extension}";
|
string fileName = $"{filePath.TrimStart('/')}{name}{extension}";
|
||||||
await _ossService.PutObjectAsync(options.Bucket, fileName, qrStream);
|
finalUrl = await _fileService.UploadFileStreamAsync(fileName, qrStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalUrl;
|
return finalUrl;
|
||||||
@ -928,23 +912,20 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
if (!options.Enable)
|
if (!options.Enable)
|
||||||
{
|
{
|
||||||
// 本地存储
|
// 本地存储
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
string localDir = string.Concat(options.Bucket?.TrimEnd('/') ?? "", filePath);
|
||||||
|
|
||||||
// 预测最终 URL
|
// 预测最终 URL
|
||||||
var request = _httpContextAccessor.HttpContext?.Request;
|
var request = _httpContextAccessor.HttpContext?.Request;
|
||||||
if (request != null)
|
if (request != null)
|
||||||
{
|
{
|
||||||
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir}{name}";
|
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir.TrimStart('/')}{name}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// OSS 上传
|
// OSS 上传
|
||||||
string fileName = $"{filePath}{name}";
|
string fileName = $"{filePath.TrimStart('/')}{name}";
|
||||||
|
finalUrl = $"{options.Domain.TrimEnd('/')}/{fileName}";
|
||||||
// 预测最终 URL
|
|
||||||
string bucketPrefix = (options.Provider == OSSProvider.Minio) ? $"/{options.Bucket}" : string.Empty;
|
|
||||||
finalUrl = $"{options.Domain.TrimEnd('/')}{bucketPrefix}{fileName}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalUrl;
|
return finalUrl;
|
||||||
@ -992,7 +973,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// OSS 上传
|
// OSS 上传
|
||||||
await _ossService.PutObjectAsync(options.Bucket, relativePath, pdfStream);
|
await _fileService.UploadFileStreamAsync(relativePath, pdfStream);
|
||||||
|
|
||||||
_logger.LogInformation("PDF文件上传到OSS: {FileName}", relativePath);
|
_logger.LogInformation("PDF文件上传到OSS: {FileName}", relativePath);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,13 +3,13 @@ using YD_Event.Core.Entities;
|
|||||||
using YD_Event.Core.Domain.Certificate;
|
using YD_Event.Core.Domain.Certificate;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using OnceMi.AspNetCore.OSS;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using YD_Event.Core.Options;
|
using YD_Event.Core.Options;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using YD_Event.Application.File;
|
||||||
|
|
||||||
namespace YD_Event.Application.Certificate;
|
namespace YD_Event.Application.Certificate;
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ public class CertificateTemplateService : BaseService<CertificateTemplate>, ITra
|
|||||||
{
|
{
|
||||||
private readonly ISqlSugarRepository<CertificateTemplate> _templateRepository;
|
private readonly ISqlSugarRepository<CertificateTemplate> _templateRepository;
|
||||||
private readonly ISqlSugarRepository<CertificatePlaceholder> _placeholderRepository;
|
private readonly ISqlSugarRepository<CertificatePlaceholder> _placeholderRepository;
|
||||||
private readonly IOSSService _ossService;
|
private readonly FileService _fileService;
|
||||||
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
||||||
private readonly IIdGenerator _idGenerator;
|
private readonly IIdGenerator _idGenerator;
|
||||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||||
@ -31,7 +31,7 @@ public class CertificateTemplateService : BaseService<CertificateTemplate>, ITra
|
|||||||
public CertificateTemplateService(
|
public CertificateTemplateService(
|
||||||
ISqlSugarRepository<CertificateTemplate> templateRepository,
|
ISqlSugarRepository<CertificateTemplate> templateRepository,
|
||||||
ISqlSugarRepository<CertificatePlaceholder> placeholderRepository,
|
ISqlSugarRepository<CertificatePlaceholder> placeholderRepository,
|
||||||
IOSSService ossService,
|
FileService fileService,
|
||||||
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
||||||
IIdGenerator idGenerator,
|
IIdGenerator idGenerator,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
@ -41,7 +41,7 @@ public class CertificateTemplateService : BaseService<CertificateTemplate>, ITra
|
|||||||
{
|
{
|
||||||
_templateRepository = templateRepository;
|
_templateRepository = templateRepository;
|
||||||
_placeholderRepository = placeholderRepository;
|
_placeholderRepository = placeholderRepository;
|
||||||
_ossService = ossService;
|
_fileService = fileService;
|
||||||
_ossOptionsMonitor = ossOptionsMonitor;
|
_ossOptionsMonitor = ossOptionsMonitor;
|
||||||
_idGenerator = idGenerator;
|
_idGenerator = idGenerator;
|
||||||
_webHostEnvironment = webHostEnvironment;
|
_webHostEnvironment = webHostEnvironment;
|
||||||
@ -345,30 +345,20 @@ public class CertificateTemplateService : BaseService<CertificateTemplate>, ITra
|
|||||||
string filePath = $"/templates/{now.Year}/{now.Month:D2}/{now.Day:D2}/";
|
string filePath = $"/templates/{now.Year}/{now.Month:D2}/{now.Day:D2}/";
|
||||||
string finalUrl = string.Empty;
|
string finalUrl = string.Empty;
|
||||||
|
|
||||||
// 预测最终 URL
|
|
||||||
if (!options.Enable)
|
|
||||||
{
|
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
|
||||||
var request = _httpContextAccessor.HttpContext?.Request;
|
|
||||||
if (request != null)
|
|
||||||
{
|
|
||||||
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir}{name}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string bucketPrefix = (options.Provider == OSSProvider.Minio) ? $"/{options.Bucket}" : string.Empty;
|
|
||||||
string fileName = $"{filePath}{name}";
|
|
||||||
finalUrl = $"{options.Domain.TrimEnd('/')}{bucketPrefix}{fileName}";
|
|
||||||
}
|
|
||||||
|
|
||||||
using var stream = file.OpenReadStream();
|
using var stream = file.OpenReadStream();
|
||||||
|
|
||||||
if (!options.Enable)
|
if (!options.Enable)
|
||||||
{
|
{
|
||||||
|
// 预测最终 URL
|
||||||
|
string localDir = string.Concat(options.Bucket?.TrimEnd('/') ?? "", filePath);
|
||||||
|
var request = _httpContextAccessor.HttpContext?.Request;
|
||||||
|
if (request != null)
|
||||||
|
{
|
||||||
|
finalUrl = $"{request.Scheme}://{request.Host.Value}/{localDir.TrimStart('/')}{name}";
|
||||||
|
}
|
||||||
|
|
||||||
// 本地存储
|
// 本地存储
|
||||||
string localDir = string.Concat(options.Bucket.TrimEnd('/'), filePath);
|
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir.TrimStart('/'));
|
||||||
string absoluteDir = Path.Combine(_webHostEnvironment.WebRootPath, localDir);
|
|
||||||
|
|
||||||
if (!Directory.Exists(absoluteDir))
|
if (!Directory.Exists(absoluteDir))
|
||||||
{
|
{
|
||||||
@ -382,8 +372,8 @@ public class CertificateTemplateService : BaseService<CertificateTemplate>, ITra
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// OSS 上传
|
// OSS 上传
|
||||||
string fileName = $"{filePath}{name}";
|
string fileName = $"{filePath.TrimStart('/')}{name}";
|
||||||
await _ossService.PutObjectAsync(options.Bucket, fileName, stream);
|
finalUrl = await _fileService.UploadFileStreamAsync(fileName, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("模板文件上传成功. URL: {Url}", finalUrl);
|
_logger.LogInformation("模板文件上传成功. URL: {Url}", finalUrl);
|
||||||
|
|||||||
@ -2,36 +2,38 @@
|
|||||||
using YD_Event.Core.Options;
|
using YD_Event.Core.Options;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using OnceMi.AspNetCore.OSS;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using YD_Event.Core.Infrastructure.Aliyun.Oss;
|
||||||
|
|
||||||
namespace YD_Event.Application.File;
|
namespace YD_Event.Application.File;
|
||||||
|
|
||||||
public class FileService : IDynamicApiController, ITransient
|
public class FileService : IDynamicApiController, ITransient
|
||||||
{
|
{
|
||||||
private readonly IOSSService _ossService;
|
|
||||||
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||||
private readonly IIdGenerator _idGenerator;
|
private readonly IIdGenerator _idGenerator;
|
||||||
|
private readonly OssService _ossService;
|
||||||
|
|
||||||
public FileService(IOSSService ossService,
|
public FileService(
|
||||||
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
IIdGenerator idGenerator)
|
IIdGenerator idGenerator,
|
||||||
|
OssService ossService)
|
||||||
{
|
{
|
||||||
_ossService = ossService;
|
|
||||||
_ossOptionsMonitor = ossOptionsMonitor;
|
_ossOptionsMonitor = ossOptionsMonitor;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_webHostEnvironment = webHostEnvironment;
|
_webHostEnvironment = webHostEnvironment;
|
||||||
_idGenerator = idGenerator;
|
_idGenerator = idGenerator;
|
||||||
|
_ossService = ossService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上传附件
|
/// 上传附件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file"></param>
|
/// <param name="file">表单文件</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回上传文件信息</returns>
|
||||||
[NonUnify]
|
[NonUnify]
|
||||||
public async Task<List<UploadFileOutput>> Upload([Required] IFormFile file)
|
public async Task<List<UploadFileOutput>> Upload([Required] IFormFile file)
|
||||||
{
|
{
|
||||||
@ -47,52 +49,171 @@ public class FileService : IDynamicApiController, ITransient
|
|||||||
{
|
{
|
||||||
throw Oops.Bah("无效文件");
|
throw Oops.Bah("无效文件");
|
||||||
}
|
}
|
||||||
//文件路径
|
|
||||||
string filePath = $"/{now.Year}/{now.Month:D2}/{now.Day:D2}/";
|
|
||||||
// 文件完整名称
|
|
||||||
if (!options.Enable)
|
|
||||||
{
|
|
||||||
filePath = string.Concat(options.Bucket.TrimEnd('/'), filePath);//ptions.Bucket.TrimEnd('/') + filePath;
|
|
||||||
string s = Path.Combine(_webHostEnvironment.WebRootPath, filePath);
|
|
||||||
if (!Directory.Exists(s))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = System.IO.File.Create($"{s}{name}{extension}");
|
string filePath = $"{now.Year}/{now.Month:D2}/{now.Day:D2}/";
|
||||||
await file.CopyToAsync(stream);
|
|
||||||
await stream.DisposeAsync();
|
|
||||||
var request = _httpContextAccessor.HttpContext!.Request;
|
|
||||||
string url = $"{request.Scheme}://{request.Host.Value}/{filePath}{name}{extension}";
|
|
||||||
return new List<UploadFileOutput>()
|
|
||||||
{
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Name = $"{name}{extension}",
|
|
||||||
Url = url
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
string fileName = $"{filePath}{name}{extension}";
|
string fileName = $"{filePath}{name}{extension}";
|
||||||
await _ossService.PutObjectAsync(options.Bucket, fileName, file.OpenReadStream());
|
|
||||||
// 解决部分对象云存储不需要拼接bucket
|
using var stream = file.OpenReadStream();
|
||||||
string bucket;
|
string url = await UploadStreamInternal(fileName, stream, options);
|
||||||
switch (options.Provider)
|
|
||||||
{
|
|
||||||
case OSSProvider.Minio:
|
|
||||||
bucket = $"/{options.Bucket}";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bucket = string.Empty;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return new List<UploadFileOutput>()
|
return new List<UploadFileOutput>()
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Name = $"{name}{extension}",
|
Name = $"{name}{extension}",
|
||||||
Url = $"{options.Domain.TrimEnd('/')}{bucket}{fileName}"
|
Url = url
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上传文件流 (供其他服务调用)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">文件名及路径</param>
|
||||||
|
/// <param name="stream">文件流</param>
|
||||||
|
/// <returns>返回完整 URL</returns>
|
||||||
|
[NonAction]
|
||||||
|
public async Task<string> UploadFileStreamAsync(string fileName, Stream stream)
|
||||||
|
{
|
||||||
|
var options = _ossOptionsMonitor.CurrentValue;
|
||||||
|
return await UploadStreamInternal(fileName, stream, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部上传文件流
|
||||||
|
/// </summary>
|
||||||
|
private async Task<string> UploadStreamInternal(string fileName, Stream stream, OssConnectionOptions options)
|
||||||
|
{
|
||||||
|
if (!options.Enable)
|
||||||
|
{
|
||||||
|
// 本地存储
|
||||||
|
string basePath = Path.Combine(_webHostEnvironment.WebRootPath, options.Bucket ?? "uploads");
|
||||||
|
string fullPath = Path.Combine(basePath, fileName);
|
||||||
|
string dir = Path.GetDirectoryName(fullPath);
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var fileStream = System.IO.File.Create(fullPath);
|
||||||
|
await stream.CopyToAsync(fileStream);
|
||||||
|
|
||||||
|
var request = _httpContextAccessor.HttpContext?.Request;
|
||||||
|
if (request != null)
|
||||||
|
{
|
||||||
|
return $"{request.Scheme}://{request.Host.Value}/{(options.Bucket ?? "uploads")}/{fileName}";
|
||||||
|
}
|
||||||
|
return $"/{(options.Bucket ?? "uploads")}/{fileName}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OSS 上传
|
||||||
|
return await _ossService.PutObjectAsync(fileName, stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">文件 URL</param>
|
||||||
|
/// <returns>文件流结果</returns>
|
||||||
|
[HttpGet("download")]
|
||||||
|
public IActionResult Download([FromQuery] string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(url)) throw Oops.Bah("参数错误");
|
||||||
|
|
||||||
|
var options = _ossOptionsMonitor.CurrentValue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!options.Enable)
|
||||||
|
{
|
||||||
|
// 本地下载
|
||||||
|
var uri = new Uri(url);
|
||||||
|
string localPath = Path.Combine(_webHostEnvironment.WebRootPath, uri.AbsolutePath.TrimStart('/'));
|
||||||
|
if (!System.IO.File.Exists(localPath)) throw Oops.Bah("文件不存在");
|
||||||
|
|
||||||
|
var stream = System.IO.File.OpenRead(localPath);
|
||||||
|
return new FileStreamResult(stream, "application/octet-stream")
|
||||||
|
{
|
||||||
|
FileDownloadName = Path.GetFileName(localPath)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OSS 下载
|
||||||
|
// 解析 objectName (移除 Domain 部分)
|
||||||
|
string domainUrl = options.Domain.TrimEnd('/') + "/";
|
||||||
|
string objectName = url;
|
||||||
|
if (url.StartsWith(domainUrl, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
objectName = url.Substring(domainUrl.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
objectName = uri.AbsolutePath.TrimStart('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentStream = _ossService.GetObject(objectName);
|
||||||
|
return new FileStreamResult(contentStream, "application/octet-stream")
|
||||||
|
{
|
||||||
|
FileDownloadName = Path.GetFileName(objectName)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw Oops.Bah($"下载失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">文件 URL</param>
|
||||||
|
[HttpDelete("delete")]
|
||||||
|
public IActionResult Delete([FromQuery] string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(url)) throw Oops.Bah("参数错误");
|
||||||
|
|
||||||
|
var options = _ossOptionsMonitor.CurrentValue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!options.Enable)
|
||||||
|
{
|
||||||
|
// 本地删除
|
||||||
|
var uri = new Uri(url);
|
||||||
|
string localPath = Path.Combine(_webHostEnvironment.WebRootPath, uri.AbsolutePath.TrimStart('/'));
|
||||||
|
if (System.IO.File.Exists(localPath))
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(localPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OSS 删除
|
||||||
|
string domainUrl = options.Domain.TrimEnd('/') + "/";
|
||||||
|
string objectName = url;
|
||||||
|
if (url.StartsWith(domainUrl, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
objectName = url.Substring(domainUrl.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
objectName = uri.AbsolutePath.TrimStart('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
_ossService.DeleteObject(objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResult(new { success = true, msg = "删除成功" });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw Oops.Bah($"删除失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -5343,8 +5343,34 @@
|
|||||||
<summary>
|
<summary>
|
||||||
上传附件
|
上传附件
|
||||||
</summary>
|
</summary>
|
||||||
<param name="file"></param>
|
<param name="file">表单文件</param>
|
||||||
<returns></returns>
|
<returns>返回上传文件信息</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Application.File.FileService.UploadFileStreamAsync(System.String,System.IO.Stream)">
|
||||||
|
<summary>
|
||||||
|
上传文件流 (供其他服务调用)
|
||||||
|
</summary>
|
||||||
|
<param name="fileName">文件名及路径</param>
|
||||||
|
<param name="stream">文件流</param>
|
||||||
|
<returns>返回完整 URL</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Application.File.FileService.UploadStreamInternal(System.String,System.IO.Stream,YD_Event.Core.Options.OssConnectionOptions)">
|
||||||
|
<summary>
|
||||||
|
内部上传文件流
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Application.File.FileService.Download(System.String)">
|
||||||
|
<summary>
|
||||||
|
下载文件
|
||||||
|
</summary>
|
||||||
|
<param name="url">文件 URL</param>
|
||||||
|
<returns>文件流结果</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Application.File.FileService.Delete(System.String)">
|
||||||
|
<summary>
|
||||||
|
删除文件
|
||||||
|
</summary>
|
||||||
|
<param name="url">文件 URL</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:YD_Event.Application.Logging.Dtos.LogPageQueryInput">
|
<member name="T:YD_Event.Application.Logging.Dtos.LogPageQueryInput">
|
||||||
<summary>
|
<summary>
|
||||||
|
|||||||
@ -80,16 +80,12 @@
|
|||||||
},
|
},
|
||||||
//对象存储配置 文档:https://github.com/oncemi/OnceMi.AspNetCore.OSS
|
//对象存储配置 文档:https://github.com/oncemi/OnceMi.AspNetCore.OSS
|
||||||
"OssConnection": {
|
"OssConnection": {
|
||||||
"Enable": false, //是否启用对象存储(不启用将存储至站点目录)
|
"Enable": true, //是否启用对象存储(不启用将存储至站点目录)
|
||||||
"Provider": "Minio", //OSS提供者;允许值:Minio/Aliyun/QCloud/Qiniu/HuaweiCloud/(Invalid:代表附件存储到当前站点下)
|
"Endpoint": "oss-cn-shanghai.aliyuncs.com", //阿里云OSS节点
|
||||||
"Endpoint": "skip81.oss-cn-shanghai.aliyuncs.com", //节点
|
"AccessKeyId": "LTAI5tLfbdZwBoA9bCZVjZkF", //阿里云OSS AccessKeyId
|
||||||
"AccessKey": "LTAI5tLfbdZwBoA9bCZVjZkF", //Key
|
"AccessKeySecret": "4DmFIY77zwdp1gaRUTmBMf7WfdsNsC", //阿里云OSS AccessKeySecret
|
||||||
"SecretKey": "4DmFIY77zwdp1gaRUTmBMf7WfdsNsC", //秘钥
|
"Bucket": "skip81", //存储桶名称
|
||||||
//"Region": "ap-chengdu",//地域
|
"Domain": "https://skip81.oss-cn-shanghai.aliyuncs.com" //外网访问域名或IP
|
||||||
"IsEnableHttps": false, //是否启用HTTPS
|
|
||||||
"IsEnableCache": true, //是否启用缓存(启用后将缓存签名URL,以减少请求次数)
|
|
||||||
"Bucket": "skip81", //默认存储根目录: null,
|
|
||||||
"Domain": "https://oss.okay123.top" //外网访问域名或IP
|
|
||||||
},
|
},
|
||||||
// 接入第三方授权登录 文档:https://github.com/mrhuo/MrHuo.OAuth
|
// 接入第三方授权登录 文档:https://github.com/mrhuo/MrHuo.OAuth
|
||||||
// QQ授权申请地址:https://connect.qq.com/
|
// QQ授权申请地址:https://connect.qq.com/
|
||||||
|
|||||||
212
YD_Event.Core/Infrastructure/Aliyun/Oss/OssService.cs
Normal file
212
YD_Event.Core/Infrastructure/Aliyun/Oss/OssService.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aliyun.OSS;
|
||||||
|
using Furion.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Polly;
|
||||||
|
using YD_Event.Core.Options;
|
||||||
|
|
||||||
|
namespace YD_Event.Core.Infrastructure.Aliyun.Oss;
|
||||||
|
|
||||||
|
public class OssService : ISingleton
|
||||||
|
{
|
||||||
|
private readonly OssConnectionOptions _options;
|
||||||
|
private readonly IOss _ossClient;
|
||||||
|
private readonly ILogger<OssService> _logger;
|
||||||
|
private readonly AsyncPolicy _retryPolicy;
|
||||||
|
|
||||||
|
public OssService(IOptionsMonitor<OssConnectionOptions> optionsMonitor, ILogger<OssService> logger)
|
||||||
|
{
|
||||||
|
_options = optionsMonitor.CurrentValue;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
if (_options.Enable)
|
||||||
|
{
|
||||||
|
_ossClient = new OssClient(_options.Endpoint, _options.AccessKeyId, _options.AccessKeySecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义重试策略:最多重试3次,每次间隔指数增长
|
||||||
|
_retryPolicy = Policy
|
||||||
|
.Handle<Exception>()
|
||||||
|
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||||
|
(exception, timeSpan, retryCount, context) =>
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"OSS操作异常,正在进行第 {retryCount} 次重试. 异常: {exception.Message}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取完整的URL
|
||||||
|
/// </summary>
|
||||||
|
private string GetFullUrl(string objectName)
|
||||||
|
{
|
||||||
|
return $"{_options.Domain.TrimEnd('/')}/{objectName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 同步上传文件流
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
/// <param name="stream">文件数据流</param>
|
||||||
|
/// <returns>文件的访问 URL</returns>
|
||||||
|
public string PutObject(string objectName, Stream stream)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行上传操作。");
|
||||||
|
|
||||||
|
// Validate File Size (example limit: 500MB)
|
||||||
|
if (stream.Length > 500 * 1024 * 1024)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("文件大小超过限制(500MB)。");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ossClient.PutObject(_options.Bucket, objectName, stream);
|
||||||
|
return GetFullUrl(objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步上传文件流
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
/// <param name="stream">文件数据流</param>
|
||||||
|
/// <returns>文件的访问 URL</returns>
|
||||||
|
public async Task<string> PutObjectAsync(string objectName, Stream stream)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行上传操作。");
|
||||||
|
|
||||||
|
if (stream.Length > 500 * 1024 * 1024)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("文件大小超过限制(500MB)。");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _retryPolicy.ExecuteAsync(() =>
|
||||||
|
{
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
// OssClient 官方SDK大部分是同步方法,我们用Task包装
|
||||||
|
_ossClient.PutObject(_options.Bucket, objectName, stream);
|
||||||
|
return GetFullUrl(objectName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步分片上传大文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
/// <param name="stream">文件数据流</param>
|
||||||
|
/// <param name="progressCallback">进度回调</param>
|
||||||
|
/// <returns>文件的访问 URL</returns>
|
||||||
|
public async Task<string> MultipartUploadAsync(string objectName, Stream stream, EventHandler<StreamTransferProgressArgs> progressCallback = null)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行分片上传操作。");
|
||||||
|
|
||||||
|
return await _retryPolicy.ExecuteAsync(async () =>
|
||||||
|
{
|
||||||
|
return await Task.Run(() =>
|
||||||
|
{
|
||||||
|
var request = new InitiateMultipartUploadRequest(_options.Bucket, objectName);
|
||||||
|
var result = _ossClient.InitiateMultipartUpload(request);
|
||||||
|
var uploadId = result.UploadId;
|
||||||
|
var partETags = new List<PartETag>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long partSize = 5 * 1024 * 1024; // 5MB 分片
|
||||||
|
long fileSize = stream.Length;
|
||||||
|
int partCount = (int)(fileSize / partSize);
|
||||||
|
if (fileSize % partSize != 0)
|
||||||
|
{
|
||||||
|
partCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
long transferredBytes = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < partCount; i++)
|
||||||
|
{
|
||||||
|
long skipBytes = partSize * i;
|
||||||
|
stream.Position = skipBytes;
|
||||||
|
long size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
|
||||||
|
|
||||||
|
var uploadPartRequest = new UploadPartRequest(_options.Bucket, objectName, uploadId)
|
||||||
|
{
|
||||||
|
InputStream = stream,
|
||||||
|
PartSize = size,
|
||||||
|
PartNumber = i + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// 每次上传进度回调(简化版:完成一个分片后触发)
|
||||||
|
uploadPartRequest.StreamTransferProgress += (sender, args) =>
|
||||||
|
{
|
||||||
|
transferredBytes += args.TransferredBytes;
|
||||||
|
progressCallback?.Invoke(this, new StreamTransferProgressArgs(transferredBytes, fileSize));
|
||||||
|
};
|
||||||
|
|
||||||
|
var uploadPartResult = _ossClient.UploadPart(uploadPartRequest);
|
||||||
|
partETags.Add(uploadPartResult.PartETag);
|
||||||
|
}
|
||||||
|
|
||||||
|
var completeRequest = new CompleteMultipartUploadRequest(_options.Bucket, objectName, uploadId);
|
||||||
|
foreach (var partETag in partETags)
|
||||||
|
{
|
||||||
|
completeRequest.PartETags.Add(partETag);
|
||||||
|
}
|
||||||
|
_ossClient.CompleteMultipartUpload(completeRequest);
|
||||||
|
|
||||||
|
return GetFullUrl(objectName);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var abortRequest = new AbortMultipartUploadRequest(_options.Bucket, objectName, uploadId);
|
||||||
|
_ossClient.AbortMultipartUpload(abortRequest);
|
||||||
|
_logger.LogError(ex, "分片上传失败,已取消上传。");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取文件流
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
/// <returns>下载文件的内容数据流</returns>
|
||||||
|
public Stream GetObject(string objectName)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行下载操作。");
|
||||||
|
|
||||||
|
var ossObject = _ossClient.GetObject(_options.Bucket, objectName);
|
||||||
|
return ossObject.Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
public void DeleteObject(string objectName)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行删除操作。");
|
||||||
|
|
||||||
|
_ossClient.DeleteObject(_options.Bucket, objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查文件是否存在
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
/// <returns>如果文件存在返回 true,否则返回 false</returns>
|
||||||
|
public bool DoesObjectExist(string objectName)
|
||||||
|
{
|
||||||
|
if (!_options.Enable)
|
||||||
|
throw new InvalidOperationException("OSS未启用,无法执行查询操作。");
|
||||||
|
|
||||||
|
return _ossClient.DoesObjectExist(_options.Bucket, objectName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace YD_Event.Core.Infrastructure.Aliyun.Oss;
|
||||||
|
|
||||||
|
public class StreamTransferProgressArgs : EventArgs
|
||||||
|
{
|
||||||
|
public long TransferredBytes { get; }
|
||||||
|
public long TotalBytes { get; }
|
||||||
|
|
||||||
|
public StreamTransferProgressArgs(long transferredBytes, long totalBytes)
|
||||||
|
{
|
||||||
|
TransferredBytes = transferredBytes;
|
||||||
|
TotalBytes = totalBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,33 @@
|
|||||||
using Furion.ConfigurableOptions;
|
using Furion.ConfigurableOptions;
|
||||||
using OnceMi.AspNetCore.OSS;
|
|
||||||
|
|
||||||
namespace YD_Event.Core.Options;
|
namespace YD_Event.Core.Options;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象存储连接配置
|
/// 对象存储连接配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class OssConnectionOptions : OSSOptions, IConfigurableOptions
|
public sealed class OssConnectionOptions : IConfigurableOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认存目录
|
/// 是否启用对象存储(不启用将存储至站点目录)
|
||||||
|
/// </summary>
|
||||||
|
public bool Enable { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OSS节点
|
||||||
|
/// </summary>
|
||||||
|
public string Endpoint { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AccessKeyId
|
||||||
|
/// </summary>
|
||||||
|
public string AccessKeyId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AccessKeySecret
|
||||||
|
/// </summary>
|
||||||
|
public string AccessKeySecret { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认存目录 (Bucket)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Bucket { get; set; }
|
public string Bucket { get; set; }
|
||||||
|
|
||||||
@ -16,9 +35,4 @@ public sealed class OssConnectionOptions : OSSOptions, IConfigurableOptions
|
|||||||
/// 外网访问域名或IP
|
/// 外网访问域名或IP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Domain { get; set; }
|
public string Domain { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否启用对象存储(不启用将存储至站点目录)
|
|
||||||
/// </summary>
|
|
||||||
public bool Enable { get; set; }
|
|
||||||
}
|
}
|
||||||
@ -10,6 +10,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.3.0" />
|
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.3.0" />
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Ocr20191230" Version="4.0.2" />
|
<PackageReference Include="AlibabaCloud.SDK.Ocr20191230" Version="4.0.2" />
|
||||||
|
<PackageReference Include="Aliyun.OSS.SDK.Core" Version="2.5.3" />
|
||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="EasyCaching.CSRedis" Version="1.9.2" />
|
<PackageReference Include="EasyCaching.CSRedis" Version="1.9.2" />
|
||||||
<PackageReference Include="EasyCaching.InMemory" Version="1.9.2" />
|
<PackageReference Include="EasyCaching.InMemory" Version="1.9.2" />
|
||||||
@ -21,7 +22,6 @@
|
|||||||
<PackageReference Include="log4net" Version="3.2.0" />
|
<PackageReference Include="log4net" Version="3.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.5" />
|
||||||
<PackageReference Include="MrHuo.OAuth.QQ" Version="1.1.1" />
|
<PackageReference Include="MrHuo.OAuth.QQ" Version="1.1.1" />
|
||||||
<PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.2.0" />
|
|
||||||
<PackageReference Include="Polly" Version="8.6.6" />
|
<PackageReference Include="Polly" Version="8.6.6" />
|
||||||
<PackageReference Include="QuestPDF" Version="2025.12.1" />
|
<PackageReference Include="QuestPDF" Version="2025.12.1" />
|
||||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||||
|
|||||||
@ -4377,6 +4377,56 @@
|
|||||||
<param name="imageUrl">图片URL</param>
|
<param name="imageUrl">图片URL</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.GetFullUrl(System.String)">
|
||||||
|
<summary>
|
||||||
|
获取完整的URL
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.PutObject(System.String,System.IO.Stream)">
|
||||||
|
<summary>
|
||||||
|
同步上传文件流
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
<param name="stream">文件数据流</param>
|
||||||
|
<returns>文件的访问 URL</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.PutObjectAsync(System.String,System.IO.Stream)">
|
||||||
|
<summary>
|
||||||
|
异步上传文件流
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
<param name="stream">文件数据流</param>
|
||||||
|
<returns>文件的访问 URL</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.MultipartUploadAsync(System.String,System.IO.Stream,System.EventHandler{YD_Event.Core.Infrastructure.Aliyun.Oss.StreamTransferProgressArgs})">
|
||||||
|
<summary>
|
||||||
|
异步分片上传大文件
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
<param name="stream">文件数据流</param>
|
||||||
|
<param name="progressCallback">进度回调</param>
|
||||||
|
<returns>文件的访问 URL</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.GetObject(System.String)">
|
||||||
|
<summary>
|
||||||
|
获取文件流
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
<returns>下载文件的内容数据流</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.DeleteObject(System.String)">
|
||||||
|
<summary>
|
||||||
|
删除文件
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Infrastructure.Aliyun.Oss.OssService.DoesObjectExist(System.String)">
|
||||||
|
<summary>
|
||||||
|
检查文件是否存在
|
||||||
|
</summary>
|
||||||
|
<param name="objectName">OSS 中的目标文件路径</param>
|
||||||
|
<returns>如果文件存在返回 true,否则返回 false</returns>
|
||||||
|
</member>
|
||||||
<member name="T:YD_Event.Core.Infrastructure.Aliyun.Sms.AliyunSmsService">
|
<member name="T:YD_Event.Core.Infrastructure.Aliyun.Sms.AliyunSmsService">
|
||||||
<summary>
|
<summary>
|
||||||
阿里云短信服务实现
|
阿里云短信服务实现
|
||||||
@ -4471,9 +4521,29 @@
|
|||||||
对象存储连接配置
|
对象存储连接配置
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Enable">
|
||||||
|
<summary>
|
||||||
|
是否启用对象存储(不启用将存储至站点目录)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Endpoint">
|
||||||
|
<summary>
|
||||||
|
OSS节点
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.AccessKeyId">
|
||||||
|
<summary>
|
||||||
|
AccessKeyId
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.AccessKeySecret">
|
||||||
|
<summary>
|
||||||
|
AccessKeySecret
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Bucket">
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Bucket">
|
||||||
<summary>
|
<summary>
|
||||||
默认存目录
|
默认存目录 (Bucket)
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Domain">
|
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Domain">
|
||||||
@ -4481,11 +4551,6 @@
|
|||||||
外网访问域名或IP
|
外网访问域名或IP
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:YD_Event.Core.Options.OssConnectionOptions.Enable">
|
|
||||||
<summary>
|
|
||||||
是否启用对象存储(不启用将存储至站点目录)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:YD_Event.Core.Options.SmsOptions">
|
<member name="T:YD_Event.Core.Options.SmsOptions">
|
||||||
<summary>
|
<summary>
|
||||||
短信配置选项
|
短信配置选项
|
||||||
|
|||||||
@ -20,7 +20,6 @@ using Mapster;
|
|||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using MrHuo.OAuth;
|
using MrHuo.OAuth;
|
||||||
using MrHuo.OAuth.QQ;
|
using MrHuo.OAuth.QQ;
|
||||||
using OnceMi.AspNetCore.OSS;
|
|
||||||
using QuestPDF;
|
using QuestPDF;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
@ -138,12 +137,6 @@ public class Startup : AppStartup
|
|||||||
//模板引擎 文档:https://furion.baiqian.ltd/docs/view-engine
|
//模板引擎 文档:https://furion.baiqian.ltd/docs/view-engine
|
||||||
services.AddViewEngine();
|
services.AddViewEngine();
|
||||||
|
|
||||||
// OSS文档:https://github.com/oncemi/OnceMi.AspNetCore.OSS
|
|
||||||
var ossOptions = App.GetConfig<OssConnectionOptions>("OssConnection");
|
|
||||||
services.AddOSSService(options =>
|
|
||||||
{
|
|
||||||
ossOptions.Adapt(options);
|
|
||||||
});
|
|
||||||
var auth = new QQOAuth(OAuthConfig.LoadFrom(App.Configuration, "oauth:qq"));
|
var auth = new QQOAuth(OAuthConfig.LoadFrom(App.Configuration, "oauth:qq"));
|
||||||
services.AddSingleton(auth);
|
services.AddSingleton(auth);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user