/// <summary> /// 设置验证失败结果 /// </summary> /// <param name="context">动作方法执行上下文</param> /// <param name="modelState">模型验证状态</param> /// <param name="actionDescriptor"></param> private static void SetValidateFailedResult(ActionExecutingContext context, ModelStateDictionary modelState, ControllerActionDescriptor actionDescriptor) { // 将验证错误信息转换成字典并序列化成 Json var validationResults = modelState.ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage)); var validateFaildMessage = JsonSerializerUtility.Serialize(validationResults); // 判断是否跳过规范化结果 if (UnifyResultContext.IsSkipUnifyHandler(actionDescriptor.MethodInfo, out var unifyResult)) { // 返回 400 错误 var result = new BadRequestObjectResult(modelState); // 设置返回的响应类型 result.ContentTypes.Add(MediaTypeNames.Application.Json); result.ContentTypes.Add(MediaTypeNames.Application.Xml); context.Result = result; } else { context.Result = unifyResult.OnValidateFailed(context, modelState, validationResults, validateFaildMessage); } // 打印验证失败信息 App.PrintToMiniProfiler(MiniProfilerCategory, "Failed", $"Validation Failed:\r\n{validateFaildMessage}", true); }
/// <summary> /// 输出验证信息 /// </summary> /// <param name="errors"></param> /// <returns></returns> internal static (Dictionary <string, IEnumerable <string> > validationResults, string validateFaildMessage, ModelStateDictionary modelState) OutputValidationInfo(object errors) { ModelStateDictionary _modelState = null; Dictionary <string, IEnumerable <string> > validationResults = null; // 如果是模型验证字典类型 if (errors is ModelStateDictionary modelState) { _modelState = modelState; // 将验证错误信息转换成字典并序列化成 Json validationResults = modelState.ToDictionary(u => !JsonSerializerUtility.EnabledPascalPropertyNaming ? u.Key.ToTitlePascal() : u.Key , u => modelState[u.Key].Errors.Select(c => c.ErrorMessage)); } // 如果是 ValidationProblemDetails 特殊类型 else if (errors is ValidationProblemDetails validation) { validationResults = validation.Errors.ToDictionary(u => !JsonSerializerUtility.EnabledPascalPropertyNaming ? u.Key.ToTitlePascal() : u.Key , u => u.Value.AsEnumerable()); } // 其他类型 else { validationResults = new Dictionary <string, IEnumerable <string> > { { string.Empty, new[] { errors?.ToString() } } } }; // 序列化 var validateFaildMessage = JsonSerializerUtility.Serialize(validationResults); return(validationResults, validateFaildMessage, _modelState); } }
/// <summary> /// 设置请求体 /// </summary> /// <param name="httpMethodAttribute"></param> /// <param name="methodParameters"></param> /// <param name="request"></param> private static void SetHttpRequestBody(HttpMethodAttribute httpMethodAttribute, Dictionary <string, ParameterValue> methodParameters, HttpRequestMessage request) { // 排除 GET/Head 请求 if (httpMethodAttribute.Method == HttpMethod.Get || httpMethodAttribute.Method == HttpMethod.Head) { return; } // 获取所有非基元类型,该类型当作 Body 参数 var bodyParameters = methodParameters.Where(u => u.Value.IsBodyParameter); if (bodyParameters.Any()) { // 获取 body 参数 var bodyArgs = bodyParameters.First().Value.Value; string body; // 处理 json 类型 if (httpMethodAttribute.ContentType.Contains("json")) { body = JsonSerializerUtility.Serialize(bodyArgs); } // 处理 xml 类型 else if (httpMethodAttribute.ContentType.Contains("xml")) { var xmlSerializer = new XmlSerializer(bodyArgs.GetType()); var buffer = new StringBuilder(); using var writer = new StringWriter(buffer); xmlSerializer.Serialize(writer, bodyArgs); body = buffer.ToString(); } // 其他类型 else { body = bodyArgs.ToString(); } if (!string.IsNullOrEmpty(body)) { var httpContent = new StringContent(body, Encoding.UTF8); // 设置内容类型 httpContent.Headers.ContentType = new MediaTypeHeaderValue(httpMethodAttribute.ContentType); request.Content = httpContent; // 打印请求地址 App.PrintToMiniProfiler(MiniProfilerCategory, "Body", body); } } }
/// <summary> /// 如果有异常则抛出 /// </summary> /// <param name="dataValidationResult"></param> public static void AddError(this DataValidationResult dataValidationResult) { if (!dataValidationResult.IsValid) { throw Oops.Oh("[Validation]" + JsonSerializerUtility.Serialize( dataValidationResult.ValidationResults .Select(u => new { MemberNames = u.MemberNames.Any() ? u.MemberNames : new[] { $"{dataValidationResult.MemberOrValue}" }, u.ErrorMessage }) .OrderBy(u => u.MemberNames.First()) .GroupBy(u => u.MemberNames.First()) .ToDictionary(u => u.Key, u => u.Select(c => c.ErrorMessage)))); } }
/// <summary> /// 发送 Http 请求 /// </summary> /// <param name="requestUri"></param> /// <param name="httpMethod"></param> /// <param name="bodyArgs"></param> /// <param name="headers"></param> /// <param name="clientName"></param> /// <param name="interceptor"></param> /// <param name="contentType">contentType</param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task <HttpResponseMessage> SendAsync(this string requestUri, HttpMethod httpMethod = default, object bodyArgs = null, Dictionary <string, string> headers = default, string clientName = default, Action <HttpRequestMessage> interceptor = default, string contentType = "application/json", CancellationToken cancellationToken = default) { // 检查 Url 地址是否有效 var result = requestUri.TryValidate(ValidationTypes.Url); if (!result.IsValid) { throw new InvalidOperationException($"{requestUri} is not a valid url address."); } // 检查 method if (httpMethod == null) { throw new ArgumentNullException(nameof(httpMethod)); } // 创建请求对象 var request = new HttpRequestMessage(httpMethod, requestUri); // 设置请求报文头 if (headers != null && headers.Count > 0) { foreach (var header in headers) { request.Headers.Add(header.Key, header.Value); } } // 设置请求报文参数,排除Get和Head请求 if (httpMethod != HttpMethod.Get && httpMethod != HttpMethod.Head && bodyArgs != null) { string body; // 处理 json 类型 if (contentType.Contains("json")) { body = JsonSerializerUtility.Serialize(bodyArgs); } // 处理 xml 类型 else if (contentType.Contains("xml")) { var xmlSerializer = new XmlSerializer(bodyArgs.GetType()); var buffer = new StringBuilder(); using var writer = new StringWriter(buffer); xmlSerializer.Serialize(writer, bodyArgs); body = buffer.ToString(); } // 其他类型 else { body = bodyArgs.ToString(); } if (!string.IsNullOrEmpty(body)) { var httpContent = new StringContent(body, Encoding.UTF8); // 设置内容类型 httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); request.Content = httpContent; // 打印请求地址 App.PrintToMiniProfiler(MiniProfilerCategory, "Body", body); } } // 请求之前拦截 interceptor?.Invoke(request); // 打印请求地址 App.PrintToMiniProfiler(MiniProfilerCategory, "Beginning", $"{request.Method} {request.RequestUri.AbsoluteUri}"); // 创建 HttpClient 对象 var clientFactory = App.GetService <IHttpClientFactory>(); if (clientFactory == null) { throw new ArgumentNullException("Please register for RemoteRequest service first: services.AddRemoteRequest();"); } var httpClient = string.IsNullOrEmpty(clientName) ? clientFactory.CreateClient() : clientFactory.CreateClient(clientName); // 发送请求 var response = await httpClient.SendAsync(request, cancellationToken); if (response.IsSuccessStatusCode) { return(response); } else { // 读取错误数据 var errorMessage = await response.Content.ReadAsStringAsync(cancellationToken); // 打印失败消息 App.PrintToMiniProfiler(MiniProfilerCategory, "Failed", errorMessage, isError: true); // 抛出请求异常 throw new HttpRequestException(errorMessage); } }
/// <summary> /// 设置方法体 /// </summary> /// <param name="request"></param> /// <param name="bodyArgs"></param> /// <param name="bodyContentTypeOptions"></param> /// <param name="jsonNamingPolicyOptions"></param> /// <param name="contentType"></param> internal static void SetHttpRequestBody(HttpRequestMessage request, object bodyArgs, HttpContentTypeOptions bodyContentTypeOptions, JsonNamingPolicyOptions jsonNamingPolicyOptions, string contentType) { // 处理 body 内容 HttpContent httpContent; switch (bodyContentTypeOptions) { case HttpContentTypeOptions.StringContent: case HttpContentTypeOptions.JsonStringContent: case HttpContentTypeOptions.XmlStringContent: string bodyContent; // application/json;text/json;application/*+json if (bodyContentTypeOptions == HttpContentTypeOptions.JsonStringContent) { // 配置 Json 命名策略 var jsonSerializerOptions = JsonSerializerUtility.GetDefaultJsonSerializerOptions(); jsonSerializerOptions.PropertyNamingPolicy = jsonNamingPolicyOptions switch { JsonNamingPolicyOptions.CamelCase => JsonNamingPolicy.CamelCase, JsonNamingPolicyOptions.Null => null, _ => null }; bodyContent = JsonSerializerUtility.Serialize(bodyArgs, jsonSerializerOptions); } // application/xml;text/xml;application/*+xml else if (bodyContentTypeOptions == HttpContentTypeOptions.XmlStringContent) { var xmlSerializer = new XmlSerializer(bodyArgs.GetType()); var buffer = new StringBuilder(); using var writer = new StringWriter(buffer); xmlSerializer.Serialize(writer, bodyArgs); bodyContent = buffer.ToString(); } // none else { bodyContent = bodyArgs.ToString(); } httpContent = new StringContent(bodyContent, Encoding.UTF8); break; // 处理 x-www-form-urlencoded case HttpContentTypeOptions.FormUrlEncodedContent: Dictionary <string, string> formDataDic = new(); if (bodyArgs is Dictionary <string, string> dic) { formDataDic = dic; } else { var bodyArgsType = bodyArgs.GetType(); // 只有类和匿名类才处理 if (bodyArgsType.IsClass || bodyArgsType.IsAnonymous()) { var properties = bodyArgsType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { formDataDic.Add(prop.Name, prop.GetValue(bodyArgs)?.ToString()); } } } httpContent = new FormUrlEncodedContent(formDataDic); break; // 处理 multipart/form-data case HttpContentTypeOptions.MultipartFormDataContent: default: throw new NotImplementedException("Please use RequestInterceptor to set."); } // 设置内容 if (httpContent != null) { httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); request.Content = httpContent; } }