43

打造适用于c#的feign - KavinDavid

 6 years ago
source link: https://www.cnblogs.com/pokemon/p/11412051.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

打造适用于c#的feign

  之前因为工作原因使用spring cloud全家桶开发过若干项目,发现其中的feign非常好用,以前开发接口客户端的时候都是重复使用HttpClient实现业务,每次新增接口都十分繁琐,故萌生了自定义一个feign.net的想法,直到最近辞去工作后有了时间着手开发. 关于feign的介绍就不多说了,网上有大量的资料.

  个人无太多精力复制feign的全部功能,只挑一些比较重要的来实现.

  首先定义一个 FeignClientAttribute,其中的Fallback和FallbackFactory主要用于服务降级.

ContractedBlock.gifExpandedBlockStart.gif

FeignClientAttribute 

  FeignClientLifetime为服务的生命周期

ContractedBlock.gifExpandedBlockStart.gif

FeignClientLifetime

 定义RequestMapping

ContractedBlock.gifExpandedBlockStart.gif

RequestMappingAttribute

 定义PathVariableAttribute等

ContractedBlock.gifExpandedBlockStart.gif

PathVariableAttribute等

 为了方便扩展,定义一个管道,里面包含了服务实例初始化,发送前,发送后等的事件.

ContractedBlock.gifExpandedBlockStart.gif

FeignClientPipeline

 基本的声明有了,然后开始实现动态生成代理类型代码.

 先定义一个Proxy父类

ContractedBlock.gifExpandedBlockStart.gif

View Code

ContractedBlock.gifExpandedBlockStart.gif

ServiceDiscoveryHttpClientHandler

 接下来开始生成代理类

 TypeBuilder

ContractedBlock.gifExpandedBlockStart.gif

CreateTypeBuilder

ContractedBlock.gifExpandedBlockStart.gif

BuildConstructor

 重写父类只读属性

ContractedBlock.gifExpandedBlockStart.gif

BuildReadOnlyProperty

        //serviceId
            BuildReadOnlyProperty(typeBuilder, serviceType, "ServiceId", serviceType.GetCustomAttribute<FeignClientAttribute>().Name);

            //baseUri
            BuildReadOnlyProperty(typeBuilder, serviceType, "BaseUri", serviceType.GetCustomAttribute<RequestMappingAttribute>()?.Value);

            // url
            if (serviceType.GetCustomAttribute<FeignClientAttribute>().Url != null)
            {
                BuildReadOnlyProperty(typeBuilder, serviceType, "Url", serviceType.GetCustomAttribute<FeignClientAttribute>().Url);
            }

            typeBuilder.AddInterfaceImplementation(serviceType);

 接下来是最重要的,读取声明服务的所有方法,全部生成到代理类中

            foreach (var method in serviceType.GetMethods())
            {
                methodBuilder.BuildMethod(typeBuilder, serviceType, method, feignClientAttribute);
            }

ContractedBlock.gifExpandedBlockStart.gif

View Code

 最后看看效果

 声明的服务

ContractedBlock.gifExpandedBlockStart.gif

Service

生成的dll代码

ContractedBlock.gifExpandedBlockStart.gif

Proxy Service

接下来测试一下

ContractedBlock.gifExpandedBlockStart.gif

AddFeignClients

ContractedBlock.gifExpandedBlockStart.gif

AddTestFeignClients

    public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            //   services.AddDiscoveryClient(Configuration);

            services.AddFeignClients()
            .AddTestFeignClients()
            //.AddSteeltoeServiceDiscovery()
            ;

        }
  [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
   
        // GET api/values/5
        [HttpGet("{id}")]
        public async Task<ActionResult<object>> Get(int id, [FromServices] ITestService testService/*, [FromServices] ITestService1 testService1*/)
        {
            await testService.PostValueAsync();

            //string html = await testService1.GetHtml();
            //return html;

            //var rrr = typeof(Func<Task>).GetConstructors(System.Reflection.BindingFlags.Default);

            //IServiceCollection serviceCollection = HttpContext.RequestServices.GetService(typeof(IServiceCollection)) as IServiceCollection;

            //testService.GetValueVoidAsync(id, null, new TestServiceParam
            //{
            //    Name = "asasdsad"
            //});
            //return await testService.GetValueAsync(id, "asdasd");
            //await testService.PostValueForm2Async(id, "", new TestServiceParam
            //{
            //    Name = "testName"
            //}, new TestServiceParam
            //{
            //    Name = "name"
            //});
            //testService.GetValueVoid(id, new TestServiceParam
            //{
            //    Name = "testName"
            //}, new TestServiceParam
            //{
            //    Name = "name"
            //});
            //await testService.PostValueAsync();
            //await testService.PostValueAsync(id, "", new TestServiceParam());
            //return testService.GetQueryResultValue(id.ToString(), new TestServiceParam
            //{
            //    Name = "asasdsad"
            //});
            //return await testService.GetQueryResultValueAsync(id.ToString(), new TestServiceParam
            //{
            //    Name = "asasdsad"
            //});
            testService.GetValueVoidAsync(id, "", null);
            return "ok";
        }

    }

433614-20190827115756944-302331726.png

正常工作了! 

目前只支持简单的服务降级操作,没有实现Hystrix.

代码地址 :  https://github.com/daixinkai/feign.net


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK