打造适用于c#的feign

  • 2019 年 10 月 3 日
  • 筆記

  之前因为工作原因使用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