天天看點

[Abp vNext 入坑分享] - 8.Redis與Refit的接入

前言

本章結束之後,這個abp vnext系列算是初步完結了,基礎的元件都已經接入了。如果各位還需要其它的元件的話,可以自己按需要進行接入使用。其實這個隻是一個基礎的架構,可以自己根據需要進行變通的。比如:如果沒有太多需求且更熟悉三層的同學可以把application和application.contract去掉就是一個三層架構了。基礎是基礎,用好還是要看各位對業務的了解是否夠深入才能發揮好架構的作用。

對于各個架構的使用,建議是:先使用起來,然後熟悉它,再然後改造它。并不是按照别人的标準一味的照抄,每一個架構都會有相應的痛點。。是以在使用的時候是要根據項目與團隊來進行評估是否适用,若不适用的時候,如何去調整。這個不僅僅是架構師要考慮的事情。

個人經驗(僅作參考):建議每一位有想法開發人員都要保持自己的獨立思考能力,無論是針對業務還是技術。但是前期是先積累技術自己驗證,多在群裡友好交流,不說教隻分析。先從大量的文章和部落格中擷取知識,理出自己需要的進行沉澱。到了一定地步(這個一定地步隻能看感覺,這種感覺會非常的明顯,需要自己保持反思,相當于比較大的坎,越過之後就是新的開始的這種)之後,再配合一些好的收費課程和書籍去深入和系統化的學習。比如:曾經我就在群裡看到一個大佬的分享然後開始入門算法,當時他分享的是hash算法,後面我有把它很白話的用場景分享給前端朋友,他也才發現原來還能這麼玩。有需要的話,可以在評論區留言,我看下是否需要找個時間整理出來,可能時間會比較長一點。。

簡要說明

【項目源碼】

【章節目錄】

本文主要介紹如何在abp vnext中使用redis和httpclient。

首先Redis是目前應用最廣泛的分布式緩存方案,這個就不進行更多的介紹了。而我們利用的元件是Microsoft.Extensions.Caching.StackExchangeRedis。此元件也是依賴于StackExchange.Redis,本文直接使用IDistributedCache來做字元的緩存,目前此接口主要是支援string與byte[]的操作,是以緩存實體也是通過序列化成字元串來進行緩存。若有更進一步的類型緩存需要的同學則可以通過StackExchange.Redis的方法來操作如:zset,list,hash等類型,這裡就不作過多介紹了。到時候看情況,如果真的有很多人回報需要的話,我再寫下怎麼比較完整的接入StackExchange.Redis吧!

其次是httpclient,由于我們的系統經常會請求到各位外部的接口。是以這個的引入也是非常重要的。我們使用來管理的元件是Refit.HttpClientFactory。通過Refit.HttpClientFactory,我們可以使用接口與注解的方式來請求外部接口。管理起來非常友善,同時此元件也是通過HttpClientFactory來管理的,并不需要我們作過多的優化。

具體步驟

1.1、首先我們需要知道的是,我們的Redis是主要是在Application層才會需要使用的。是以,原來Host裡面的引入的Redis相關元件可以删除了。定位到AbpVnext.Learn.HttpApi.Host把Microsoft.Extensions.Caching.StackExchangeRedis,Microsoft.AspNetCore.DataProtection.StackExchangeRedis解除安裝掉。同時删除掉Host中的Module的相關代碼。

1.2、然後我們定位到AbpVnext.Learn.Domain層安裝我們需要的nuget包Microsoft.Extensions.Caching.StackExchangeRedis。定位到LearnDomainModule,增加以下代碼用于注入IDistributedCache的Redis服務:

public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var configuration = context.Services.GetConfiguration();
            context.Services.AddStackExchangeRedisCache(options =>
            {
                options.Configuration = configuration["Redis:Configuration"];
            });
        }
           

1.3、然後我們在UserAppServices中使用IDistributedCache去操作緩存,如下:

public async Task<UserDto> get_userbyuserid(Guid userid)
        {
            var cachekey = $"user_{userid.ToString()}";
            var userdto_str =await _distributedCache.GetStringAsync(cachekey);
            if (String.IsNullOrEmpty(userdto_str))
            {
                var usermodel = await _repository.get_userinfo(userid);
                if (usermodel != null)
                {
                    var userdto = new UserDto() { Id = usermodel.Id, user_status = usermodel.user_status, user_name = usermodel.user_name, user_phone = usermodel.user_phone };
                    await _distributedCache.SetStringAsync(cachekey, Newtonsoft.Json.JsonConvert.SerializeObject(userdto));
                    return userdto;
                }
            }
            else
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<UserDto>(userdto_str);
            }
   return null;
    }
           

1.4、修改UserAppServices中的get_userbyuserid方法如下:

public async Task<UserDto> get_userbyuserid(Guid userid)
        {
            var cachekey = $"user_{userid.ToString()}";
            var userdto_str =await _distributedCache.GetStringAsync(cachekey);
            if (String.IsNullOrEmpty(userdto_str))
            {
                var usermodel = await _repository.get_userinfo(userid);
                if (usermodel != null)
                {
                    var userdto = new UserDto() { Id = usermodel.Id, user_status = usermodel.user_status, user_name = usermodel.user_name, user_phone = usermodel.user_phone };
                    await _distributedCache.SetStringAsync(cachekey, Newtonsoft.Json.JsonConvert.SerializeObject(userdto));
                    return userdto;
                }
            }
            else
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<UserDto>(userdto_str);
            }
           return null;
        }
           

然後調試項目,調用init接口,檢視Redis如下:

我們可以看到,IDistributedCache的調用String操作到了Redis裡面是使用的hash結構來做存儲的。

[Abp vNext 入坑分享] - 8.Redis與Refit的接入

1.5、封裝一個RedisHelper來統一操作Redis,這樣若是後期修改了元件也不需要修改太多的代碼。如下圖,

[Abp vNext 入坑分享] - 8.Redis與Refit的接入

修改UserAppServices中的方法如下:

[Abp vNext 入坑分享] - 8.Redis與Refit的接入

調試後,效果與原來的redis一緻。

2.1、接下來我們來接入Refit.HttpClientFactory,其實我們的httpclient也是在Application層才使用的。是以我們也是在Domain層進行接入。Refit的接入的話,建議是為每一個不同的外部請求的根域名定義一個接口。然後再引入,這是因為Refit注入是需要server的。下面我們拿一個微信的Api接口來做為入門例子。

2.2、首先定義IWechatApi接口加入以下代碼:

//擷取微信公衆号的access_token
        [Get("/cgi-bin/token")]
        Task<WechatAccessTokenModel> get_accesstoken(string appid, string secret, string grant_type = "client_credential");
           

在Dommain.Shared中補充好需要的WechatAccessTokenModel。對應的是微信公衆号接口傳回的字段。access_token,expires_in,一般我會定義一個BaseWechatModel用于接收errcode,errmsg。如下

public class BaseWechatModel
    {
        //錯誤時微信會傳回錯誤碼
        public int errcode { get; set; }
        //錯誤資訊
        public string errmsg { get; set; }
    }
 //微信擷取Access_Token的模型
    public class WechatAccessTokenModel: BaseWechatModel
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
    }
           

2.3、接下來我們回到LearnDomainModule中,注入IWechatApi如下:

context.Services.AddRefitClient<IWechatApi>().ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.weixin.qq.com"));
           

然後我們在UserAppServices随便找個方法調用一下,試試效果如下則表示我調用的傳回是正常的。由于我使用的appid是錯誤的導緻的。

[Abp vNext 入坑分享] - 8.Redis與Refit的接入