贵州做网站公司
贵州做网站公司~专业!靠谱!
10年网站模板开发经验,熟悉国内外开源网站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等网站程序,可为您提供网站建设,网站克隆,仿站,网页设计,网站制作,网站推广优化等服务。我们专注高端营销型网站,企业官网,集团官网,自适应网站,手机网站,网络营销,网站优化,网站服务器环境搭建以及托管运维等。为客户提供一站式网站解决方案!!!

refit(如何在Asp.Net Core中使用Refit)

来源:网络转载 时间:2024-05-08 04:23:01

ASP.NET 是什么

ASP.NET 是开源,跨平台,高性能,轻量级的 Web 应用构建框架,常用于通过 HTML、CSS、JavaScript 以及服务器脚本来构建网页和网站

  一 常规创建方式

  在常规的方式中我们一般使用IHttpClientFactory来创建HttpClient对象,然后使用这个对象来发送和接收消息,至于为什么要使用这个接口来创建HttpClient对象而不是使用using new HttpClient的原因请点击这里了解更多的信息,我们先来看下面的这个例子。

usingSystem;usingSystem.Collections.Generic;usingSystem.componentmodel.DataAnnotations;usingSystem.Net;usingSystem.Net.Http;usingSystem.Net.Http.Headers;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Web;usingAbp.Domain.Services;usingMicrosoft.Extensions.Logging;usingNewtonsoft.Json;namespaceSunlight.Dms.Parts.Domain.Web{///<summary>///HttpClient的帮助类///</summary>publicclassDcsPartClientService:DomainService{privatereadonlyHttpClient_httpClient;privatereadonlyIlogger<DcsPartClientService>_loggerHelper;publicDcsPartClientService(IHttpClientFactoryhttpClientFactory,ILogger<DcsPartClientService>loggerHelper){_loggerHelper=loggerHelper;_httpClient=httpClientFactory.CreateClient(PartsConsts.DcsPartClientName);if(_httpClient.BaseAddress==null){thrownewArgumentNullException(nameof(httpClientFactory),$"没有配置名称为{PartsConsts.DcsPartClientName}的HttpClient,或者接口服务的地址为空");}}///<summary>///Post请求返回实体///</summary>///<paramname="relativeUrl">请求相对路径</param>///<paramname="postObj">请求数据</param>///<returns>实体T</returns>publicasyncTask<List<T>>PostResponse<T>(stringrelativeUrl,objectpostObj)whereT:class{varpostData=JsonConvert.SerializeObject(postObj);_httpClient.DefaultRequestHeaders.Add("user-agent","Dcs-Parts");_httpClient.CancelPendingRequests();_httpClient.DefaultRequestHeaders.Clear();HttpContenthttpContent=newStringContent(postData);httpContent.Headers.ContentType=newMediaTypeHeaderValue("application/json");varresult=default(List<T>);varresponse=await_httpClient.PostAsync(_httpClient.BaseAddress+relativeUrl,httpContent);if(response.StatusCode==HttpStatusCode.NotFound){thrownewValidationException("找不到对应的DcsParts服务");}varresponseContent=awaitresponse.Content.ReadAsAsync<ReceiveResponseBody<List<T>>>();if(response.IsSuccessStatusCode){result=responseContent?.Payload;}else{if(!string.IsNullOrWhiteSpace(responseContent?.Message)){thrownewValidationException(responseContent.Message);}_loggerHelper.LogDebug($"请求返回结果:{0}请求内容:{1}",response.StatusCode,postData);}returnawaitTask.FromResult(result);}publicasyncTask<List<T>>GetResponse<T>(stringrelativeUrl,objectqueryObj)whereT:class{varqueryData=ModelToUriQueryParam(queryObj);_httpClient.DefaultRequestHeaders.Add("user-agent","Dcs-Parts");_httpClient.CancelPendingRequests();_httpClient.DefaultRequestHeaders.Clear();_httpClient.DefaultRequestHeaders.Add("accept","application/json");varresult=default(List<T>);varresponse=await_httpClient.GetAsync(_httpClient.BaseAddress+relativeUrl+queryData);if(response.StatusCode==HttpStatusCode.NotFound){thrownewValidationException("找不到对应的DcsParts服务");}varresponseContent=awaitresponse.Content.ReadAsAsync<ReceiveResponseBody<List<T>>>();if(response.IsSuccessStatusCode){result=responseContent?.Payload;}else{if(!string.IsNullOrWhiteSpace(responseContent?.Message)){thrownewValidationException(responseContent.Message);}}returnawaitTask.FromResult(result);}privatestringModelToUriQueryParam<T>(Tt,stringurl=""){varproperties=t.GetType().GetProperties();varsb=newStringBuilder();sb.Append(url);sb.Append("?");foreach(varpinproperties){varv=p.GetValue(t,null);if(v==null)continue;sb.Append(p.Name);sb.Append("=");sb.Append(HttpUtility.UrlEncode(v.ToString()));sb.Append("&");}sb.Remove(sb.Length-1,1);returnsb.ToString();}}publicclassReceiveResponseBody<T>whereT:class{publicstringMessage{get;set;}publicTPayload{get;set;}}publicclassReceiveResponseBody{publicstringMessage{get;set;}}}

  1.1 注入IHttpClientFactory对象

  在这个过程中我们通过构造函数来注入IHttpClientFactory接口,然后用这个接口的CreateClient方法来创建一个唯一的HttpClient对象,在这里我们一般都会同步注入ILogger接口来记录日志信息从而便于我们排查线上问题,这里我们在CreateClient方法中传入了一个字符串类型的参数用于标记自己创建的HttpClient对象的唯一性。这里我们可以看到在构造函数中我们会去判断当前创建的HttpClient的BaseAddress,如果没有这个基地址那么程序会直接抛出错误提示,那么问题来了我们的HttpClient的BaseAddress到底在哪里配置呢?熟悉Asp.Net Core机制的朋友肯定一下子就会想到在Startup类中配置,那么我们来看看需要怎么配置。

  1.2 配置HttpClient的BaseAddress  

publicIServiceProviderConfigureServices(IServiceCollectionservices){//dcs.part服务services.AddHttpClient(PartsConsts.DcsPartClientName,config=>{config.BaseAddress=newUri(_appConfiguration["DependencyServices:DcsParts"]);config.Timeout=TimeSpan.FromSeconds(60);});}  

  这里我只是简要截取了一小段内容,这里我们看到AddHttpClient的第一个参数也是一个字符串常量,这个常量应该是和IHttpClientFactory的CreateClient的方法中的那个常量保持绝对的一致,只有这样我们才能够标识唯一的标识一个HttpClient对象,创建完了之后我们就能够在这个里面去配置这个HttpClient的各种参数了,另外在上面的这段代码中_appConfiguration这个对象是通过Startup的构造函数注入的,具体的代码请参考下面。

publicStartup(IHostingEnvironmentenv){_appConfiguration=env.GetAppConfiguration();Clock.Provider=ClockProviders.Local;Environment=env;Console.OutputEncoding=System.Text.Encoding.UTF8;}  

  另外我们还需要配置一些HttpClient所必须的属性包括基地址、超时时间......等等,当然这个基地址我们是配置在appsetting.json中的,具体的配置如下所示。

"DependencyServices":{"BlobStorage":"http://blob-storage/","DcsParts":"http://dcs-parts/","DmsAfterSales":"http://dms-after-sales/"}

  有了这些我们就能够具备创建一个HttpClient对象的条件了,后面我们来看看我们怎么使用这个HttpClient进行发送和接收数据。

  1.3 HttpClient进行数据的发送和接收

///<summary>///Post请求返回实体///</summary>///<paramname="relativeUrl">请求相对路径</param>///<paramname="postObj">请求数据</param>///<returns>实体T</returns>publicasyncTask<List<T>>PostResponse<T>(stringrelativeUrl,objectpostObj)whereT:class{varpostData=JsonConvert.SerializeObject(postObj);_httpClient.DefaultRequestHeaders.Add("user-agent","Dcs-Parts");_httpClient.CancelPendingRequests();_httpClient.DefaultRequestHeaders.Clear();HttpContenthttpContent=newStringContent(postData);httpContent.Headers.ContentType=newMediaTypeHeaderValue("application/json");varresult=default(List<T>);varresponse=await_httpClient.PostAsync(_httpClient.BaseAddress+relativeUrl,httpContent);if(response.StatusCode==HttpStatusCode.NotFound){thrownewValidationException("找不到对应的DcsParts服务");}varresponseContent=awaitresponse.Content.ReadAsAsync<ReceiveResponseBody<List<T>>>();if(response.IsSuccessStatusCode){result=responseContent?.Payload;}else{if(!string.IsNullOrWhiteSpace(responseContent?.Message)){thrownewValidationException(responseContent.Message);}_loggerHelper.LogDebug($"请求返回结果:{0}请求内容:{1}",response.StatusCode,postData);}returnawaitTask.FromResult(result);}

  在上面的代码中我们模拟了一个Post请求,请求完成以后我们再使用ReadAsAsync的方法来异步接收另外一个域中的数据,然后我们根据返回的StatusCode来抛出不同的错误提示,并记录相关的日志信息并返回最终Post请求的结果,进而完成整个过程,在这个中间我们发送请求的时候需要注意一下内容:1 最终的完整版地址=BaseAddress+RelativeAddress,基地址是在appsetting.json中进行配置的,RelativeAddress是我们请求不同域的时候的相对地址,这个需要我们根据实际的业务来进行配置。2 请求的对象是我们将数据对象序列化成json后的结果,这两点需要特别注意。

  1.4 总结

  通过上面的讲述我们知道了如何完整的创建HttpClient以及通过创建的HttpClient如何收发数据,但同时我们也发现了通过上面的方式我们的缺点:如果一个业务中有大量的这种跨域请求整个代码显得非常臃肿并且由于不同开发人员的认知不同最终导致很容易出问题,那么我们是否有办法能够去解决上面的问题呢?Refit库的出现正好解决了这个问题,Refit通过这种申明式的方式能够很大程度上让代码更加简练明了而且提供了更加丰富的功能。

  二 使用Refit来创建HttpClient对象

  2.1 引入Refit包

  在我们的项目中我们可以通过 <PackageReference Include="Refit" Version="XXX" />来快速引用Refit包,引用的方式这里便不再赘述。

  2.2 定义接口

  我们将我们业务中涉及到的方法定义在一个接口中,就像下面这样。

publicinterfaceIDmsAfterSalesApi{[Headers("User-Agent:Dms-Parts")][Post("/internal/api/v1/customerAccounts/update")]Task<ResponseBody>UpdateCustomerAmount([Body]PartRetailSettlementModelinput);[Headers("User-Agent:Dms-Parts")][Post("/internal/api/v1/repairShortagePart/checkCustomerAccount")]Task<RepairShortagePartResponseBody>RepairShortagePartCheckCustomerAccount([Body]RepairShortagePartModelinput);[Headers("User-Agent:Dms-Parts")][Post("/internal/api/v1/vehiclesAndMemberCode/forCoupons")]Task<GetMemberCodeBrandCodeForVehicleBody>GetMemberCodeBrandCodeForVehicle(GuidvehicleId);}

  2.3 注入接口并使用接口中的方法

publicclassDmsAfterSalesClientService:DomainService{privatereadonlyIDmsAfterSalesApi_api;privatereadonlyILogger<DcsPartClientService>_logger;privateconststringFrom="DmsAfterSales";publicDmsAfterSalesClientService(IDmsAfterSalesApiapi,ILogger<DcsPartClientService>logger){_api=api;_logger=logger;}privateasyncTask<Exception>WrapException(ApiExceptionexception){if(exception.StatusCode==System.Net.HttpStatusCode.BadRequest){varreceivedBody=awaitexception.GetContentAsAsync<ResponseBody>();returnnewValidationException($"业务校验失败,{receivedBody.Message}({From})",exception);}else{_logger.LogWarning(exception,"CallDmsAfterSalesAPIfailed");returnnewApplicationException($"内部调用失败,{exception.Message}({exception.StatusCode})({From})",exception);}}privateExceptionWrapException(HttpRequestExceptionexception){_logger.LogWarning(exception,"CallDmsAfterSalesAPIfailed");returnnewApplicationException($"内部调用失败,{exception.Message}({From})",exception);}publicasyncTaskUpdateCustomerAmount([Body]PartRetailSettlementModelinput){try{await_api.UpdateCustomerAmount(input);}catch(ApiExceptionex){throwawaitWrapException(ex);}catch(HttpRequestExceptionex){throwWrapException(ex);}}publicasyncTask<decimal>RepairShortagePartCheckCustomerAccount([Body]RepairShortagePartModelinput){try{varresult=await_api.RepairShortagePartCheckCustomerAccount(input);returnresult.Payload.BalanceAmount;}catch(ApiExceptionex){throwawaitWrapException(ex);}catch(HttpRequestExceptionex){throwWrapException(ex);}}publicasyncTask<GetMemberCodeBrandCodeForVehicleOutput>GetMemberCodeBrandCodeForVehicle([Body]GuidvehicleId){try{varresult=await_api.GetMemberCodeBrandCodeForVehicle(vehicleId);returnresult.Payload;}catch(ApiExceptionex){throwawaitWrapException(ex);}catch(HttpRequestExceptionex){throwWrapException(ex);}}}

  在上面接口中定义好这个方法以后我们就可以直接在我们的领域类中引入这个接口IDmsAfterSalesApi ,然后就直接使用这个接口中的方法,讲到这里便有疑问,这个接口的实现到底在哪里?这里当我们定义好接口然后点击里面的方法转到实现的时候我们发现里面会转到一个叫做RefitStubs.g.cs的类中,然后自动的生成下面的方法。

///<inheritdoc/>[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage][global::System.Diagnostics.DebuggerNonUserCode][Preserve][global::System.Reflection.Obfuscation(Exclude=true)]partialclassAutoGeneratedIDmsAfterSalesApi:IDmsAfterSalesApi{///<inheritdoc/>publicHttpClientClient{get;protectedset;}readonlyIRequestBuilderrequestBuilder;///<inheritdoc/>publicAutoGeneratedIDmsAfterSalesApi(HttpClientclient,IRequestBuilderrequestBuilder){Client=client;this.requestBuilder=requestBuilder;}///<inheritdoc/>Task<ResponseBody>IDmsAfterSalesApi.UpdateCustomerAmount(PartRetailSettlementModelinput){vararguments=newobject[]{input};varfunc=requestBuilder.BuildRestResultFuncForMethod("UpdateCustomerAmount",newType[]{typeof(PartRetailSettlementModel)});return(Task<ResponseBody>)func(Client,arguments);}///<inheritdoc/>Task<RepairShortagePartResponseBody>IDmsAfterSalesApi.RepairShortagePartCheckCustomerAccount(RepairShortagePartModelinput){vararguments=newobject[]{input};varfunc=requestBuilder.BuildRestResultFuncForMethod("RepairShortagePartCheckCustomerAccount",newType[]{typeof(RepairShortagePartModel)});return(Task<RepairShortagePartResponseBody>)func(Client,arguments);}///<inheritdoc/>Task<GetMemberCodeBrandCodeForVehicleBody>IDmsAfterSalesApi.GetMemberCodeBrandCodeForVehicle(GuidvehicleId){vararguments=newobject[]{vehicleId};varfunc=requestBuilder.BuildRestResultFuncForMethod("GetMemberCodeBrandCodeForVehicle",newType[]{typeof(Guid)});return(Task<GetMemberCodeBrandCodeForVehicleBody>)func(Client,arguments);}}  

  这里面的核心是调用一个BuildRestResultFuncForMethod的方法,后面我们再来分析这里面到底是怎么实现的,这里我们首先把这整个使用流程说完,之前我们说过Refit的很多配置都是通过标签的方式来注入进去的,这里包括请求类型、相对请求地址,那么我们的默认超时时间和BaseAddress到底是怎样来配置的呢?下面我们就来重点讲述。

  2.4 在Startup中配置基础配置信息

publicIServiceProviderConfigureServices(IServiceCollectionservices){//refitdmsaftersales服务services.AddRefitClient<IDmsAfterSalesApi>().ConfigureHttpClient(c=>{c.BaseAddress=newUri(_appConfiguration["DependencyServices:DmsAfterSales"]);c.Timeout=TimeSpan.FromMilliseconds(_appConfiguration.GetValue<int>("AppSettings:ServiceTimeOutMs"));});}

  这里我们看到通过一个AddRefitClient方法我们就能够去配置我们的基础信息,讲到这里我们是不是对整个过程都有一个清楚的认识呢?通过上下两种方式的对比,相信你对整个Refit的使用都有自己的理解。

  2.5 注意事项

  由于我们的Headers经常需要我们去配置一组数据,那么我们应该怎么配置多个项呢?

[Headers("User-Agent:Dms-Parts","Content-Type:application/json")]

  通过上面的方式我们能够配置一组Headers,另外在很多的时候如果Headers里面没有配置Content-Type那么很有可能会返回StatusCode=415 Unsupport Media Type这个类型的错误信息,这个在使用的时候需要注意。

以上就是如何在Asp.Net Core中使用Refit,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注本站行业资讯频道。

标签:refit-

如今外卖行业成为了一种很便捷的服务,随着美团、饿了么、滴滴平台的崛起,越来越多的人选择足不出户就能在家点餐。那么外卖小程序开发有哪些价值?一、外卖小程序的价值1...

  时代在发展,微信小程序从发布了“跳一跳”开始,微信小程序游戏就已经在朋友圈中“传疯”了,在如今这个社会上,游戏市场从以前的对对碰,到现在的绝地求生,游戏世界...

很多企业由于缺乏专业代运营人员或经验,所以寻找专业的微信代运营平台。那么微信代运营平台哪个好?如何选择微信代运营平台?企业想寻找微信代运营平台,首先要搞清楚自己...

创业板鑫东财配资买涨不买跌怎么回事?大多数股民选择离开A股市场,是因为股市并不具备赚钱效应,更是在保护投资者的利益中不断的让股民们流泪,导致进入股市中90%的投资者都是亏损。而散户是证券市场不可分割的部分,占了80%的体量,却也是股市受伤最大的群体,在交易制度中受到了限制,在风险对冲中对于股指期货和融券却设了50万门槛,更是在外围股市走出十年长牛时,只能做多的市场却是长期的走熊,本想赚点利润改善生...

(资料图)板块有:1、风帆股份太阳能。2、力诺太阳能,高硼硅管材行业第一 。3、威远生化太阳能,新能源领域的不断拓展。4、杉杉股份太阳能,上游领域独具优势。5、特变电工太阳能,组件制造新力量。6、航天机电太阳能,控股子公司国内领先。7、维科精华太阳能,着力打造新能源航母。8、交大南洋太阳能,控股子公司生产能力强。...

越来越多人选择退出相互宝,原因其实离不开负面舆论的影响,如同多诺米骨牌,排山倒海式的轻松压垮相互宝在很多人心中的形象。最开始骂当然是因为分摊金上涨了,相互宝就是从这个时候开始被扣上了“不靠谱”“割韭菜”等帽子。对于想要推出相互宝的朋友想要知道相互宝怎么才能退本金呢?相互宝退出流程1、登录支付宝APP,点击【我的】--【蚂蚁保险】找到相互宝,进入相互宝...

TOP