[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結構來做存儲的。
1.5、封裝一個RedisHelper來統一操作Redis,這樣若是後期修改了組件也不需要修改太多的程式碼。如下圖,
修改UserAppServices中的方法如下:
調試後,效果與原來的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("//api.weixin.qq.com"));
然後我們在UserAppServices隨便找個方法調用一下,試試效果如下則表示我調用的返回是正常的。由於我使用的appid是錯誤的導致的。