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
相关文章
|
C语言 C++
【C语言】rand()函数(如何生成指定范围随机数)
【C语言】rand()函数(如何生成指定范围随机数)
1124 0
|
JSON API PHP
天气预报免费API接口【地址查询版】使用教程
本文介绍了如何使用中国气象局官方数据提供的免费天气预报API接口,通过省份和地点查询指定地区当日天气信息。该接口由接口盒子支持,提供JSON格式数据、GET/POST请求方式,并需注册获取用户ID和KEY进行身份验证。
6616 2
|
JSON 数据可视化 API
GraphRAG+Ollama,构建本地精准全局问答系统!
RAG 是目前大语言模型相关最知名的工具之一,从外部知识库中检索事实,以便为大型语言模型 (LLM) 提供最准确、最新的信息。
|
SQL 开发框架 关系型数据库
不会使用 EF Core 的 Code First 模式?来看看这篇文章,手把手地教你
不会使用 EF Core 的 Code First 模式?来看看这篇文章,手把手地教你
1547 0
|
存储 人工智能 关系型数据库
向量数据库和嵌入模型
本文介绍了向量数据库和嵌入模型的概念及应用,重点探讨了两者在AI技术栈中的协作关系。向量数据库是一种用于存储高维向量数据的解决方案,支持相似性搜索而非传统的关系型数据库精确匹配。文中通过实例展示了如何使用阿里百炼的文本嵌入模型(text-embedding-v3)将文本向量化,并结合Qdrant向量数据库进行存储与检索。代码示例部分详细说明了从文本嵌入到向量存储及查询的完整流程,为开发者提供了实践参考。
2326 15
向量数据库和嵌入模型
|
人工智能 自然语言处理 算法
【Gemini怎么使用】:Gemini 2.0 国内使用指南
人工智能领域风起云涌,Google 凭借其 Gemini AI 模型的迭代升级,持续引领着技术革新的浪潮。特别是 Gemini 2.0 的发布,标志着 AI 发展进入了一个全新的阶段
8805 14
|
数据采集 JSON 数据可视化
基于Python的51job招聘数据采集与可视化项目实践
本文介绍了一个基于Python的51job招聘数据采集与可视化项目,该项目通过自动化手段获取大量招聘信息,并运用数据分析和可视化工具对就业市场进行深度分析,旨在为求职者和企业提供数据支持和决策依据。
1195 5
|
自然语言处理 搜索推荐 Docker
CosyVoice实现声音复刻
这篇文章介绍了如何使用CosyVoice平台实现个性化的声音复刻,包括录制样本音频、上传处理以及生成定制化语音的全流程。
3619 6
CosyVoice实现声音复刻