zoukankan      html  css  js  c++  java
  • 声明式RESTful客户端在asp.net core中的应用

    1 声明式RESTful客户端

    声明式服务调用的客户端,常见有安卓的Retrofit、SpringCloud的Feign等,.net有Refit和WebApiClient,这些客户端都是以java或.net某个语言来声明接口,描述如何请求RESTful api。

    1.1 WebApiClient

    WebApiClient由c#开发,但适用于任意.net语言,包括c#、vb.net、f#等项目,其提供两个nuget包:WebApiClient.JIT和WebApiClient.AOT,均支持.net framework4.5.NET Standard 1.3

    WebApiClient.JIT

    在运行时使用Emit创建Http请求接口的代理类,HttpApiClient.Create()时,在新的程序集创建了TInterface的代理类,类名与TInterface相同,命名空间也相同,由于代理类和TInterface接口不在同一程序集,所以要求TInterface为public。

    • 可以在项目中直接引用WebApiClient.JIT.dll就能使用;
    • 不适用于不支持JIT技术的平台(IOS、UWP);
    • 接口要求为public;

    WebApiClient.AOT

    在编译过程中使用Mono.Cecil修改编译得到的程序集,向其插入Http请求接口的代理类IL指令,这一步是在AOT编译阶段之前完成。代理类型所在的程序集、模块、命名空间与接口类型的一样,其名称为$前缀的接口类型名称,使用反编译工具查看项目编译后的程序集可以看到这些代理类。

    • 项目必须使用nuget安装WebApiClient.AOT才能正常使用;
    • 没有JIT,支持的平台广泛;
    • 接口不要求为public,可以嵌套在类里面;

    1.2 Refit

    Refit是一个开发很早的项目,在github有很高的人气,由c#开发,目前仅支持c#语言项目,支持.NET Standard 1.4,.net framework需要4.6.1得以支持。

    Refit的内部实现与WebApiClient.AOT有相似之处,都是在编译阶段向声明接口项目插入接口实现类的代码或IL指令,我们可以称之为静态代理的编译时织入。Refit使用Microsoft.CodeAnalysis.CSharp来分析接口语法,编译前补充生成接口的代理类代码用来与项目代码一起编译。

    2 WebApiClient的声明式接口

    WebApiClient支持GET/HEAD、PUT/POST/DELETE、PATCH请求方法,请求内容体支持json、xml、multipart/form-data、application/x-www-form-urlencoded和自定义无结构内容等,其声明式接口风格与asp.net core的接口声明非常相似。

    2.1 接口声明

    远程服务asp.net core接口示例

    [Route("api/[controller]")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        // GET api/users
        [HttpGet]
        public UserInfo[] Get()
        {
            return new UserInfo[]
            {
                new UserInfo { Account="laojiu" },
                new UserInfo { Account="webapicleint" }
            };
        }
    
        // GET api/users/id001
        [HttpGet("{id}")]
        public UserInfo Get(string id)
        {
            return new UserInfo { Id = id, Account = "laojiu" };
        }
    
        // POST api/users
        [HttpPost]
        public bool Post([FromBody] UserInfo value)
        {
            return true;
        }
    
        // PUT api/users
        [HttpPut]
        public bool Put([FromBody] UserInfo value)
        {
            return true;
        }
    
        // PATCH api/users/id001
        [HttpPatch("{id}")]
        public bool Patch(string id, [FromBody] JsonPatchDocument<UserInfo> value)
        {
            var user = new UserInfo { Account = "laojiu" };
            value.ApplyTo(user);
    
            return true;
        }
    
    
        // DELETE api/users/id001
        [HttpDelete("{id}")]
        public bool Delete(string id)
        {
            return true;
        }
    }
    

    WebApiClient声明式调用接口

    [TraceFilter]
    public interface IUsersApi : IHttpApi
    {
        [HttpGet("api/users")]
        ITask<UserInfo[]> GetAsync();
    
        [HttpGet("api/users/{id}")]
        ITask<UserInfo> GetAsync(string id);
    
        [HttpPost("api/users")]
        ITask<bool> PostAsync([JsonContent] UserInfo value);
    
        [HttpPut("api/users")]
        ITask<bool> PutAsync([JsonContent] UserInfo value);
    
        [HttpPatch("api/users/{id}")]
        ITask<bool> PatchAsync(string id, JsonPatchDocument<UserInfo> value);
    
        [HttpDelete("api/users/{id}")]
        ITask<bool> DeleteAsync(string id);
    }
    

    3 WebApiClient与DI结合

    asp.net core环境中,我们可以使用WebApiClient.Extensions项目简单WebApiClient的DI的配置,目前有DependencyInjection和HttpClientFactory的扩展等。

    3.1 WebApiClient.Extensions.DependencyInjection

    引入nuget包

    PM> install-package WebApiClient.Extensions.DependencyInjection 
    

    Startup相关配置

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpApi<IUsersApi>().ConfigureHttpApiConfig((c,p) =>
        {
            c.HttpHost = new Uri("https://localhost:5001/");
            c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
            c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
        });
        ...
    }
    

    Controller

    public class HomeController : Controller
    {
        public async Task<string> Index([FromServices]IUsersApi usersApi)
        {
            var u = new UserInfo { Id = "id001", Account = "webapiclient", Password = "123456" };
            var doc = new JsonPatchDocument<UserInfo>();
            doc.Replace(item => item.Password, "888888");
    
            var users = await usersApi.GetAsync();
            var user = await usersApi.GetAsync("id001");
            var postState = await usersApi.PostAsync(u);
            var putState = await usersApi.PutAsync(u);
            var patchState = await usersApi.PatchAsync("id001", doc);
            var deleteState = await usersApi.DeleteAsync("id001");
            return "ok";
        }
    }
    

    3.2 WebApiClient.Extensions.HttpClientFactory

    引入nuget包

    PM> install-package WebApiClient.Extensions.HttpClientFactory 
    

    Startup相关配置

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {   
        services.AddHttpApiTypedClient<IUsersApi>((c, p) =>
        {
            c.HttpHost = new Uri("https://localhost:5001/");
            c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
            c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
        });
        ...
    }
    

    4 总结

    本文讲解了声明式客户端的概念、列表几个声明式客户端项目,同时讲解声明式客户端WebApiClient在asp.net core项目中的简单使用,有关更多高级的应用,可以到WebApiClient的github上查看相关wiki。

  • 相关阅读:
    vue promise
    vue 数组操作
    vue登录注册切换的坑
    筆記連接
    vue配置jquery和bootstarp
    css的寬高約束
    css框模型
    css居中flex
    css居中
    遍历forEach与map的区别-forEach踩坑记
  • 原文地址:https://www.cnblogs.com/kewei/p/9786319.html
Copyright © 2011-2022 走看看