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的缓存和持久化能力;引申出对有状态应用(集群)配置会话亲和性。


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

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
6月前
|
存储 JSON API
如何将 Swagger 文档导出为 PDF 文件
你会发现自己可能需要将 Swagger 文档导出为 PDF 或文件,以便于共享和存档。在这篇博文中,我们将指导你完成将 Swagger 文档导出为 PDF 格式的过程。
|
11月前
|
JSON 开发框架 自然语言处理
Abp源码分析之Abp本地化
本文介绍了如何在 ASP.NET Core MVC 项目中实现本地化功能,包括使用资源文件和 JSON 文件两种方式。首先,通过修改 `Program.cs` 配置支持的多语言环境,并创建相应的资源文件目录。接着,展示了如何在视图中使用本地化字符串。此外,还介绍了使用 ABP 框架实现本地化的具体步骤,包括新建模块、配置服务和创建资源文件。最后,通过源码分析详细解释了本地化机制的实现原理。
211 0
Abp源码分析之Abp本地化
|
11月前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
131 1
vue学习第十章(组件开发)
|
10月前
|
人工智能 小程序 程序员
我的 2024 年终总结,持续尝试
复盘一下今年做过的所有关于探索收入多样性的事情。包括这一年工作以外的 “工作进展”,收获的事项,遇到的种种问题,以及来年的计划等,最后希望能对大家有一点点参考意义。
169 2
|
12月前
|
存储 关系型数据库 MySQL
MySQL 字符字段长度设置详解:语法、注意事项和示例
MySQL 字符字段长度设置详解:语法、注意事项和示例
940 0
|
网络协议 关系型数据库 Linux
PostGresql数据库Linux服务器安装
PostGresql数据库,Linux服务器,在线,离线安装
4377 2
PostGresql数据库Linux服务器安装
|
存储 关系型数据库 MySQL
MySQL | 数据库的表的增删改查【进阶】【万字详解】(一)
MySQL | 数据库的表的增删改查【进阶】【万字详解】(一)
|
数据安全/隐私保护 Windows
全网最新超详细的【Axure】Axure RP 10的下载、安装、中文字体、授权【2023年】
全网最新超详细的【Axure】Axure RP 10的下载、安装、中文字体、授权【2023年】
1768 0
全网最新超详细的【Axure】Axure RP 10的下载、安装、中文字体、授权【2023年】
|
移动开发 小程序 JavaScript
微信小程序转uniapp的迁移步骤及遇到的问题
微信小程序转uniapp的迁移步骤及遇到的问题
776 0
微信小程序转uniapp的迁移步骤及遇到的问题