打造适用于c#的feign

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

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

 

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

   

打造适用于c#的feign
    /// <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为服务的生命周期

打造适用于c#的feign
    /// <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

打造适用于c#的feign
   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等

打造适用于c#的feign
    [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等

 

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

打造适用于c#的feign
    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父类

 

打造适用于c#的feign
    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

 

打造适用于c#的feign
    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

打造适用于c#的feign
        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

 构造函数

 

打造适用于c#的feign
        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

 重写父类只读属性

 

打造适用于c#的feign
 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);
            }

 

打造适用于c#的feign
    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

 

 最后看看效果

 声明的服务

打造适用于c#的feign
 [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代码

打造适用于c#的feign
// 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

 

接下来测试一下

打造适用于c#的feign
    [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

 

打造适用于c#的feign
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";
        }

    }

 

打造适用于c#的feign

正常工作了! 

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

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

 

打造适用于c#的feign

上一篇:Windbg and resources leaks in .NET applications 资源汇总


下一篇:WPF DataGrid获取单元格