图片上传是很常见的功能,里面有些固定的操作也可以沉淀下来。

本文记录使用Abp vNext做图片上传的姿势。

本文的技术核心与Abp无关,Abp只是手段!

目标

  1. 上传图片----->预览图片----->确定保存
  2. 支持集群部署

实现思路:

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

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

③ 前端利用FileReader渲染预览图;

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

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

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

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

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

实践

利用Abp做图片上传

IFormFile能力如下红框:

下面将图片二进制流转化为 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.NETCore官方文档:

  1. Abp默认的IDistributedCache实现是分布式内存缓存;
  2. 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托管服务,具备多实例自动缩放的能力,

其有关会话亲和性的配置如图:

3. K8S nginx-ingress

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

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

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

That's All

本文以常见的图片上传功能为例,实战演练了Abp的缓存和持久化能力;

引申出对有状态应用配置会话亲和性,部署方式要结合业务功能。

希望对大家有所帮助!

Abp小试牛刀之 图片上传的更多相关文章

  1. Asp.Net Mvc 使用WebUploader 多图片上传

    来博客园有一个月了,哈哈.在这里学到了很多东西.今天也来试着分享一下学到的东西.希望能和大家做朋友共同进步. 最近由于项目需要上传多张图片,对于我这只菜鸟来说,以前上传图片都是直接拖得控件啊,而且还是 ...

  2. 06.LoT.UI 前后台通用框架分解系列之——浮夸的图片上传

    LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...

  3. JS图片上传预览插件制作(兼容到IE6)

    其实,图片预览功能非常地常见.很意外,之前遇到上传图片的时候都不需要预览,也一直没有去实现过.现在手上的项目又需要有图片预览功能,所以就动手做了一个小插件.在此分享一下思路. 一.实现图片预览的一些方 ...

  4. HTML5笔记:跨域通讯、多线程、本地存储和多图片上传技术

    最近做项目在前端我使用了很多新技术,这些技术有bootstrap.angularjs,不过最让我兴奋的还是使用了HTML5的技术,今天我想总结一些HTML5的技术,好记性不如烂笔头,写写文章可以很好的 ...

  5. 对百度的UEditor多图片上传的一些补充

    我已经写了一篇文章关于百度的UEditor提取多图片上传模块.如果还没有看过,请点击以下链接查看 http://www.cnblogs.com/luke1006/p/3719029.html 出差了两 ...

  6. 使用localResizeIMG3+WebAPI实现手机端图片上传

    前言 惯例~惯例~昨天发表的使用OWIN作为WebAPI的宿主..嗯..有很多人问..是不是缺少了什么 - - 好吧,如果你要把OWIN寄宿在其他的地方...代码如下: namespace Conso ...

  7. TinyMCE的使用(包括汉化及本地图片上传功能)

    TinyMCE我就不多介绍了,这是下载地址:https://www.tinymce.com/download/ 下载下来是英文版,要汉化也很简单.首先去网上随便下载个汉化包,然后把汉化包解压后的lan ...

  8. 包含修改字体,图片上传等功能的文本输入框-Bootstrap

    通过jQuery Bootstrap小插件,框任何一个div转换变成一个富文本编辑框,主要特色: 在Mac和window平台下自动针对常用操作绑定热键 可以拖拽插入图片,支持图片上传(也可以获取移动设 ...

  9. PHP多图片上传实例demo

    upload.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...

随机推荐

  1. Java基础教程——Set

    Set·无序,不重复 HashSet 特点:没有重复数据,数据不按存入的顺序输出. HashSet由Hash表结构支持.不支持set的迭代顺序,不保证顺序. 但是Hash表结构查询速度很快. 创建集合 ...

  2. 【不尽如人意的redisTemplete封装】

    线下项目里对spring redisTemplete进行了简单的封装,但是项目里关于其序列化的配置真的有点一言难尽: 可以看到这里用了JdkSerializationRedisSerializer去对 ...

  3. Linux服务器学习----haproxy+keepalived

    实验需要4台虚拟机,两台做服务器,两台做代理服务器 www1:ip:10.30.40.11       hk1: 代理:10.30.40.13(hk1.netdj.net) www2:ip  10.3 ...

  4. 蓝桥杯 调手表(bfs解法)

    小明买了块高端大气上档次的电子手表,他正准备调时间呢. 在 M78 星云,时间的计量单位和地球上不同,M78 星云的一个小时有 n 分钟. 大家都知道,手表只有一个按钮可以把当前的数加一.在调分钟的时 ...

  5. .net core3.1开始页面实时编译

    安装NuGet包 Install-Package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation  startup.cs 中的ConfigureSe ...

  6. ERP费用报销操作与设计--开源软件诞生31

    赤龙ERP费用报销讲解--第31篇 用日志记录"开源软件"的诞生 [进入地址 点亮星星]----祈盼着一个鼓励 博主开源地址: 码云:https://gitee.com/redra ...

  7. 从TFS到git的持续集成之路

    前言 公司目前使用TFS,由于TFS不灵活不能很好的持续集成,且给测试造成很大重的负担,所以近期准备迁移到git上 目标 解决项目运转的瓶颈(版本太多,导致测试跟不上,需引入自动化测试) 过程 主线分 ...

  8. PyQt(Python+Qt)学习随笔:QScrollArea的alignment属性不起作用的原因

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 Scroll Area滚动区域提供了一个呈现在其他部件上的可滚动区域视图,对应类为QScrollAr ...

  9. PyQt(Python+Qt)学习随笔:QTableWidget的属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.概述 除了从父类继承的属性外,在Designer中QTableWidget只有两个属性,就是行数 ...

  10. PyQt(Python+Qt)学习随笔:QTreeWidget的columnCount属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 树型部件中的每个项有一个或多个文字标签或其他装饰符(如图标),这些内容每个显示为一列.QTreeWi ...