• 打造适用于c#的feign


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

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

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

       

        /// <summary>
        /// a feign client service
        /// </summary>
        [AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
        public class FeignClientAttribute : Attribute
        {
            public FeignClientAttribute(string name)
            {
                if (name == null)
                {
                    throw new ArgumentNullException(nameof(name));
                }
                Name = name;
            }
            public virtual string Name { get; }
            public virtual string Url { get; set; }
            public virtual Type Fallback { get; set; }
            public virtual Type FallbackFactory { get; set; }
    
            public FeignClientLifetime? Lifetime { get; set; }
    
        }
    FeignClientAttribute 

      

      FeignClientLifetime为服务的生命周期

        /// <summary>
        /// Specifies the lifetime of a service
        /// </summary>
        public enum FeignClientLifetime
        {
            /// <summary>
            /// Specifies that a single instance of the service will be created.   
            /// </summary>
            Singleton = 0,
            /// <summary>
            /// Specifies that a new instance of the service will be created for each scope.
            /// </summary>
            Scoped = 1,
            /// <summary>
            /// Specifies that a new instance of the service will be created every time it is
            /// </summary>
            Transient = 2
        }
    FeignClientLifetime

     定义RequestMapping

       public class RequestMappingAttribute : RequestMappingBaseAttribute
        {
            public RequestMappingAttribute() { }
            public RequestMappingAttribute(string value) : this(value, "GET")
            {
            }
            public RequestMappingAttribute(string value, string method) : base(value)
            {
                Method = method;
            }
            public string Method { get; set; }
    
            public override string GetMethod()
            {
                return Method;
            }
        }
    RequestMappingAttribute

     定义PathVariableAttribute等

        [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
        public sealed class PathVariableAttribute : Attribute, IRequestParameter
        {
            public PathVariableAttribute()
            {
            }
            public PathVariableAttribute(string name)
            {
                Name = name;
            }
            public string Name { get; set; }
        }
    
        [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
        public sealed class RequestBodyAttribute : Attribute, IRequestParameter
        {
        }
    
        [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
        public sealed class RequestFormAttribute : Attribute, IRequestParameter
        {
        }
    
        [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
        public sealed class RequestParamAttribute : Attribute, IRequestParameter
        {
            public RequestParamAttribute()
            {
            }
            public RequestParamAttribute(string name)
            {
                Name = name;
            }
            public string Name { get; set; }
        }
    
        [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
        public sealed class RequestQueryAttribute : Attribute, IRequestParameter
        {
        }
    PathVariableAttribute等

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

        public interface IServiceFeignClientPipeline<TService>
        {
            bool Enabled { get; set; }
            event EventHandler<BuildingRequestEventArgs<TService>> BuildingRequest;
            event EventHandler<SendingRequestEventArgs<TService>> SendingRequest;
            event EventHandler<CancelRequestEventArgs<TService>> CancelRequest;
            event EventHandler<ErrorRequestEventArgs<TService>> ErrorRequest;
            event EventHandler<ReceivingResponseEventArgs<TService>> ReceivingResponse;
            event EventHandler<InitializingEventArgs<TService>> Initializing;
            event EventHandler<DisposingEventArgs<TService>> Disposing;
            event EventHandler<FallbackRequestEventArgs<TService>> FallbackRequest;
        }
    
        /// <summary>
        /// 全局Pipeline
        /// </summary>
        public interface IGlobalFeignClientPipeline : IServiceFeignClientPipeline<object>
        {
            IServiceFeignClientPipeline<object> GetServicePipeline(string serviceId);
            IServiceFeignClientPipeline<object> GetOrAddServicePipeline(string serviceId);
            IServiceFeignClientPipeline<TService> GetServicePipeline<TService>();
            IServiceFeignClientPipeline<TService> GetOrAddServicePipeline<TService>();
        }
    FeignClientPipeline

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

     先定义一个Proxy父类

        public interface IFeignClient
        {
            /// <summary>
            /// Gets the serviceId
            /// </summary>
            string ServiceId { get; }
        }
    
        public interface IFeignClient<out TService> : IFeignClient
        {
            TService Service { get; }
        }
    
        public abstract partial class FeignClientHttpProxy<TService> : IFeignClient<TService>, IDisposable where TService : class
        {
            public FeignClientHttpProxy(IFeignOptions feignOptions, IServiceDiscovery serviceDiscovery, ICacheProvider cacheProvider, ILoggerFactory loggerFactory)
            {
                _feignOptions = feignOptions;
                _globalFeignClientPipeline = _feignOptions?.FeignClientPipeline as GlobalFeignClientPipeline;
                _serviceIdFeignClientPipeline = _globalFeignClientPipeline?.GetServicePipeline(ServiceId);
                _serviceFeignClientPipeline = _globalFeignClientPipeline?.GetServicePipeline<TService>();
                _logger = loggerFactory?.CreateLogger(typeof(FeignClientHttpProxy<TService>));
                ServiceDiscoveryHttpClientHandler<TService> serviceDiscoveryHttpClientHandler = new ServiceDiscoveryHttpClientHandler<TService>(this, serviceDiscovery, cacheProvider, _logger);
                serviceDiscoveryHttpClientHandler.ShouldResolveService = string.IsNullOrWhiteSpace(Url);
                serviceDiscoveryHttpClientHandler.AllowAutoRedirect = false;
                HttpClient = new HttpClient(serviceDiscoveryHttpClientHandler);
                string baseUrl = serviceDiscoveryHttpClientHandler.ShouldResolveService ? ServiceId ?? "" : Url;
                if (!baseUrl.StartsWith("http"))
                {
                    baseUrl = $"http://{baseUrl}";
                }
                if (!string.IsNullOrWhiteSpace(BaseUri))
                {
                    if (baseUrl.EndsWith("/"))
                    {
                        baseUrl = baseUrl.TrimEnd('/');
                    }
                    if (BaseUri.StartsWith("/"))
                    {
                        baseUrl += BaseUri;
                    }
                    else
                    {
                        baseUrl += "/" + BaseUri;
                    }
                }
    
                if (baseUrl.EndsWith("/"))
                {
                    baseUrl = baseUrl.TrimEnd('/');
                }
                BaseUrl = baseUrl;
    
                InitializingEventArgs<TService> initializingEventArgs = new InitializingEventArgs<TService>(this);
                initializingEventArgs.HttpClient = HttpClient;
                OnInitializing(initializingEventArgs);
                HttpClient = initializingEventArgs.HttpClient;
                if (HttpClient == null)
                {
                    throw new ArgumentNullException(nameof(HttpClient));
                }
            }
    
    
    
            internal GlobalFeignClientPipeline _globalFeignClientPipeline;
    
            internal ServiceIdFeignClientPipeline _serviceIdFeignClientPipeline;
    
            internal ServiceFeignClientPipeline<TService> _serviceFeignClientPipeline;
    
            ILogger _logger;
    
            IFeignOptions _feignOptions;
    
            protected IFeignOptions FeignOptions => _feignOptions;
    
            TService IFeignClient<TService>.Service { get { return this as TService; } }
    
            public abstract string ServiceId { get; }
    
            protected virtual bool IsResponseTerminatedRequest => true;
    
            public virtual string BaseUri { get { return null; } }
    
            public virtual string Url { get { return null; } }
    
            protected string BaseUrl { get; }
    
            protected HttpClient HttpClient { get; }
    
            #region IDisposable Support
            private bool disposedValue = false; // 要检测冗余调用
    
            protected virtual void Dispose(bool disposing)
            {
                if (!disposedValue)
                {
                    DisposingEventArgs<TService> disposingEventArgs = new DisposingEventArgs<TService>(this, disposing);
                    OnDisposing(disposingEventArgs);
                    if (disposing)
                    {
                        // TODO: 释放托管状态(托管对象)。
                    }
    
                    // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                    // TODO: 将大型字段设置为 null。
                    HttpClient.Dispose();
                    disposedValue = true;
                }
            }
    
            // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
            //~FeignClientServiceBase()
            //{
            //    // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            //    Dispose(false);
            //}
    
            // 添加此代码以正确实现可处置模式。
            void IDisposable.Dispose()
            {
                // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
                Dispose(true);
                // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
                //GC.SuppressFinalize(this);
            }
            #endregion
    
            #region PathVariable
            protected string ReplacePathVariable<T>(string uri, string name, T value)
            {
                return FeignClientUtils.ReplacePathVariable<T>(_feignOptions.Converters, uri, name, value);
            }
            #endregion
            #region RequestParam
            protected string ReplaceRequestParam<T>(string uri, string name, T value)
            {
                return FeignClientUtils.ReplaceRequestParam<T>(_feignOptions.Converters, uri, name, value);
            }
            #endregion
            #region RequestQuery
            protected string ReplaceRequestQuery<T>(string uri, string name, T value)
            {
                return FeignClientUtils.ReplaceRequestQuery<T>(_feignOptions.Converters, uri, name, value);
            }
            #endregion
    
        }
    View Code
        public class FeignProxyHttpClientHandler<TService> : HttpClientHandler where TService : class
        {
            private readonly ILogger _logger;
            private FeignClientHttpProxy<TService> _feignClient;
    
            //IFeignClient IFeignHttpClientHandler.FeignClient => _feignClient;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="FeignHttpClientHandler"/> class.
            /// </summary>
            public FeignProxyHttpClientHandler(FeignClientHttpProxy<TService> feignClient, ILogger logger)
            {
                _feignClient = feignClient;
                _logger = logger;
            }
    
            protected virtual Uri LookupRequestUri(Uri uri)
            {
                return uri;
            }
    
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                FeignHttpRequestMessage feignRequest = request as FeignHttpRequestMessage;
                return SendInternalAsync(feignRequest, cancellationToken);
            }
    
    
            async Task<HttpResponseMessage> SendInternalAsync(FeignHttpRequestMessage request, CancellationToken cancellationToken)
            {
                var current = request.RequestUri;
                try
                {
    
                    #region BuildingRequest
                    BuildingRequestEventArgs<TService> buildingArgs = new BuildingRequestEventArgs<TService>(_feignClient, request.Method.ToString(), request.RequestUri, new Dictionary<string, string>());
                    _feignClient.OnBuildingRequest(buildingArgs);
                    //request.Method = new HttpMethod(buildingArgs.Method);
                    request.RequestUri = buildingArgs.RequestUri;
                    if (buildingArgs.Headers != null && buildingArgs.Headers.Count > 0)
                    {
                        foreach (var item in buildingArgs.Headers)
                        {
                            request.Headers.TryAddWithoutValidation(item.Key, item.Value);
                        }
                    }
                    #endregion
                    request.RequestUri = LookupRequestUri(request.RequestUri);
                    #region SendingRequest
                    SendingRequestEventArgs<TService> sendingArgs = new SendingRequestEventArgs<TService>(_feignClient, request);
                    _feignClient.OnSendingRequest(sendingArgs);
                    if (sendingArgs.IsTerminated)
                    {
                        //请求被终止
                        throw new TerminatedRequestException();
                    }
                    request = sendingArgs.RequestMessage;
                    if (request == null)
                    {
                        _logger?.LogError($"SendingRequest is null;");
                        return new HttpResponseMessage(System.Net.HttpStatusCode.ExpectationFailed)
                        {
                            Content = new StringContent(""),
                            //Headers = new System.Net.Http.Headers.HttpResponseHeaders(),
                            RequestMessage = request
                        };
                    }
                    #endregion
    
                    #region CannelRequest
                    CancelRequestEventArgs<TService> cancelArgs = new CancelRequestEventArgs<TService>(_feignClient, cancellationToken);
                    _feignClient.OnCancelRequest(cancelArgs);
                    #endregion
    
                    return await base.SendAsync(request, cancellationToken);
                }
                catch (Exception e)
                {
                    if (!e.IsSkipLog())
                    {
                        _logger?.LogError(e, "Exception during SendAsync()");
                    }
                    if (e is HttpRequestException)
                    {
                        FeignHttpRequestException feignHttpRequestException = new FeignHttpRequestException(_feignClient, request, (HttpRequestException)e);
                        ExceptionDispatchInfo exceptionDispatchInfo = ExceptionDispatchInfo.Capture(feignHttpRequestException);
                        exceptionDispatchInfo.Throw();
                    }
                    throw;
                }
                finally
                {
                    request.RequestUri = current;
                }
            }
    
        }
    
     public class ServiceDiscoveryHttpClientHandler<TService> : FeignProxyHttpClientHandler<TService> where TService : class
        {
    
            private IServiceResolve _serviceResolve;
            private IServiceDiscovery _serviceDiscovery;
            private ICacheProvider _serviceCacheProvider;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="ServiceDiscoveryHttpClientHandler"/> class.
            /// </summary>
            public ServiceDiscoveryHttpClientHandler(FeignClientHttpProxy<TService> feignClient, IServiceDiscovery serviceDiscovery, ICacheProvider serviceCacheProvider, ILogger logger) : base(feignClient, logger)
            {
                _serviceResolve = new RandomServiceResolve(logger);
                _serviceDiscovery = serviceDiscovery;
                _serviceCacheProvider = serviceCacheProvider;
                ShouldResolveService = true;
            }
    
    
            public bool ShouldResolveService { get; set; }
    
    
            protected override Uri LookupRequestUri(Uri uri)
            {
                if (!ShouldResolveService)
                {
                    return uri;
                }
                if (_serviceDiscovery == null)
                {
                    return uri;
                }
                IList<IServiceInstance> services = _serviceDiscovery.GetServiceInstancesWithCache(uri.Host, _serviceCacheProvider);
                return _serviceResolve.ResolveService(uri, services);
            }
    
        }
    ServiceDiscoveryHttpClientHandler

     接下来开始生成代理类

     TypeBuilder

            private TypeBuilder CreateTypeBuilder(string typeName, Type parentType)
            {
                return _dynamicAssembly.ModuleBuilder.DefineType(typeName,
                              TypeAttributes.Public |
                              TypeAttributes.Class |
                              TypeAttributes.AutoClass |
                              TypeAttributes.AnsiClass |
                              TypeAttributes.BeforeFieldInit |
                              TypeAttributes.AutoLayout,
                              parentType);
            }
    CreateTypeBuilder

     构造函数

            void BuildConstructor(TypeBuilder typeBuilder, Type parentType)
            {
                ConstructorInfo baseConstructorInfo = GetConstructor(parentType);
                var parameterTypes = baseConstructorInfo.GetParameters().Select(s => s.ParameterType).ToArray();
    
                ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
                   MethodAttributes.Public,
                   CallingConventions.Standard,
                   parameterTypes);
    
                ILGenerator constructorIlGenerator = constructorBuilder.GetILGenerator();
                constructorIlGenerator.Emit(OpCodes.Ldarg_0);
                for (int i = 1; i <= baseConstructorInfo.GetParameters().Length; i++)
                {
                    constructorIlGenerator.Emit(OpCodes.Ldarg_S, i);
                }
                constructorIlGenerator.Emit(OpCodes.Call, baseConstructorInfo);
                constructorIlGenerator.Emit(OpCodes.Ret);
            }
    BuildConstructor

     重写父类只读属性

     void BuildReadOnlyProperty(TypeBuilder typeBuilder, Type interfaceType, string propertyName, string propertyValue)
            {
                PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, typeof(string), Type.EmptyTypes);
    
                MethodBuilder propertyGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes);
                ILGenerator iLGenerator = propertyGet.GetILGenerator();
                if (propertyValue == null)
                {
                    iLGenerator.Emit(OpCodes.Ldnull);
                }
                else
                {
                    iLGenerator.Emit(OpCodes.Ldstr, propertyValue);
                }
                iLGenerator.Emit(OpCodes.Ret);
                propertyBuilder.SetGetMethod(propertyGet);
            }
    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);
                }
        class FeignClientHttpProxyEmitMethodBuilder : IMethodBuilder
        {
            #region define
            //protected static readonly MethodInfo ReplacePathVariableMethod = typeof(FeignClientHttpProxy<>).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o => o.IsGenericMethod && o.Name == "ReplacePathVariable");
    
            //protected static readonly MethodInfo ReplaceRequestParamMethod = typeof(FeignClientHttpProxy<>).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o => o.IsGenericMethod && o.Name == "ReplaceRequestParam");
    
            //protected static readonly MethodInfo ReplaceRequestQueryMethod = typeof(FeignClientHttpProxy<>).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o => o.IsGenericMethod && o.Name == "ReplaceRequestQuery");
    
            protected static MethodInfo GetReplacePathVariableMethod(TypeBuilder typeBuilder)
            {
                return typeBuilder.BaseType.GetMethod("ReplacePathVariable", BindingFlags.Instance | BindingFlags.NonPublic);
            }
    
            protected static MethodInfo GetReplaceRequestParamMethod(TypeBuilder typeBuilder)
            {
                return typeBuilder.BaseType.GetMethod("ReplaceRequestParam", BindingFlags.Instance | BindingFlags.NonPublic);
            }
    
            protected static MethodInfo GetReplaceRequestQueryMethod(TypeBuilder typeBuilder)
            {
                return typeBuilder.BaseType.GetMethod("ReplaceRequestQuery", BindingFlags.Instance | BindingFlags.NonPublic);
            }
    
            #endregion
    
            public void BuildMethod(TypeBuilder typeBuilder, Type serviceType, MethodInfo method, FeignClientAttribute feignClientAttribute)
            {
                BuildMethod(typeBuilder, serviceType, method, feignClientAttribute, GetRequestMappingAttribute(method));
            }
    
            void BuildMethod(TypeBuilder typeBuilder, Type serviceType, MethodInfo method, FeignClientAttribute feignClientAttribute, RequestMappingBaseAttribute requestMapping)
            {
                MethodBuilder methodBuilder = CreateMethodBuilder(typeBuilder, method);
                ILGenerator iLGenerator = methodBuilder.GetILGenerator();
                if (requestMapping == null)
                {
                    iLGenerator.Emit(OpCodes.Newobj, typeof(NotSupportedException).GetConstructor(Type.EmptyTypes));
                    iLGenerator.Emit(OpCodes.Throw);
                    return;
                }
                string uri = requestMapping.Value ?? "";
                LocalBuilder local_Uri = iLGenerator.DeclareLocal(typeof(string)); // uri
                LocalBuilder local_OldValue = iLGenerator.DeclareLocal(typeof(string)); // temp
                iLGenerator.Emit(OpCodes.Ldstr, uri);
                iLGenerator.Emit(OpCodes.Stloc, local_Uri);
                List<EmitRequestContent> emitRequestContents = EmitParameter(typeBuilder, iLGenerator, method, local_Uri, local_OldValue);
                EmitCallMethod(typeBuilder, methodBuilder, iLGenerator, serviceType, method, requestMapping, local_Uri, emitRequestContents);
            }
    
            protected MethodInfo GetInvokeMethod(Type serviceType, MethodInfo method, RequestMappingBaseAttribute requestMapping)
            {
                if (method.IsTaskMethod())
                {
                    if (method.ReturnType.IsGenericType)
                    {
                        return GetInvokeMethod(serviceType, requestMapping, method.ReturnType.GenericTypeArguments[0], true);
                    }
                    return GetInvokeMethod(serviceType, requestMapping, method.ReturnType, true);
                }
                return GetInvokeMethod(serviceType, requestMapping, method.ReturnType, false);
            }
    
            protected virtual MethodInfo GetInvokeMethod(Type serviceType, RequestMappingBaseAttribute requestMapping, Type returnType, bool async)
            {
                MethodInfo httpClientMethod;
                bool isGeneric = !(returnType == null || returnType == typeof(void) || returnType == typeof(Task));
                if (isGeneric)
                {
                    //httpClientMethod = async ? FeignClientHttpProxy<object>.HTTP_SEND_ASYNC_GENERIC_METHOD : FeignClientHttpProxy<object>.HTTP_SEND_GENERIC_METHOD;
                    httpClientMethod = async ? FeignClientHttpProxy<object>.GetHttpSendAsyncGenericMethod(serviceType) : FeignClientHttpProxy<object>.GetHttpSendGenericMethod(serviceType);
                }
                else
                {
                    //  httpClientMethod = async ? FeignClientHttpProxy<object>.HTTP_SEND_ASYNC_METHOD : FeignClientHttpProxy<object>.HTTP_SEND_METHOD;
                    httpClientMethod = async ? FeignClientHttpProxy<object>.GetHttpSendAsyncMethod(serviceType) : FeignClientHttpProxy<object>.GetHttpSendMethod(serviceType);
                }
                if (isGeneric)
                {
                    return httpClientMethod.MakeGenericMethod(returnType);
                }
                return httpClientMethod;
            }
    
            protected bool SupportRequestContent(MethodInfo method, RequestMappingBaseAttribute requestMappingBaseAttribute)
            {
                return "POST".Equals(requestMappingBaseAttribute.GetMethod(), StringComparison.OrdinalIgnoreCase) || "PUT".Equals(requestMappingBaseAttribute.GetMethod(), StringComparison.OrdinalIgnoreCase);
            }
    
            protected RequestMappingBaseAttribute GetRequestMappingAttribute(MethodInfo method)
            {
                if (method.IsDefined(typeof(RequestMappingBaseAttribute)))
                {
                    RequestMappingBaseAttribute[] requestMappingBaseAttributes = method.GetCustomAttributes<RequestMappingBaseAttribute>().ToArray();
                    if (requestMappingBaseAttributes.Length > 1)
                    {
                        throw new ArgumentException(nameof(requestMappingBaseAttributes.Length));
                    }
                    return requestMappingBaseAttributes[0];
                }
                string methodName = method.Name.ToLower();
    
                if (methodName.StartsWith("get") || methodName.StartsWith("query") || methodName.StartsWith("select"))
                {
                    //get
                    return new GetMappingAttribute();
                }
                else if (methodName.StartsWith("post") || methodName.StartsWith("create") || methodName.StartsWith("insert"))
                {
                    //post
                    return new PostMappingAttribute();
                }
                else if (methodName.StartsWith("put") || methodName.StartsWith("update"))
                {
                    //put
                    return new PutMappingAttribute();
                }
                else if (methodName.StartsWith("delete") || methodName.StartsWith("remove"))
                {
                    //delete
                    return new DeleteMappingAttribute();
                }
                return null;
            }
    
    
            protected MethodBuilder CreateMethodBuilder(TypeBuilder typeBuilder, MethodInfo method)
            {
                MethodAttributes methodAttributes;
                if (method.IsVirtual)
                {
                    //methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual;
                    methodAttributes =
                        MethodAttributes.Public
                        | MethodAttributes.HideBySig
                        | MethodAttributes.NewSlot
                        | MethodAttributes.Virtual
                        | MethodAttributes.Final;
                }
                else
                {
                    methodAttributes = MethodAttributes.Public;
                }
                var arguments = method.GetParameters().Select(a => a.ParameterType).ToArray();
                MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes, CallingConventions.Standard, method.ReturnType, arguments);
                typeBuilder.DefineMethodOverride(methodBuilder, method);
                return methodBuilder;
            }
    
            protected virtual void EmitCallMethod(TypeBuilder typeBuilder, MethodBuilder methodBuilder, ILGenerator iLGenerator, Type serviceType, MethodInfo method, RequestMappingBaseAttribute requestMapping, LocalBuilder uri, List<EmitRequestContent> emitRequestContents)
            {
                var invokeMethod = GetInvokeMethod(serviceType, method, requestMapping);
                if (emitRequestContents != null && emitRequestContents.Count > 0 && !SupportRequestContent(invokeMethod, requestMapping))
                {
                    throw new NotSupportedException("不支持RequestBody或者RequestForm");
                }
                LocalBuilder feignClientRequest = DefineFeignClientRequest(typeBuilder, serviceType, iLGenerator, uri, requestMapping, emitRequestContents, method);
                iLGenerator.Emit(OpCodes.Ldarg_0);  //this
                iLGenerator.Emit(OpCodes.Ldloc, feignClientRequest);
                iLGenerator.Emit(OpCodes.Call, invokeMethod);
                iLGenerator.Emit(OpCodes.Ret);
            }
    
            protected LocalBuilder DefineFeignClientRequest(TypeBuilder typeBuilder, Type serviceType, ILGenerator iLGenerator, LocalBuilder uri, RequestMappingBaseAttribute requestMapping, List<EmitRequestContent> emitRequestContents, MethodInfo methodInfo)
            {
                LocalBuilder localBuilder = iLGenerator.DeclareLocal(typeof(FeignClientHttpRequest));
                // baseUrl
                EmitBaseUrl(iLGenerator, serviceType);
                //mapping uri
                if (requestMapping.Value == null)
                {
                    iLGenerator.Emit(OpCodes.Ldnull);
                }
                else
                {
                    iLGenerator.Emit(OpCodes.Ldstr, requestMapping.Value);
                }
                //uri
                iLGenerator.Emit(OpCodes.Ldloc, uri);
                //httpMethod
                iLGenerator.Emit(OpCodes.Ldstr, requestMapping.GetMethod());
    
                //contentType
                string contentType = requestMapping.ContentType;
                if (string.IsNullOrWhiteSpace(contentType) && serviceType.IsDefined(typeof(RequestMappingAttribute)))
                {
                    contentType = serviceType.GetCustomAttribute<RequestMappingAttribute>().ContentType;
                }
                if (contentType == null)
                {
                    iLGenerator.Emit(OpCodes.Ldnull);
                }
                else
                {
                    iLGenerator.Emit(OpCodes.Ldstr, contentType);
                }
    
                //requestContent
                if (emitRequestContents != null && emitRequestContents.Count > 0)
                {
                    if (emitRequestContents.Count == 1)
                    {
                        if (typeof(IHttpRequestFile).IsAssignableFrom(emitRequestContents[0].Parameter.ParameterType))
                        {
                            EmitFeignClientMultipartRequestContent(iLGenerator, emitRequestContents);
                        }
                        else
                        {
                            EmitFeignClientRequestContent(iLGenerator, emitRequestContents[0], null);
                        }
                    }
                    else if (emitRequestContents.Any(s => !s.SupportMultipart))
                    {
                        throw new NotSupportedException("最多只支持一个RequestContent");
                    }
                    else
                    {
                        EmitFeignClientMultipartRequestContent(iLGenerator, emitRequestContents);
                    }
                }
                else
                {
                    iLGenerator.Emit(OpCodes.Ldnull);
                }
                //method
                // method=null
                LocalBuilder methodInfoLocalBuilder = iLGenerator.DeclareLocal(typeof(MethodInfo));
                iLGenerator.Emit(OpCodes.Ldnull);
                iLGenerator.Emit(OpCodes.Stloc, methodInfoLocalBuilder);
                Label newFeingClientRequestLabel = iLGenerator.DefineLabel();
    
                #region if (base.FeignOptions.IncludeMethodMetadata) set the call method
    
                PropertyInfo feignOptionsProperty = typeBuilder.BaseType.GetProperty("FeignOptions", BindingFlags.Instance | BindingFlags.NonPublic);
                PropertyInfo includeMethodMetadataProperty = feignOptionsProperty.PropertyType.GetProperty("IncludeMethodMetadata");
                iLGenerator.Emit(OpCodes.Ldarg_0);
                iLGenerator.Emit(OpCodes.Call, feignOptionsProperty.GetMethod);
                iLGenerator.Emit(OpCodes.Call, includeMethodMetadataProperty.GetMethod);
                iLGenerator.Emit(OpCodes.Ldc_I4, 1);
                iLGenerator.Emit(OpCodes.Ceq);
                iLGenerator.Emit(OpCodes.Brfalse_S, newFeingClientRequestLabel);
                ReflectionHelper.EmitMethodInfo(iLGenerator, methodInfo);
                iLGenerator.Emit(OpCodes.Stloc, methodInfoLocalBuilder);
    
                #endregion
    
                iLGenerator.MarkLabel(newFeingClientRequestLabel);
                iLGenerator.Emit(OpCodes.Ldloc, methodInfoLocalBuilder);
                iLGenerator.Emit(OpCodes.Newobj, typeof(FeignClientHttpRequest).GetConstructors()[0]);
                iLGenerator.Emit(OpCodes.Stloc, localBuilder);
                return localBuilder;
            }
    
            void EmitFeignClientRequestContent(ILGenerator iLGenerator, EmitRequestContent emitRequestContent, LocalBuilder localBuilder)
            {
                if (typeof(IHttpRequestFileForm).IsAssignableFrom(emitRequestContent.Parameter.ParameterType))
                {
                    //iLGenerator.Emit(OpCodes.Ldstr, emitRequestContent.Parameter.Name);
                    iLGenerator.Emit(OpCodes.Ldarg_S, emitRequestContent.ParameterIndex);
                    iLGenerator.Emit(OpCodes.Newobj, typeof(FeignClientHttpFileFormRequestContent).GetConstructors()[0]);
                    if (localBuilder != null)
                    {
                        iLGenerator.Emit(OpCodes.Stloc, localBuilder);
                    }
                    return;
                }
                if (typeof(IHttpRequestFile).IsAssignableFrom(emitRequestContent.Parameter.ParameterType))
                {
                    iLGenerator.Emit(OpCodes.Ldstr, emitRequestContent.Parameter.Name);
                    iLGenerator.Emit(OpCodes.Ldarg_S, emitRequestContent.ParameterIndex);
                    iLGenerator.Emit(OpCodes.Newobj, typeof(FeignClientHttpFileRequestContent).GetConstructors()[0]);
                    if (localBuilder != null)
                    {
                        iLGenerator.Emit(OpCodes.Stloc, localBuilder);
                    }
                    return;
                }
                ConstructorInfo constructorInfo;
                switch (emitRequestContent.MediaType)
                {
                    case "application/json":
                        constructorInfo = typeof(FeignClientHttpJsonRequestContent<>).MakeGenericType(emitRequestContent.Parameter.ParameterType).GetConstructors()[0];
                        break;
                    case "application/x-www-form-urlencoded":
                        constructorInfo = typeof(FeignClientHttpFormRequestContent<>).MakeGenericType(emitRequestContent.Parameter.ParameterType).GetConstructors()[0];
                        break;
                    default:
                        throw new NotSupportedException("不支持的content type");
                        //constructorInfo = typeof(FeignClientFormRequestContent<>).MakeGenericType(emitRequestContent.Parameter.ParameterType).GetConstructors()[0];
                        //break;
                };
                iLGenerator.Emit(OpCodes.Ldstr, emitRequestContent.Parameter.Name);
                iLGenerator.Emit(OpCodes.Ldarg_S, emitRequestContent.ParameterIndex);
                iLGenerator.Emit(OpCodes.Newobj, constructorInfo);
                if (localBuilder != null)
                {
                    iLGenerator.Emit(OpCodes.Stloc, localBuilder);
                }
            }
    
            void EmitFeignClientMultipartRequestContent(ILGenerator iLGenerator, List<EmitRequestContent> emitRequestContents)
            {
                LocalBuilder requestContent = iLGenerator.DeclareLocal(typeof(FeignClientHttpMultipartFormRequestContent));
                MethodInfo methodAddContent = typeof(FeignClientHttpMultipartFormRequestContent).GetMethod("AddContent");
                iLGenerator.Emit(OpCodes.Newobj, typeof(FeignClientHttpMultipartFormRequestContent).GetConstructors()[0]);
                iLGenerator.Emit(OpCodes.Stloc, requestContent);
                for (int i = 0; i < emitRequestContents.Count; i++)
                {
                    LocalBuilder childRequestContent = iLGenerator.DeclareLocal(typeof(FeignClientHttpRequestContent));
                    EmitFeignClientRequestContent(iLGenerator, emitRequestContents[i], childRequestContent);
                    iLGenerator.Emit(OpCodes.Ldloc, requestContent);
                    iLGenerator.Emit(OpCodes.Ldstr, emitRequestContents[i].Parameter.Name);
                    iLGenerator.Emit(OpCodes.Ldloc, childRequestContent);
                    iLGenerator.Emit(OpCodes.Call, methodAddContent);
                }
                iLGenerator.Emit(OpCodes.Ldloc, requestContent);
            }
    
            void EmitBaseUrl(ILGenerator iLGenerator, Type serviceType)
            {
                PropertyInfo propertyInfo = typeof(FeignClientHttpProxy<>).MakeGenericType(serviceType).GetProperty("BaseUrl", BindingFlags.Instance | BindingFlags.NonPublic);
                iLGenerator.Emit(OpCodes.Ldarg_0); //this
                iLGenerator.Emit(OpCodes.Callvirt, propertyInfo.GetMethod);
            }
    
            protected List<EmitRequestContent> EmitParameter(TypeBuilder typeBuilder, ILGenerator iLGenerator, MethodInfo method, LocalBuilder uri, LocalBuilder value)
            {
                int index = 0;
                List<EmitRequestContent> emitRequestContents = new List<EmitRequestContent>();
                foreach (var parameterInfo in method.GetParameters())
                {
                    index++;
                    if (typeof(IHttpRequestFileForm).IsAssignableFrom(parameterInfo.ParameterType))
                    {
                        emitRequestContents.Add(new EmitRequestContent
                        {
                            MediaType = Constants.MediaTypes.MULTIPART_FORMDATA,
                            Parameter = parameterInfo,
                            SupportMultipart = false,
                            ParameterIndex = index
                        });
                        continue;
                    }
                    if (typeof(IHttpRequestFile).IsAssignableFrom(parameterInfo.ParameterType))
                    {
                        emitRequestContents.Add(new EmitRequestContent
                        {
                            MediaType = Constants.MediaTypes.FORMDATA,
                            Parameter = parameterInfo,
                            SupportMultipart = true,
                            ParameterIndex = index
                        });
                        continue;
                    }
                    if (parameterInfo.IsDefined(typeof(RequestBodyAttribute)))
                    {
                        emitRequestContents.Add(new EmitRequestContent
                        {
                            MediaType = Constants.MediaTypes.APPLICATION_JSON,
                            Parameter = parameterInfo,
                            SupportMultipart = false,
                            ParameterIndex = index
                        });
                        continue;
                    }
                    if (parameterInfo.IsDefined(typeof(RequestFormAttribute)))
                    {
                        emitRequestContents.Add(new EmitRequestContent
                        {
                            MediaType = Constants.MediaTypes.APPLICATION_FORM_URLENCODED,
                            Parameter = parameterInfo,
                            SupportMultipart = true,
                            ParameterIndex = index
                        });
                        continue;
                    }
                    MethodInfo replaceValueMethod;
                    string name;
                    if (parameterInfo.IsDefined(typeof(RequestParamAttribute)))
                    {
                        name = parameterInfo.GetCustomAttribute<RequestParamAttribute>().Name ?? parameterInfo.Name;
                        //replaceValueMethod = ReplaceRequestParamMethod;
                        replaceValueMethod = GetReplaceRequestParamMethod(typeBuilder);
                    }
                    else if (parameterInfo.IsDefined(typeof(RequestQueryAttribute)))
                    {
                        name = parameterInfo.Name;
                        //replaceValueMethod = ReplaceRequestQueryMethod;
                        replaceValueMethod = GetReplaceRequestQueryMethod(typeBuilder);
                    }
                    else
                    {
                        name = parameterInfo.IsDefined(typeof(PathVariableAttribute)) ? parameterInfo.GetCustomAttribute<PathVariableAttribute>().Name : parameterInfo.Name;
                        //replaceValueMethod = ReplacePathVariableMethod;
                        replaceValueMethod = GetReplacePathVariableMethod(typeBuilder);
                    }
    
                    if (string.IsNullOrWhiteSpace(name))
                    {
                        name = parameterInfo.Name;
                    }
    
                    iLGenerator.Emit(OpCodes.Ldstr, name);
                    iLGenerator.Emit(OpCodes.Stloc, value);
                    iLGenerator.Emit(OpCodes.Ldarg_0);
                    iLGenerator.Emit(OpCodes.Ldloc, uri);
                    iLGenerator.Emit(OpCodes.Ldloc, value);
                    iLGenerator.Emit(OpCodes.Ldarg_S, index);
                    replaceValueMethod = replaceValueMethod.MakeGenericMethod(parameterInfo.ParameterType);
                    iLGenerator.Emit(OpCodes.Call, replaceValueMethod);
                    iLGenerator.Emit(OpCodes.Stloc, uri);
    
                }
                return emitRequestContents;
            }
    
        }
    
    class FallbackFeignClientHttpProxyEmitMethodBuilder : FeignClientHttpProxyEmitMethodBuilder
        {
            public FallbackFeignClientHttpProxyEmitMethodBuilder(DynamicAssembly dynamicAssembly)
            {
                _dynamicAssembly = dynamicAssembly;
            }
    
            DynamicAssembly _dynamicAssembly;
    
    
            protected override MethodInfo GetInvokeMethod(Type serviceType, RequestMappingBaseAttribute requestMapping, Type returnType, bool async)
            {
                MethodInfo httpClientMethod;
                bool isGeneric = !(returnType == null || returnType == typeof(void) || returnType == typeof(Task));
                if (isGeneric)
                {
                    //httpClientMethod = async ? FallbackFeignClientHttpProxy<object, object>.HTTP_SEND_ASYNC_GENERIC_METHOD_FALLBACK : FallbackFeignClientHttpProxy<object, object>.HTTP_SEND_GENERIC_METHOD_FALLBACK;
                    httpClientMethod = async ? FallbackFeignClientHttpProxy<object, object>.GetHttpSendAsyncGenericFallbackMethod(serviceType, serviceType) : FallbackFeignClientHttpProxy<object, object>.GetHttpSendGenericFallbackMethod(serviceType, serviceType);
                }
                else
                {
                    //httpClientMethod = async ? FallbackFeignClientHttpProxy<object, object>.HTTP_SEND_ASYNC_METHOD_FALLBACK : FallbackFeignClientHttpProxy<object, object>.HTTP_SEND_METHOD_FALLBACK;
                    httpClientMethod = async ? FallbackFeignClientHttpProxy<object, object>.GetHttpSendAsyncFallbackMethod(serviceType, serviceType) : FallbackFeignClientHttpProxy<object, object>.GetHttpSendFallbackMethod(serviceType, serviceType);
                }
                if (isGeneric)
                {
                    return httpClientMethod.MakeGenericMethod(returnType);
                }
                return httpClientMethod;
            }
    
            protected override void EmitCallMethod(TypeBuilder typeBuilder, MethodBuilder methodBuilder, ILGenerator iLGenerator, Type serviceType, MethodInfo method, RequestMappingBaseAttribute requestMapping, LocalBuilder uri, List<EmitRequestContent> emitRequestContents)
            {
                var invokeMethod = GetInvokeMethod(serviceType, method, requestMapping);
                if (emitRequestContents != null && emitRequestContents.Count > 0 && !SupportRequestContent(invokeMethod, requestMapping))
                {
                    throw new NotSupportedException("不支持RequestBody或者RequestForm");
                }
                LocalBuilder feignClientRequest = DefineFeignClientRequest(typeBuilder, serviceType, iLGenerator, uri, requestMapping, emitRequestContents, method);
                // fallback
                LocalBuilder fallbackDelegate = DefineFallbackDelegate(typeBuilder, methodBuilder, iLGenerator, serviceType, method);
                iLGenerator.Emit(OpCodes.Ldarg_0);  //this
                iLGenerator.Emit(OpCodes.Ldloc, feignClientRequest);
                iLGenerator.Emit(OpCodes.Ldloc, fallbackDelegate);
                iLGenerator.Emit(OpCodes.Call, invokeMethod);
                iLGenerator.Emit(OpCodes.Ret);
            }
    
            LocalBuilder DefineFallbackDelegate(TypeBuilder typeBuilder, MethodBuilder methodBuilder, ILGenerator iLGenerator, Type serviceType, MethodInfo method)
            {
                Type delegateType;
                if (method.ReturnType == null || method.ReturnType == typeof(void))
                {
                    delegateType = typeof(Action);
                }
                else
                {
                    delegateType = typeof(Func<>).MakeGenericType(method.ReturnType);
                }
    
                int bindingFlagsValue = 0;
                foreach (BindingFlags item in Enum.GetValues(typeof(BindingFlags)))
                {
                    bindingFlagsValue += item.GetHashCode();
                }
                var delegateConstructor = delegateType.GetConstructors((BindingFlags)bindingFlagsValue)[0];
                LocalBuilder invokeDelegate = iLGenerator.DeclareLocal(delegateType);
                // if has parameters
                if (method.GetParameters().Length > 0)
                {
                    var anonymousMethodClassTypeBuild = FallbackProxyAnonymousMethodClassBuilder.BuildType(_dynamicAssembly.ModuleBuilder, serviceType, method);
                    // new anonymousMethodClass
                    LocalBuilder anonymousMethodClass = iLGenerator.DeclareLocal(anonymousMethodClassTypeBuild.Item1);
                    //field
                    iLGenerator.Emit(OpCodes.Ldarg_0); //this
    
                    iLGenerator.Emit(OpCodes.Call, typeBuilder.BaseType.GetProperty("Fallback").GetMethod); //.Fallback
                    for (int i = 1; i <= method.GetParameters().Length; i++)
                    {
                        iLGenerator.Emit(OpCodes.Ldarg_S, i);
                    }
    
                    iLGenerator.Emit(OpCodes.Newobj, anonymousMethodClassTypeBuild.Item2);
                    iLGenerator.Emit(OpCodes.Stloc, anonymousMethodClass);
                    iLGenerator.Emit(OpCodes.Ldloc, anonymousMethodClass);
                    iLGenerator.Emit(OpCodes.Ldftn, anonymousMethodClassTypeBuild.Item3);
                }
                else
                {
                    iLGenerator.Emit(OpCodes.Ldarg_0); //this
                    iLGenerator.Emit(OpCodes.Call, typeBuilder.BaseType.GetProperty("Fallback").GetMethod); //.Fallback
                    iLGenerator.Emit(OpCodes.Ldftn, method);
                }
    
                iLGenerator.Emit(OpCodes.Newobj, delegateConstructor);
                iLGenerator.Emit(OpCodes.Stloc, invokeDelegate);
    
                return invokeDelegate;
            }
    
    
        }
    View Code

     最后看看效果

     声明的服务

     [CustomFeignClient("yun-platform-service-provider"
            , Fallback = typeof(TestServiceFallback)
            //, FallbackFactory = typeof(TestServiceFallbackFactory)
            //, Url = "http://localhost:8802/"
            //, Url = "http://10.1.5.90:8802/"
            //, Url = "http://localhost:62088/"
            )]
        [RequestMapping("/organizations")]
        public interface ITestService
        {
    
            //string Name { get; }
    
            [RequestMapping("/{id}/asdasdsad", Method = "POST")]
            Task PostValueAsync();
    
            [RequestMapping("/Values/uploadFile", Method = "POST")]
            Task<string> UploadFileAsync(IHttpRequestFile file, [RequestForm] TestServiceParam param);
    
            [RequestMapping("/Values/uploadFile", Method = "POST")]
            Task<string> UploadFileAsync(IHttpRequestFile file, [RequestForm] string name);
    
            [RequestMapping("/Values/uploadFile", Method = "POST")]
            Task<string> UploadFileAsync(TestServiceUploadFileParam param);
    
            [RequestMapping("/Values/formTest", Method = "POST")]
            Task<string> FormTestAsync([RequestForm] TestServiceParam param);
    
            [RequestMapping("/Values/uploadFiles", Method = "POST")]
            Task<string> UploadFilesAsync(IHttpRequestFile file1, IHttpRequestFile file2, IHttpRequestFile file3);
    
            [RequestMapping("/{id}", Method = "GET")]
            Task<QueryResult<JObject>> GetQueryResultValueAsync([PathVariable("id")]string id, [RequestQuery] TestServiceParam param);
    
            [RequestMapping("/{id}", Method = "GET")]
            QueryResult<JObject> GetQueryResultValue([PathVariable("id")]string id, [RequestQuery] TestServiceParam param);
    
            //[RequestMapping("/{id}", Method = "GET")]
            //Task<JObject> GetValueAsync([PathVariable("id")]string id);
            //[RequestMapping("/{id}", Method = "GET")]
            //Task<JObject> GetValueAsync([PathVariable]int id, [RequestParam] string test);
            //[GetMapping("/{id}")]
            //Task<JObject> GetValueAsync([PathVariable]int id, [RequestQuery] TestServiceParam param);
            [RequestMapping("/{id}")]
            void GetValueVoid([PathVariable]int id, [RequestParam] string test, [RequestQuery] TestServiceParam param);
    
            [RequestMapping("/{id}")]
            Task GetValueVoidAsync([PathVariable]int id, [RequestParam] string test, [RequestQuery] TestServiceParam param);
    
            [RequestMapping("/{id}", Method = "POST")]
            Task PostValueAsync([PathVariable]int id, [RequestParam] string test, [RequestBody] TestServiceParam param);
    
            [RequestMapping("/{id}", Method = "POST")]
            Task PostValueFormAsync([PathVariable]int id, [RequestParam] string test, [RequestForm] TestServiceParam param);
    
            [RequestMapping("/{id}", Method = "POST")]
            Task PostValueForm2Async([PathVariable]int id, [RequestParam] string test, [RequestForm] TestServiceParam param1, [RequestForm] TestServiceParam param2);
    
            [RequestMapping("/{id}")]
            void GetValueVoid([PathVariable]int id, [RequestParam] TestServiceParam queryParam, [RequestQuery] TestServiceParam param);
    
            //[GetMapping("/{id}")]
            //Task<JObject> GetValueAsync([PathVariable]int id, [RequestParam] string test, [RequestQuery] TestServiceParam param);
    
        }
    Service

    生成的dll代码

    // Token: 0x02000002 RID: 2
        [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
        public class ITestService_Proxy_115A31A563E54DEF888C90E5FA6CAC78 : FallbackFeignClientHttpProxy<ITestService, TestServiceFallback>, ITestService
        {
            // Token: 0x06000001 RID: 1 RVA: 0x00002E0C File Offset: 0x0000100C
            public ITestService_Proxy_115A31A563E54DEF888C90E5FA6CAC78(IFeignOptions A_1, IServiceDiscovery A_2, ICacheProvider A_3, ILoggerFactory A_4, TestServiceFallback A_5) : base(A_1, A_2, A_3, A_4, A_5)
            {
            }
    
            // Token: 0x17000001 RID: 1
            // (get) Token: 0x06000002 RID: 2 RVA: 0x00002E38 File Offset: 0x00001038
            public override string ServiceId
            {
                get
                {
                    return "yun-platform-service-provider";
                }
            }
    
            // Token: 0x17000002 RID: 2
            // (get) Token: 0x06000003 RID: 3 RVA: 0x00002E4C File Offset: 0x0000104C
            public override string BaseUri
            {
                get
                {
                    return "/organizations";
                }
            }
    
            // Token: 0x17000003 RID: 3
            // (get) Token: 0x06000004 RID: 4 RVA: 0x00002E60 File Offset: 0x00001060
            public override string Url
            {
                get
                {
                    return "http://10.1.5.90:8802/";
                }
            }
    
            // Token: 0x06000005 RID: 5 RVA: 0x00002E74 File Offset: 0x00001074
            public Task PostValueAsync()
            {
                string text = "/{id}/asdasdsad";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}/asdasdsad";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.PostValueAsync());
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                Func<Task> fallback = new Func<Task>(base.Fallback.PostValueAsync);
                return base.SendAsync(request, fallback);
            }
    
            // Token: 0x06000006 RID: 6 RVA: 0x00002EE4 File Offset: 0x000010E4
            public Task<string> UploadFileAsync(IHttpRequestFile A_1, TestServiceParam A_2)
            {
                string text = "/Values/uploadFile";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/Values/uploadFile";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpMultipartFormRequestContent feignClientHttpMultipartFormRequestContent = new FeignClientHttpMultipartFormRequestContent();
                FeignClientHttpRequestContent content = new FeignClientHttpFileRequestContent("file", A_1);
                feignClientHttpMultipartFormRequestContent.AddContent("file", content);
                FeignClientHttpRequestContent content2 = new FeignClientHttpFormRequestContent<TestServiceParam>("param", A_2);
                feignClientHttpMultipartFormRequestContent.AddContent("param", content2);
                FeignClientHttpRequestContent requestContent = feignClientHttpMultipartFormRequestContent;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.UploadFileAsync(IHttpRequestFile, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_F32799B3B1C14C489846B440A4A6DCD4 @object = new ITestService_F32799B3B1C14C489846B440A4A6DCD4(base.Fallback, A_1, A_2);
                Func<Task<string>> fallback = new Func<Task<string>>(@object.UploadFileAsync);
                return base.SendAsync<string>(request, fallback);
            }
    
            // Token: 0x06000007 RID: 7 RVA: 0x00002FAC File Offset: 0x000011AC
            public Task<string> UploadFileAsync(IHttpRequestFile A_1, string A_2)
            {
                string text = "/Values/uploadFile";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/Values/uploadFile";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpMultipartFormRequestContent feignClientHttpMultipartFormRequestContent = new FeignClientHttpMultipartFormRequestContent();
                FeignClientHttpRequestContent content = new FeignClientHttpFileRequestContent("file", A_1);
                feignClientHttpMultipartFormRequestContent.AddContent("file", content);
                FeignClientHttpRequestContent content2 = new FeignClientHttpFormRequestContent<string>("name", A_2);
                feignClientHttpMultipartFormRequestContent.AddContent("name", content2);
                FeignClientHttpRequestContent requestContent = feignClientHttpMultipartFormRequestContent;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.UploadFileAsync(IHttpRequestFile, string));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_A8C583A16C3949079BB9E5BCB6209ACE @object = new ITestService_A8C583A16C3949079BB9E5BCB6209ACE(base.Fallback, A_1, A_2);
                Func<Task<string>> fallback = new Func<Task<string>>(@object.UploadFileAsync);
                return base.SendAsync<string>(request, fallback);
            }
    
            // Token: 0x06000008 RID: 8 RVA: 0x00003074 File Offset: 0x00001274
            public Task<string> UploadFileAsync(TestServiceUploadFileParam A_1)
            {
                string text = "/Values/uploadFile";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/Values/uploadFile";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = new FeignClientHttpFileFormRequestContent(A_1);
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.UploadFileAsync(TestServiceUploadFileParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_20E3415B035B4A89B66A6D4BD923F0A2 @object = new ITestService_20E3415B035B4A89B66A6D4BD923F0A2(base.Fallback, A_1);
                Func<Task<string>> fallback = new Func<Task<string>>(@object.UploadFileAsync);
                return base.SendAsync<string>(request, fallback);
            }
    
            // Token: 0x06000009 RID: 9 RVA: 0x000030FC File Offset: 0x000012FC
            public Task<string> FormTestAsync(TestServiceParam A_1)
            {
                string text = "/Values/formTest";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/Values/formTest";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = new FeignClientHttpFormRequestContent<TestServiceParam>("param", A_1);
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.FormTestAsync(TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_2FEEC93AF4DF464F935172779B3FCB64 @object = new ITestService_2FEEC93AF4DF464F935172779B3FCB64(base.Fallback, A_1);
                Func<Task<string>> fallback = new Func<Task<string>>(@object.FormTestAsync);
                return base.SendAsync<string>(request, fallback);
            }
    
            // Token: 0x0600000A RID: 10 RVA: 0x00003188 File Offset: 0x00001388
            public Task<string> UploadFilesAsync(IHttpRequestFile A_1, IHttpRequestFile A_2, IHttpRequestFile A_3)
            {
                string text = "/Values/uploadFiles";
                string baseUrl = this.BaseUrl;
                string mappingUri = "/Values/uploadFiles";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpMultipartFormRequestContent feignClientHttpMultipartFormRequestContent = new FeignClientHttpMultipartFormRequestContent();
                FeignClientHttpRequestContent content = new FeignClientHttpFileRequestContent("file1", A_1);
                feignClientHttpMultipartFormRequestContent.AddContent("file1", content);
                FeignClientHttpRequestContent content2 = new FeignClientHttpFileRequestContent("file2", A_2);
                feignClientHttpMultipartFormRequestContent.AddContent("file2", content2);
                FeignClientHttpRequestContent content3 = new FeignClientHttpFileRequestContent("file3", A_3);
                feignClientHttpMultipartFormRequestContent.AddContent("file3", content3);
                FeignClientHttpRequestContent requestContent = feignClientHttpMultipartFormRequestContent;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.UploadFilesAsync(IHttpRequestFile, IHttpRequestFile, IHttpRequestFile));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_BDAAB91BBC294D7A9A643C222FF7CDF0 @object = new ITestService_BDAAB91BBC294D7A9A643C222FF7CDF0(base.Fallback, A_1, A_2, A_3);
                Func<Task<string>> fallback = new Func<Task<string>>(@object.UploadFilesAsync);
                return base.SendAsync<string>(request, fallback);
            }
    
            // Token: 0x0600000B RID: 11 RVA: 0x00003274 File Offset: 0x00001474
            public Task<QueryResult<JObject>> GetQueryResultValueAsync(string A_1, TestServiceParam A_2)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<string>(text, name, A_1);
                name = "param";
                text = base.ReplaceRequestQuery<TestServiceParam>(text, name, A_2);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "GET";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.GetQueryResultValueAsync(string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_60B9BA54F7BE4F059E71A3FA0B0E99DA @object = new ITestService_60B9BA54F7BE4F059E71A3FA0B0E99DA(base.Fallback, A_1, A_2);
                Func<Task<QueryResult<JObject>>> fallback = new Func<Task<QueryResult<JObject>>>(@object.GetQueryResultValueAsync);
                return base.SendAsync<QueryResult<JObject>>(request, fallback);
            }
    
            // Token: 0x0600000C RID: 12 RVA: 0x00003320 File Offset: 0x00001520
            public QueryResult<JObject> GetQueryResultValue(string A_1, TestServiceParam A_2)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<string>(text, name, A_1);
                name = "param";
                text = base.ReplaceRequestQuery<TestServiceParam>(text, name, A_2);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "GET";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.GetQueryResultValue(string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_B53A91345B5F4218B3B164103A8ADC0D @object = new ITestService_B53A91345B5F4218B3B164103A8ADC0D(base.Fallback, A_1, A_2);
                Func<QueryResult<JObject>> fallback = new Func<QueryResult<JObject>>(@object.GetQueryResultValue);
                return base.Send<QueryResult<JObject>>(request, fallback);
            }
    
            // Token: 0x0600000D RID: 13 RVA: 0x000033CC File Offset: 0x000015CC
            public void GetValueVoid(int A_1, string A_2, TestServiceParam A_3)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "test";
                text = base.ReplaceRequestParam<string>(text, name, A_2);
                name = "param";
                text = base.ReplaceRequestQuery<TestServiceParam>(text, name, A_3);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "GET";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.GetValueVoid(int, string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_39637F2AC6C646519BA9CDBDA1A87290 @object = new ITestService_39637F2AC6C646519BA9CDBDA1A87290(base.Fallback, A_1, A_2, A_3);
                Action fallback = new Action(@object.GetValueVoid);
                base.Send(request, fallback);
            }
    
            // Token: 0x0600000E RID: 14 RVA: 0x00003490 File Offset: 0x00001690
            public Task GetValueVoidAsync(int A_1, string A_2, TestServiceParam A_3)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "test";
                text = base.ReplaceRequestParam<string>(text, name, A_2);
                name = "param";
                text = base.ReplaceRequestQuery<TestServiceParam>(text, name, A_3);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "GET";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.GetValueVoidAsync(int, string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_3F68917A83FF4447A3D850B09069AA08 @object = new ITestService_3F68917A83FF4447A3D850B09069AA08(base.Fallback, A_1, A_2, A_3);
                Func<Task> fallback = new Func<Task>(@object.GetValueVoidAsync);
                return base.SendAsync(request, fallback);
            }
    
            // Token: 0x0600000F RID: 15 RVA: 0x00003554 File Offset: 0x00001754
            public Task PostValueAsync(int A_1, string A_2, TestServiceParam A_3)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "test";
                text = base.ReplaceRequestParam<string>(text, name, A_2);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = new FeignClientHttpJsonRequestContent<TestServiceParam>("param", A_3);
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.PostValueAsync(int, string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_B485C397DD544B24AA11792EE5E285A3 @object = new ITestService_B485C397DD544B24AA11792EE5E285A3(base.Fallback, A_1, A_2, A_3);
                Func<Task> fallback = new Func<Task>(@object.PostValueAsync);
                return base.SendAsync(request, fallback);
            }
    
            // Token: 0x06000010 RID: 16 RVA: 0x00003614 File Offset: 0x00001814
            public Task PostValueFormAsync(int A_1, string A_2, TestServiceParam A_3)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "test";
                text = base.ReplaceRequestParam<string>(text, name, A_2);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = new FeignClientHttpFormRequestContent<TestServiceParam>("param", A_3);
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.PostValueFormAsync(int, string, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_0B34E9A3AF144790983D48B04B98950B @object = new ITestService_0B34E9A3AF144790983D48B04B98950B(base.Fallback, A_1, A_2, A_3);
                Func<Task> fallback = new Func<Task>(@object.PostValueFormAsync);
                return base.SendAsync(request, fallback);
            }
    
            // Token: 0x06000011 RID: 17 RVA: 0x000036D4 File Offset: 0x000018D4
            public Task PostValueForm2Async(int A_1, string A_2, TestServiceParam A_3, TestServiceParam A_4)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "test";
                text = base.ReplaceRequestParam<string>(text, name, A_2);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "POST";
                string contentType = null;
                FeignClientHttpMultipartFormRequestContent feignClientHttpMultipartFormRequestContent = new FeignClientHttpMultipartFormRequestContent();
                FeignClientHttpRequestContent content = new FeignClientHttpFormRequestContent<TestServiceParam>("param1", A_3);
                feignClientHttpMultipartFormRequestContent.AddContent("param1", content);
                FeignClientHttpRequestContent content2 = new FeignClientHttpFormRequestContent<TestServiceParam>("param2", A_4);
                feignClientHttpMultipartFormRequestContent.AddContent("param2", content2);
                FeignClientHttpRequestContent requestContent = feignClientHttpMultipartFormRequestContent;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.PostValueForm2Async(int, string, TestServiceParam, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_231A4252DE2747128CCEE23E62E2CCE0 @object = new ITestService_231A4252DE2747128CCEE23E62E2CCE0(base.Fallback, A_1, A_2, A_3, A_4);
                Func<Task> fallback = new Func<Task>(@object.PostValueForm2Async);
                return base.SendAsync(request, fallback);
            }
    
            // Token: 0x06000012 RID: 18 RVA: 0x000037D0 File Offset: 0x000019D0
            public void GetValueVoid(int A_1, TestServiceParam A_2, TestServiceParam A_3)
            {
                string text = "/{id}";
                string name = "id";
                text = base.ReplacePathVariable<int>(text, name, A_1);
                name = "queryParam";
                text = base.ReplaceRequestParam<TestServiceParam>(text, name, A_2);
                name = "param";
                text = base.ReplaceRequestQuery<TestServiceParam>(text, name, A_3);
                string baseUrl = this.BaseUrl;
                string mappingUri = "/{id}";
                string uri = text;
                string httpMethod = "GET";
                string contentType = null;
                FeignClientHttpRequestContent requestContent = null;
                MethodInfo method = null;
                if (base.FeignOptions.IncludeMethodMetadata)
                {
                    method = methodof(ITestService.GetValueVoid(int, TestServiceParam, TestServiceParam));
                }
                FeignClientHttpRequest request = new FeignClientHttpRequest(baseUrl, mappingUri, uri, httpMethod, contentType, requestContent, method);
                ITestService_A1609C56DF7E43209BF87431714D47CB @object = new ITestService_A1609C56DF7E43209BF87431714D47CB(base.Fallback, A_1, A_2, A_3);
                Action fallback = new Action(@object.GetValueVoid);
                base.Send(request, fallback);
            }
        }
    Proxy Service

    接下来测试一下

        [EditorBrowsable(EditorBrowsableState.Never)]
        public static class FeignBuilderExtensions
        {
    
            public static TFeignBuilder AddFeignClients<TFeignBuilder>(this TFeignBuilder feignBuilder, IFeignOptions options) where TFeignBuilder : IFeignBuilder
            {
                if (options.Assemblies.Count == 0)
                {
                    feignBuilder.AddFeignClients(Assembly.GetEntryAssembly(), options.Lifetime);
                }
                else
                {
                    foreach (var assembly in options.Assemblies)
                    {
                        feignBuilder.AddFeignClients(assembly, options.Lifetime);
                    }
                }
                feignBuilder.AddLoggerFactory<DefaultLoggerFactory>();
                feignBuilder.AddCacheProvider<DefaultCacheProvider>();
                feignBuilder.AddServiceDiscovery<DefaultServiceDiscovery>();
                feignBuilder.AddService<IFeignOptions>(options);
                return feignBuilder;
            }
    
            public static TFeignBuilder AddFeignClients<TFeignBuilder>(this TFeignBuilder feignBuilder, Assembly assembly, FeignClientLifetime lifetime)
        where TFeignBuilder : IFeignBuilder
            {
                if (assembly == null)
                {
                    return feignBuilder;
                }
                foreach (var serviceType in assembly.GetTypes())
                {
                    FeignClientTypeInfo feignClientTypeInfo = feignBuilder.TypeBuilder.Build(serviceType);
                    if (feignClientTypeInfo == null || feignClientTypeInfo.BuildType == null)
                    {
                        continue;
                    }
                    FeignClientAttribute feignClientAttribute = serviceType.GetCustomAttribute<FeignClientAttribute>();
                    feignBuilder.AddService(serviceType, feignClientTypeInfo.BuildType, feignClientAttribute.Lifetime ?? lifetime);
                    // add fallback
                    if (feignClientAttribute.Fallback != null)
                    {
                        feignBuilder.AddService(feignClientAttribute.Fallback, feignClientAttribute.Lifetime ?? lifetime);
                    }
                    if (feignClientAttribute.FallbackFactory != null)
                    {
                        feignBuilder.AddService(feignClientAttribute.FallbackFactory, feignClientAttribute.Lifetime ?? lifetime);
                    }
                }
                return feignBuilder;
            }
    
    
            public static IFeignBuilder AddConverter<TSource, TResult>(this IFeignBuilder feignBuilder, IConverter<TSource, TResult> converter)
            {
                feignBuilder.Options.Converters.AddConverter(converter);
                return feignBuilder;
            }
    
            public static IFeignBuilder AddLoggerFactory<TLoggerFactory>(this IFeignBuilder feignBuilder) where TLoggerFactory : ILoggerFactory
            {
                feignBuilder.AddOrUpdateService(typeof(ILoggerFactory), typeof(TLoggerFactory), FeignClientLifetime.Singleton);
                return feignBuilder;
            }
    
    
            public static IFeignBuilder AddServiceDiscovery<TServiceDiscovery>(this IFeignBuilder feignBuilder) where TServiceDiscovery : IServiceDiscovery
            {
                feignBuilder.AddOrUpdateService(typeof(IServiceDiscovery), typeof(TServiceDiscovery), FeignClientLifetime.Singleton);
                return feignBuilder;
            }
    
            public static IFeignBuilder AddCacheProvider<TCacheProvider>(this IFeignBuilder feignBuilder) where TCacheProvider : ICacheProvider
            {
                feignBuilder.AddOrUpdateService(typeof(ICacheProvider), typeof(TCacheProvider), FeignClientLifetime.Singleton);
                return feignBuilder;
            }
    
        }   
    
     [EditorBrowsable(EditorBrowsableState.Never)]
        public static class ServiceCollectionExtensions
        {
    
            public static IDependencyInjectionFeignBuilder AddFeignClients(this IServiceCollection services)
            {
                return AddFeignClients(services, (FeignOptions)null);
            }
    
            public static IDependencyInjectionFeignBuilder AddFeignClients(this IServiceCollection services, Action<IFeignOptions> setupAction)
            {
                FeignOptions options = new FeignOptions();
                setupAction?.Invoke(options);
                return AddFeignClients(services, options);
            }
    
            public static IDependencyInjectionFeignBuilder AddFeignClients(this IServiceCollection services, IFeignOptions options)
            {
                if (options == null)
                {
                    options = new FeignOptions();
                }
    
                DependencyInjectionFeignBuilder feignBuilder = new DependencyInjectionFeignBuilder();
                feignBuilder.Services = services;
                feignBuilder.Options = options;
                feignBuilder.AddFeignClients(options)
                    .AddLoggerFactory<LoggerFactory>()
                    .AddCacheProvider<CacheProvider>()
                    ;
                return feignBuilder;
            }
    
    
        }
    AddFeignClients
    public static class FeignExtensions
        {
    
            public static IFeignBuilder AddTestFeignClients(this IFeignBuilder feignBuilder)
            {
                feignBuilder.AddServiceDiscovery<TestServiceDiscovery>();
                feignBuilder.Options.IncludeMethodMetadata = true;
                feignBuilder.AddFeignClients(Assembly.GetExecutingAssembly(), FeignClientLifetime.Transient);
                feignBuilder.Options.FeignClientPipeline.Service<ITestService>().SendingRequest += (sender, e) =>
                {
                    //e.Terminate();
                };
                feignBuilder.Options.FeignClientPipeline.FallbackRequest += (sender, e) =>
                {
                    var parameters = e.GetParameters();
                    object fallback = e.Fallback;
                    IFallbackProxy fallbackProxy = e.FallbackProxy;
                    if (fallbackProxy == null)
                    {
                        string s = "";
                    }
                    MethodInfo method = e.Method;
                    e.Terminate();
                };
                feignBuilder.Options.FeignClientPipeline.Initializing += (sender, e) =>
                {
    
                };
                feignBuilder.Options.FeignClientPipeline.Service("yun-platform-service-provider").Initializing += (sender, e) =>
                {
    
                };
                feignBuilder.Options.FeignClientPipeline.Disposing += (sender, e) =>
                {
    
                };
                feignBuilder.Options.FeignClientPipeline.Authorization(proxy =>
                {
    #if NETSTANDARD
                    return ("global", "asdasd");
    #else
                                return new AuthenticationHeaderValue("global", "asdasd");
    #endif
                });
                feignBuilder.Options.FeignClientPipeline.BuildingRequest += FeignClientPipeline_BuildingRequest;
                feignBuilder.Options.FeignClientPipeline.Service<ITestService>().BuildingRequest += (sender, e) =>
                {
                    IFeignClient<ITestService> feignClient = e.FeignClient as IFeignClient<ITestService>;
                    ITestService service = feignClient.Service;
                };
                feignBuilder.Options.FeignClientPipeline.Service("yun-platform-service-provider").BuildingRequest += (sender, e) =>
                {
                    var fallbackFeignClient = e.FeignClient.AsFallback();
                    fallbackFeignClient = e.FeignClient.AsFallback<object>();
                    fallbackFeignClient = e.FeignClient.AsFallback<ITestService>();
    
                    var fallback = fallbackFeignClient?.Fallback;
    
                    fallback = e.FeignClient.GetFallback();
                    fallback = e.FeignClient.GetFallback<object>();
                    //     fallback = e.FeignClient.GetFallback<ITestService>();
    
                    if (!e.Headers.ContainsKey("Authorization"))
                    {
                        e.Headers["Authorization"] = "service asdasd";
                    }
                    e.Headers["Accept-Encoding"] = "gzip, deflate, br";
    
                    //add session
                    e.Headers.Add("cookie", "csrftoken=EGxYkyZeT3DxEsvYsdR5ncmzpi9pmnQx; _bl_uid=nLjRstOyqOejLv2s0xtzqs74Xsmg; courseId=1; versionId=522; textbookId=2598; Hm_lvt_f0984c42ef98965e03c60661581cd219=1559783251,1559818390,1560213044,1560396804; uuid=6a30ff68-2b7c-4cde-a355-2e332b74e31d##1; Hm_lpvt_f0984c42ef98965e03c60661581cd219=1560413345; SESSION=5ee4854d-34b7-423a-9cca-76ddc8a0f111; sid=5ee4854d-34b7-423a-9cca-76ddc8a0f111");
    
                };
                feignBuilder.Options.FeignClientPipeline.Service<ITestService>().Authorization(proxy =>
                {
    #if NETSTANDARD
                    return ("service", "asdasd");
    #else
                    return new AuthenticationHeaderValue("service", "asdasd");
    #endif
                });
                feignBuilder.Options.FeignClientPipeline.SendingRequest += FeignClientPipeline_SendingRequest;
                feignBuilder.Options.FeignClientPipeline.Service("yun-platform-service-provider").ReceivingResponse += (sender, e) =>
                {
    
                };
                feignBuilder.Options.FeignClientPipeline.ReceivingQueryResult();
                feignBuilder.Options.FeignClientPipeline.CancelRequest += (sender, e) =>
                {
                    e.CancellationToken.Register((state) =>
                    {
    
                    }, sender);
                };
                feignBuilder.Options.FeignClientPipeline.ErrorRequest += (sender, e) =>
                {
                    Exception exception = e.Exception;
                    //e.ExceptionHandled = true;
                };
                return feignBuilder;
            }
    
            private static void FeignClientPipeline_BuildingRequest(object sender, IBuildingRequestEventArgs<object> e)
            {
            }
    
            private static void FeignClientPipeline_SendingRequest(object sender, ISendingRequestEventArgs<object> e)
            {
                //e.Terminate();
            }
    
    
            public static void ReceivingQueryResult(this IGlobalFeignClientPipeline globalFeignClient)
            {
                globalFeignClient.ReceivingResponse += (sender, e) =>
                {
                    if (!typeof(QueryResult).IsAssignableFrom(e.ResultType))
                    {
                        return;
                    }
                    if (e.ResultType == typeof(QueryResult))
                    {
                        e.Result = new QueryResult()
                        {
                            StatusCode = e.ResponseMessage.StatusCode
                        };
                        return;
                    }
    
                    if (e.ResultType.IsGenericType && e.ResultType.GetGenericTypeDefinition() == typeof(QueryResult<>))
                    {
                        QueryResult queryResult;
                        if (e.ResponseMessage.IsSuccessStatusCode)
                        {
                            string json = e.ResponseMessage.Content.ReadAsStringAsync().Result;
                            object data = Newtonsoft.Json.JsonConvert.DeserializeObject(json, e.ResultType.GetGenericArguments()[0]);
                            if (data == null)
                            {
                                queryResult = InvokeQueryResultConstructor(e.ResultType.GetGenericArguments()[0]);
                            }
                            else
                            {
                                queryResult = InvokeQueryResultConstructor(data.GetType(), data);
                            }
                        }
                        else
                        {
                            queryResult = InvokeQueryResultConstructor(e.ResultType.GetGenericArguments()[0]);
                        }
                        queryResult.StatusCode = e.ResponseMessage.StatusCode;
                        e.Result = queryResult;
                    }
    
                };
            }
    
            static readonly System.Collections.Concurrent.ConcurrentDictionary<Type, Func<object, QueryResult>> _newQueryResultMap = new System.Collections.Concurrent.ConcurrentDictionary<Type, Func<object, QueryResult>>();
    
            static Func<QueryResult> _queryResultFunc;
    
            static QueryResult InvokeQueryResultConstructor(Type type, object value)
            {
                Func<object, QueryResult> func = _newQueryResultMap.GetOrAdd(type, key =>
                {
                    Type queryResultType = typeof(QueryResult<>).MakeGenericType(key);
                    ConstructorInfo constructor = queryResultType.GetConstructor(new Type[] { key });
                    ParameterExpression parameter = Expression.Parameter(typeof(object));
                    NewExpression constructorExpression = Expression.New(constructor, Expression.Convert(parameter, key));
                    return Expression.Lambda<Func<object, QueryResult>>(constructorExpression, parameter).Compile();
                });
                return func.Invoke(value);
            }
    
            static QueryResult InvokeQueryResultConstructor(Type type)
            {
                if (_queryResultFunc == null)
                {
                    Type queryResultType = typeof(QueryResult<>).MakeGenericType(type);
                    ConstructorInfo constructor = queryResultType.GetConstructor(Type.EmptyTypes);
                    NewExpression constructorExpression = Expression.New(constructor);
                    _queryResultFunc = Expression.Lambda<Func<QueryResult>>(constructorExpression).Compile();
                }
                return _queryResultFunc.Invoke();
            }
    
        }
    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";
            }
    
        }

    正常工作了! 

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

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

  • 相关阅读:
    GNU make manual 翻译( 一百五十)
    [导入]Google开发者日见闻 王开源现身
    [导入]微软中国原高管宫力就任火狐中国总经理
    [导入]QQTalk Beta1 简体中文版
    [导入]《南方都市报》:国产龙芯产业化 难
    [导入][多图]Nokia正式发布奢华8600/6500双子手机
    [导入]用户界面设计的技巧与技术
    [导入]BitComet(比特彗星) 0.89
    [导入]µTorrent 1.7 beta 2248
    今天我注册了
  • 原文地址:https://www.cnblogs.com/pokemon/p/11412051.html
Copyright © 2020-2023  润新知