context.Services.AddHttpClientProxies( typeof(IdentityApplicationContractsModule).Assembly, //接口层程序集 RemoteServiceName //远程服务名称 ); public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string remoteServiceConfigurationName = "Default", bool asDefaultService = true) { /*省略一些代码...*/ Type type2 = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type); //拦截器 services.AddTransient(type2); Type interceptorAdapterType = typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(type2); Type validationInterceptorAdapterType = typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(typeof(ValidationInterceptor)); if (asDefaultService) { //生成代理,依赖注入到容器 services.AddTransient(type, (IServiceProvider serviceProvider) => ProxyGeneratorInstance.CreateInterfaceProxyWithoutTarget(type, (IInterceptor)serviceProvider.GetRequiredService(validationInterceptorAdapterType), (IInterceptor)serviceProvider.GetRequiredService(interceptorAdapterType))); } services.AddTransient(typeof(IHttpClientProxy<>).MakeGenericType(type), delegate (IServiceProvider serviceProvider) { //生成代理,通过HttpClientProxy封装,依赖注入到容器 object obj = ProxyGeneratorInstance.CreateInterfaceProxyWithoutTarget(type, (IInterceptor)serviceProvider.GetRequiredService(validationInterceptorAdapterType), (IInterceptor)serviceProvider.GetRequiredService(interceptorAdapterType)); return Activator.CreateInstance(typeof(HttpClientProxy<>).MakeGenericType(type), obj); }); return services; }
public override async Task InterceptAsync(IAbpMethodInvocation invocation) { var context = new ClientProxyRequestContext( await GetActionApiDescriptionModel(invocation), //获取Api描述信息 invocation.ArgumentsDictionary, typeof(TService)); if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) { await InterceptorClientProxy.CallRequestAsync(context); } else { var returnType = invocation.Method.ReturnType.GenericTypeArguments[0]; var result = (Task)CallRequestAsyncMethod .MakeGenericMethod(returnType) .Invoke(this, new object[] { context }); invocation.ReturnValue = await GetResultAsync(result, returnType); //调用CallRequestAsync泛型方法 } }
protected virtual async Task<ActionApiDescriptionModel> GetActionApiDescriptionModel(IAbpMethodInvocation invocation) { var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(typeof(TService)) ?? //获取远程服务名称 throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}."); var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName);//获取远程服务端点配置 var client = HttpClientFactory.Create(clientConfig.RemoteServiceName); //创建HttpClient return await ApiDescriptionFinder.FindActionAsync( client, remoteServiceConfig.BaseUrl, //远程服务地址 typeof(TService), invocation.Method ); }
"RemoteServices": { "Default": { "BaseUrl": "http://localhost:44388" }, "XXXDemo":{ "BaseUrl": "http://localhost:44345" } },
public async Task<ActionApiDescriptionModel> FindActionAsync( HttpClient client, string baseUrl, Type serviceType, MethodInfo method) { var apiDescription = await GetApiDescriptionAsync(client, baseUrl); //获取Api描述信息并缓存结果 //TODO: Cache finding? var methodParameters = method.GetParameters().ToArray(); foreach (var module in apiDescription.Modules.Values) { foreach (var controller in module.Controllers.Values) { if (!controller.Implements(serviceType)) //不继承接口跳过,所以写控制器为什么需要要继承服务接口的作用之一便在于此 { continue; } foreach (var action in controller.Actions.Values) { if (action.Name == method.Name && action.ParametersOnMethod.Count == methodParameters.Length) //签名是否匹配 { /*省略部分代码 */ } } } } throw new AbpException($"Could not found remote action for method: {method} on the URL: {baseUrl}"); } public virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(HttpClient client, string baseUrl) { return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(client, baseUrl)); //缓存结果 }
protected virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionFromServerAsync( HttpClient client, string baseUrl) { //构造请求信息 var requestMessage = new HttpRequestMessage( HttpMethod.Get, baseUrl.EnsureEndsWith('/') + "api/abp/api-definition" ); AddHeaders(requestMessage); //添加请求头 var response = await client.SendAsync( //发送请求并获取响应结果 requestMessage, CancellationTokenProvider.Token ); if (!response.IsSuccessStatusCode) { throw new AbpException("Remote service returns error! StatusCode = " + response.StatusCode); } var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(content, DeserializeOptions); return result; }
public virtual async Task<T> CallRequestAsync<T>(ClientProxyRequestContext requestContext) { return await base.RequestAsync<T>(requestContext); } public virtual async Task<HttpContent> CallRequestAsync(ClientProxyRequestContext requestContext) { return await base.RequestAsync(requestContext); }
protected virtual async Task<HttpContent> RequestAsync(ClientProxyRequestContext requestContext) { //获取远程服务名称 var clientConfig = ClientOptions.Value.HttpClientProxies.GetOrDefault(requestContext.ServiceType) ?? throw new AbpException($"Could not get HttpClientProxyConfig for {requestContext.ServiceType.FullName}."); //获取远程服务端点配置 var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); var client = HttpClientFactory.Create(clientConfig.RemoteServiceName); var apiVersion = await GetApiVersionInfoAsync(requestContext); //获取API版本 var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + await GetUrlWithParametersAsync(requestContext, apiVersion); //拼接完整的url var requestMessage = new HttpRequestMessage(requestContext.Action.GetHttpMethod(), url) //构造HTTP请求信息 { Content = await ClientProxyRequestPayloadBuilder.BuildContentAsync(requestContext.Action, requestContext.Arguments, JsonSerializer, apiVersion) }; AddHeaders(requestContext.Arguments, requestContext.Action, requestMessage, apiVersion); //添加请求头 if (requestContext.Action.AllowAnonymous != true) //是否需要认证 { await ClientAuthenticator.Authenticate( //认证 new RemoteServiceHttpClientAuthenticateContext( client, requestMessage, remoteServiceConfig, clientConfig.RemoteServiceName ) ); } HttpResponseMessage response; try { response = await client.SendAsync( //发送请求 requestMessage, HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/, GetCancellationToken(requestContext.Arguments) ); } return response.Content; }
public override async Task Authenticate(RemoteServiceHttpClientAuthenticateContext context) { if (context.RemoteService.GetUseCurrentAccessToken() != false) { var accessToken = await GetAccessTokenFromHttpContextOrNullAsync(); //获取当前登录用户Token if (accessToken != null) { context.Request.SetBearerToken(accessToken); return; } } await base.Authenticate(context); }
[DependsOn(typeof(AbpHttpClientIdentityModelWebModule))]
"UseCurrentAccessToken": "true" } }
protected virtual void AddHeaders( IReadOnlyDictionary<string, object> argumentsDictionary, ActionApiDescriptionModel action, HttpRequestMessage requestMessage, ApiVersionInfo apiVersion) { /*省略代码/* //TenantId if (CurrentTenant.Id.HasValue) { //TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); } /*省略代码/* }
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(IIdentityRoleAppService), typeof(IdentityRoleClientProxy))] public partial class IdentityRoleClientProxy : ClientProxyBase<IIdentityRoleAppService>, IIdentityRoleAppService { public virtual async Task<ListResultDto<IdentityRoleDto>> GetAllListAsync() { return await RequestAsync<ListResultDto<IdentityRoleDto>>(nameof(GetAllListAsync)); } } protected virtual async Task RequestAsync(string methodName, ClientProxyRequestTypeValue arguments = null) { await RequestAsync(BuildHttpProxyClientProxyContext(methodName, arguments)); }
protected virtual ClientProxyRequestContext BuildHttpProxyClientProxyContext(string methodName, ClientProxyRequestTypeValue arguments = null) { if (arguments == null) { arguments = new ClientProxyRequestTypeValue(); } var methodUniqueName = $"{typeof(TService).FullName}.{methodName}.{string.Join("-", arguments.Values.Select(x => TypeHelper.GetFullNameHandlingNullableAndGenerics(x.Key)))}"; var action = ClientProxyApiDescriptionFinder.FindAction(methodUniqueName); //获取调用方法的API描述信息 if (action == null) { throw new AbpException($"The API description of the {typeof(TService).FullName}.{methodName} method was not found!"); } var actionArguments = action.Parameters.GroupBy(x => x.NameOnMethod).ToList(); if (action.SupportedVersions.Any()) { //TODO: make names configurable actionArguments.RemoveAll(x => x.Key == "api-version" || x.Key == "apiVersion"); } return new ClientProxyRequestContext( //封装未远程调用上下文 action, actionArguments .Select((x, i) => new KeyValuePair<string, object>(x.Key, arguments.Values[i].Value)) .ToDictionary(x => x.Key, x => x.Value), typeof(TService)); }
private ApplicationApiDescriptionModel GetApplicationApiDescriptionModel() { var applicationApiDescription = ApplicationApiDescriptionModel.Create(); var fileInfoList = new List<IFileInfo>(); GetGenerateProxyFileInfos(fileInfoList); foreach (var fileInfo in fileInfoList) { using (var streamReader = new StreamReader(fileInfo.CreateReadStream())) { var content = streamReader.ReadToEnd(); var subApplicationApiDescription = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(content); foreach (var module in subApplicationApiDescription.Modules) { if (!applicationApiDescription.Modules.ContainsKey(module.Key)) { applicationApiDescription.AddModule(module.Value); } } } } return applicationApiDescription; } private void GetGenerateProxyFileInfos(List<IFileInfo> fileInfoList, string path = "") { foreach (var directoryContent in VirtualFileProvider.GetDirectoryContents(path)) { if (directoryContent.IsDirectory) { GetGenerateProxyFileInfos(fileInfoList, directoryContent.PhysicalPath); } else { if (directoryContent.Name.EndsWith("generate-proxy.json")) { fileInfoList.Add(VirtualFileProvider.GetFileInfo(directoryContent.GetVirtualOrPhysicalPathOrNull())); } } } }