概念
集成阿里云OSS文件存储服务
引用阿里云包
封装AliyunSmsClient(二次封装阿里云短信基类)
public class AliyunOssClient{private readonly AliyunOssOptions _options;private readonly OssClient _client;public AliyunOssClient(IOptions<AliyunOssOptions> options){_options = options.Value;_client = new OssClient(_options.EndPoint, _options.AccessKeyId, _options.AccessKeySecret);}/// <summary>/// 推送文件/// </summary>/// <param name="formFile"></param>/// <returns></returns>public async Task<string> UpFileAsync(IFormFile formFile){return await Task.Run(() =>{var path = _options.ProjectName + "/" + _options.ServiceName + "/";path += IdGenerator.NextId() + "/";path+= formFile.FileName;try{// 计算MD5。string md5;var stream = formFile.OpenReadStream();md5 = OssUtils.ComputeContentMd5(stream, stream.Length);var objectMeta = new ObjectMetadata{ContentMd5 = md5};_client.PutObject(_options.BucketName, path, stream, objectMeta);Console.WriteLine("Put object succeeded");}catch (OssException ex){Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);}catch (Exception ex){Console.WriteLine("Failed with error info: {0}", ex.Message);}return Task.FromResult(path);});}/// <summary>/// 获取文件流/// </summary>/// <param name="key"></param>/// <returns></returns>public async Task<Stream> GetStreamAsync(string key){return await Task.Run(() =>{return _client.GetObject(_options.BucketName, key).Content;});}#region 获取字节数组/// <summary>/// 获取字节数组/// </summary>/// <param name="key"></param>/// <returns></returns>public async Task<byte[]> GetBytesAsync(string key){using (var sm = await GetStreamAsync(key)){var buf = new byte[1024];var ms = new MemoryStream();var len = 0;while ((len = sm.Read(buf, 0, 1024)) != 0){ms.Write(buf, 0, len);}ms.Position = 0;return ms.ToArray();}}#endregion#region 获取文件基本信息/// <summary>/// 获取文件基本信息/// </summary>/// <param name="key"></param>/// <returns></returns>public async Task<ObjectMetadata> GetMetadataAsync(string key){return await Task.Run(() =>{return _client.GetObjectMetadata(_options.BucketName, key);});}#endregion#region 获取预签名地址/// <summary>/// 获取预签名地址/// </summary>/// <param name="key"></param>/// <param name="expirationMinutes"></param>/// <returns></returns>public async Task<string> GetPresignedUriAsync(string key, int? expirationMinutes = null){return await Task.Run(() =>{return _client.GeneratePresignedUri(new GeneratePresignedUriRequest(_options.BucketName, key, SignHttpMethod.Get){Expiration = DateTime.Now.AddMinutes(expirationMinutes != null && expirationMinutes.Value > 0 ? expirationMinutes.Value : _options.PresignedUriExpirationMinutes)}).AbsoluteUri;});}#endregion#region 获取网页Post直传签名策略/// <summary>/// 获取网页Post直传签名策略/// https://help.aliyun.com/document_detail/31988.htm?spm=a2c4g.11186623.2.34.76e8295fUDcbJN#title-5go-s2f-dnw/// </summary>/// <param name="directory"></param>/// <returns></returns>public async Task<AliyunOssPostPolicyResponse> GeneratePostPolicyAsync(string directory){return await Task.Run(() =>{directory = directory.Replace("//", "/").Replace("\\", "/");directory = directory.EndsWith("/") ? directory : directory + "/";var policyConds = new PolicyConditions();policyConds.AddConditionItem("bucket", _options.BucketName);policyConds.AddConditionItem(MatchMode.StartWith, PolicyConditions.CondKey, directory);policyConds.AddConditionItem(PolicyConditions.CondContentLengthRange, 1, int.MaxValue);var policy = _client.GeneratePostPolicy(DateTime.Now.AddMinutes(_options.PolicyExpirationMinutes), policyConds);var encPolicy = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy));using (var algorithm = KeyedHashAlgorithm.Create("HmacSHA1".ToUpperInvariant())){algorithm.Key = Encoding.UTF8.GetBytes(_options.AccessKeySecret.ToCharArray());var signature = Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(encPolicy.ToCharArray())));return new AliyunOssPostPolicyResponse{Key = directory + "${filename}",OssAccessKeyId = _options.AccessKeyId,Policy = encPolicy,Signature = signature,Success_Action_Status = "200",Host = BuildRequestUri(_options.EndPoint, _options.BucketName)};};});}#endregionprivate static string BuildRequestUri(string endpoint, string bucketName){var requestUriBuilder = new StringBuilder();if (endpoint.StartsWith("http://")){requestUriBuilder.Append("http://");requestUriBuilder.Append(bucketName);requestUriBuilder.Append('.');requestUriBuilder.Append(endpoint.Substring("http://".Length));}else if (endpoint.StartsWith("https://")){requestUriBuilder.Append("https://");requestUriBuilder.Append(bucketName);requestUriBuilder.Append('.');requestUriBuilder.Append(endpoint.Substring("https://".Length));}else{requestUriBuilder.Append("http://");requestUriBuilder.Append(bucketName);requestUriBuilder.Append('.');requestUriBuilder.Append(endpoint);}return requestUriBuilder.ToString();}}
封装参数构造类AliyunSmsSendRequestBuilder
public class AliyunSmsSendRequestBuilder{private readonly SendSmsRequest _request;private readonly List<string> _phones;private readonly Dictionary<string, object> _templateParams;public AliyunSmsSendRequestBuilder(string templateCode){_request = new SendSmsRequest();_request.TemplateCode = templateCode;_phones = new List<string>();_templateParams = new Dictionary<string, object>();}public AliyunSmsSendRequestBuilder AddPhone(IEnumerable<string> phones) => AddPhone(phones.ToArray());public AliyunSmsSendRequestBuilder AddPhone(params string[] phones){_phones.AddRange(phones);return this;}public AliyunSmsSendRequestBuilder AddSignName( string signName){_request.SignName = signName;return this;} public AliyunSmsSendRequestBuilder AddTemplateParam(string key, object value){_templateParams.Add(key, value);return this;}public SendSmsRequest Build(){_request.PhoneNumbers = string.Join(",", _phones.Distinct());_request.TemplateParam = JsonConvert.SerializeObject(_templateParams as dynamic);return _request;}}
封装初始化参数类AliyunSmsOptions
public class AliyunSmsOptions{public string AccessKeyId { get; set; }public string AccessKeySecret { get; set; }public string SignName { get; set; }}
封装服务扩展静态类ServiceCollectionExtensions
public static class ServiceCollectionExtensions{public static IServiceCollection AddAliyunSms(this IServiceCollection services, Action<AliyunSmsOptions> setup){services.Configure(setup);services.AddSingleton<AliyunSmsClient>();return services;}}
项目打包推送至nuget仓库
打包传送门 https://www.cnblogs.com/inclme/p/16053978.html
.net6中使用
引用上述nuget包
添加扩展服务
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAliyunSms((op) =>
{builder.Configuration.Bind("BPA:AliyunSms", op);
});
参数参考
"AliyunSms": {"AccessKeyId": "参考Key","AccessKeySecret": "参考Secret","SignName": "参考"},
封装接口
public class AliyunOssGeneratePostPolicyRequest{/// <summary>/// 根目录/// </summary>[DisplayName("根目录")][Required(ErrorMessage = "[{0}] 不能为空")]public string Directory { get; set; }/// <summary>/// 是否构建唯一目录/// </summary>public bool BuildUniqueDirectory { get; set; }}
/// <summary>/// 构建网页Post直传策略/// </summary>/// <param name="request"></param>/// <returns></returns>[HttpPost][Route("GeneratePostPolicy")]public async Task<AliyunOssPostPolicyResponse> GeneratePostPolicyAsync(AliyunOssGeneratePostPolicyRequest request){var dir = request.Directory;dir = request.BuildUniqueDirectory ? $"{request.Directory}{(request.Directory.EndsWith("/") ? "" : "/")}{DateTime.Now.ToString("yyyyMMdd")}/{IdGenerator.NextId()}/" : dir;dir = !dir.EndsWith("/") ? dir + "/" : dir;var data =await _aliyunOssClient.GeneratePostPolicyAsync(dir);return data;}
前端使用
async uploadData(params) {const res = await this.$api.games.upload({directory: "good",buildUniqueDirectory: true});if (res.code != 200) {uni.showToast({title: "文件保存失败",icon: 'none'});}var formData = new FormData(); //注意formData里append添加的键的大小写formData.append("name", params.name); //文件名formData.append("key", res.content.key); //存储在oss的文件路径formData.append("ossAccessKeyId", res.content.ossAccessKeyId); //accessKeyIdformData.append("policy", res.content.policy); //policyformData.append("signature", res.content.signature); //签名 //如果是base64文件,那么直接把base64字符串转成blob对象进行上传就可以了formData.append("file", params.file);formData.append("success_Action_Status", 200); //成功后返回的操作码formData.append("host", res.content.host);var fileUrl = "";let _this = this;await $.ajax({url: res.content.host,type: "POST",data: formData,cache: false,contentType: false,processData: false,success: function(data) {_this.imageValue.push({url: res.content.host +"/" +res.content.key.replace("${filename}", params.name),//extname: params.extname,name: params.name})},error: function(data) {console.log(data);}});},