Abp小试牛刀之 图片上传

简介: 图片上传是很常见的功能,里面有些固定的操作也可以沉淀下来。本文记录使用Abp vNext做图片上传的姿势。

目标


  1. 上传图片----->预览图片----->确定保存


  1. 支持集群部署


5eedebfa56551c257b5fe5d440d17bd6.png


实现思路:


1. 上传图片要使用WebAPI特定媒体类型:multipart/form-data;


2. 因为要做图片预览,故在上传时利用AbpCache做一个临时缓存,返回图片Id


3. 前端利用FileReader渲染预览图;


4.  [确定]: 发起持久化WebAPI(利用第2步返回的图片Id)


为什么强调支持集群部署?


就这个功能而言,[上传预览]和[确定保存]是两次Http WebAPI请求。


如果服务端使用的是Redis等进程外缓存: 那这正好是一个Stateless应用功能,集群环境无惧!


如果服务端使用的是进程内缓存:在集群环境,前后两次请求有可能打到不同的App服务,后置的[确定保存]WebAPI因此可能报错, 此处需要做 [会话亲和性] Session affinity


实践


利用Abp做图片上传


IFormFile能力如下红框:


a3bd999ae35f5224366479dd08ece22c.png


下面将图片二进制流转化为 base64字符串,注入Abp缓存组件IDistributedCache<string>;缓存图片字符串1小时。


[上传预览], [确定保存]的API完整代码如下:


/// <summary>
       /// 上传预览, 返回待上传的图片id,Content-Type:multipart/form-data
       /// </summary>
       /// <returns></returns>
       [Consumes("multipart/form-data")]
       [Route("upload/preview")]
       [ProducesResponseType(typeof(Guid),200)]
       [HttpPost]
       public async Task<Guid> UploadPicPreviewAsync(IFormFile uploadedFile)
       {
           var formFileName = uploadedFile.FileName;
           if (!new[] { ".png", ".jpg", ".bmp" }.Any((item) => formFileName.EndsWith(item)))
           {
               throw new AbpValidationException("您上传的文件格式必须为png、jpg、bmp中的一种");
           }
           byte[] bytes;
           using (var bodyStream = uploadedFile.OpenReadStream())
           {
               using (var m = new MemoryStream())
               {
                   await bodyStream.CopyToAsync(m);
                   bytes = m.ToArray();
               }
           }
           string base64 = Convert.ToBase64String(bytes);
           var bgId = Guid.NewGuid();
           _cache.Set($"{CurrentUser.TenantId}:bg:{bgId}", base64, new DistributedCacheEntryOptions { SlidingExpiration = new TimeSpan(1, 0, 0) });
           return bgId;
       }
       /// <summary>
       /// 保存图片,要使用到前置API的预览图片id
       /// </summary>
       /// <param name="createPictureInput"></param>
       /// <returns></returns>
       [Route("upload/")]
       [HttpPost]
       public async Task<bool> UploadPicAsync([FromBody] CreatePictureInput createPictureInput)
       {
           var based64 = await _cache.GetAsync($"{CurrentUser.TenantId}:bg:{createPictureInput.PreviewPicId}");
           if (string.IsNullOrEmpty(based64))
               throw  new AbpException("Cache Hotmap Picture do not find");
           var model = ObjectMapper.Map<CreatePictureInput, Picture>(createPictureInput);
           model.ProfileId = CurrentUser.TenantId;
           model.BlobStorage = Convert.FromBase64String(based64);
           return await _pictures.InsertAsync(model)!= null;
       }


Default implementation of the IDistributedCache interface is the MemoryDistributedCache which works in-memory.

The Distributed Memory Cache (AddDistributedMemoryCache) is a framework-provided implementation of IDistributedCache that stores items in memory. The Distributed Memory Cache isn't an actual distributed cache. Cached items are stored by the app instance on the server where the app is running.


以上两段文字来自 Abp和ASP.NET Core官方文档:


  1. Abp默认的IDistributedCache实现是分布式内存缓存;


  1. ASP.NETCore 分布式内存缓存是框架内置的,是一个假的分布式缓存,实际是单纯的内存缓存。


在没有使用真实分布式缓存的情况下, 需要对前后两个API配置会话亲和性。


会话亲和性


下面从nginx、Azure、k8s ingress 三角度配置[会话亲和性],(全站生效)  


会话亲和性的实现原理,是在接受客户端首次请求时响应某个cookie,服务器会认定使用同一个cookie的请求为一个会话。


1. nginx


属于nginx负载均衡的范畴:https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/


示例如下:


upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    sticky cookie srv_id expires=1h domain=.example.com path=/;
}

2. Azure App Service


Azure pp Service是Azure云平台提供的App托管服务,具备多实例自动缩放的能力, 其有关会话亲和性的配置如图:


548b7085aeed4217cd2cbeba7bfc1efa.png


3. K8S nginx-ingress


注解nginx.ingress.kubernetes.io/affinity在入口的所有上游中启用和设置亲和性类型。


这样,请求将总是被定向到相同的上游服务器。


https://kubernetes.github.io/ingress-nginx/examples/affinity/cookie/


bfdae82108d91289667a440b4fa555a9.png


That's All


本文以常见的图片上传功能为例,实战演练了Abp的缓存和持久化能力;引申出对有状态应用(集群)配置会话亲和性。


部署配置要结合业务功能,希望对大家有所帮助!

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
4月前
|
存储
若依框架 --- pdf文件上传预览功能实现
若依框架 --- pdf文件上传预览功能实现
163 0
|
4月前
|
对象存储
关于uniapp解决单/多文件上传的解决思路
关于uniapp解决单/多文件上传的解决思路
100 0
|
6月前
|
SQL 开发框架 .NET
CodeSmith 简单使用和常用模板
CodeSmith 简单使用和常用模板
20 0
CodeSmith 简单使用和常用模板
|
JavaScript 索引
WebApi入门第十二章(原生轮播图 )(完结)
WebApi入门第十二章(原生轮播图 )(完结)
93 0
WebApi入门第十二章(原生轮播图 )(完结)
WebApi入门第八章(模拟百度搜索框 )
WebApi入门第八章(模拟百度搜索框 )
55 0
WebApi入门第八章(模拟百度搜索框 )
|
前端开发
前端学习案例-ant design带你封装一个上传图片组件
前端学习案例-ant design带你封装一个上传图片组件
227 0
前端学习案例-ant design带你封装一个上传图片组件
|
JavaScript 前端开发
#yyds干货盘点# 一步步教你用taro封装一个公司库的下拉组件
#yyds干货盘点# 一步步教你用taro封装一个公司库的下拉组件
203 0
|
PHP 编解码
laravel 图片/头像上传通用方法
laravel 图片/头像上传通用方法
1523 0
|
前端开发
巧用 Swagger 在线编辑器生成前端接口代码
Swagger / Open API 在Restful API 领域已慢慢成为标准,越来越多的系统使用swagger来规范开发接口文档,由于Swagger 本身并不依赖特定的语言和开发平台,所以特别合适作为前后端分离的接口标准来使用。
3422 0
|
移动开发 自然语言处理 数据库