Abp小试牛刀之 图片上传

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

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

目标

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

  2. 支持集群部署

实现思路:

1. 上传图片要使用WebAPI特定媒体类型:multipart/form-data;
2. 因为要做图片预览,故在上传时利用AbpCache做一个临时缓存,返回图片Id
3. 前端利用FileReader渲染预览图;
4.  [确定]: 发起持久化WebAPI(利用第2步返回的图片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.NET Core官方文档:

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

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

关注并星标我们
更多干货及最佳实践分享

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
BackgroundJob 是 ABP 框架中的一个重要组件,用于处理后台任务。它可以让我们在后台执行一些长时间运行的任务,如发送邮件、生成报告、备份数据库等。 在 ABP 框架中,BackgroundJob 的实现基于 Hangfire。Hangfire 是一个 .NET 平台下的开源后台任务调度框架,它可以让我们方便地创建、管理和监控后台任务。 ABP 框架对 Hangfire 进行了封装,提供了一些简单易用的 API,使我们可以快速地创建和管理后台任务。下面是一个简单的示例: ```csharp public class MyJob : BackgroundJob<string> { public override async Task ExecuteAsync(string args) { // 执行后台任务的代码 } } public class MyService : ITransientDependency { private readonly IBackgroundJobManager _backgroundJobManager; public MyService(IBackgroundJobManager backgroundJobManager) { _backgroundJobManager = backgroundJobManager; } public async Task QueueJobAsync() { await _backgroundJobManager.EnqueueAsync(new MyJob(), "job args"); } } ``` 在上面的代码中,我们定义了一个名为 MyJob 的后台任务,它继承自 ABP 框架中的 BackgroundJob 类。这个后台任务接受一个字符串类型的参数,在 ExecuteAsync 方法中执行具体的后台任务代码。 接着,我们定义了一个名为 MyService 的服务,它依赖于 IBackgroundJobManager 接口。这个服务中有一个名为 QueueJobAsync 的方法,它使用 _backgroundJobManager.EnqueueAsync 方法将 MyJob 加入到后台任务队列中。 当我们调用 MyService 的 QueueJobAsync 方法时,MyJob 就会被加入到后台任务队列中,并在后台自动执行。我们可以通过 ABP 框架提供的界面来监控后台任务的执行情况,也可以通过代码来实现任务的暂停、恢复、取消等操作。 总之,BackgroundJob 是 ABP 框架中非常实用的一个组件,它可以帮助我们方便地处理后台任务,提高应用程序的性能和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有态度的马甲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值