internal static bool CreateContentObjectIfSpecified(BodyAttribute bodyAttr, ParameterInfo bodyParam, StringBuilder clasStringBuilder) { if (bodyAttr == null || bodyParam == null) { return(false); } var format = bodyAttr.Format; if (format == Format.Auto) { format = typeof(Stream).IsAssignableFrom(bodyParam.ParameterType) ? Format.Raw : Format.Json; } // Format.Auto is handled above. At this point it is always Format.Raw or Format.Json // ReSharper disable once SwitchStatementMissingSomeCases switch (format) { case Format.Json: clasStringBuilder.AppendLine($" var content = ConvertToJson({bodyParam.Name});"); break; case Format.Raw: clasStringBuilder.AppendLine($" var content = StreamRawContent({bodyParam.Name});"); break; default: return(false); } return(true); }
internal static void ReturnContentObject(BodyAttribute bodyAttr, Type returnType, bool isAsyncCall, StringBuilder classBuilder) { if (bodyAttr == null || returnType == null) { return; } var format = bodyAttr.Format; if (format == Format.Auto) { format = typeof(Stream).IsAssignableFrom(returnType) ? Format.Raw : Format.Json; } // The Format.Auto is handled above, since it will always be Raw or Json at this point // ReSharper disable once SwitchStatementMissingSomeCases switch (format) { case Format.Json: classBuilder.AppendLine(isAsyncCall ? $" return await ConvertToObjectAsync<{WebServiceClassGenerator.ToCompilableName(returnType)}>(response);" : $" return ConvertToObject<{WebServiceClassGenerator.ToCompilableName(returnType)}>(response);"); break; case Format.Raw: classBuilder.AppendLine(isAsyncCall ? " return await response.Content.ReadAsStreamAsync();" : " return response.Content.ReadAsStreamAsync().Result;"); break; default: return; } }
internal static void ReturnContentObject(BodyAttribute bodyAttr, Type returnType, bool isAsyncCall, IndentBuilder contentBuilder) { if (bodyAttr == null || returnType == null) { return; } var format = bodyAttr.Format; if (format == Format.Auto) { format = typeof(Stream).IsAssignableFrom(returnType) ? Format.Raw : Format.Json; } // The Format.Auto is handled above, since it will always be Raw or Json at this point // ReSharper disable once SwitchStatementMissingSomeCases switch (format) { case Format.Json: contentBuilder.AppendLine(isAsyncCall ? $"return await DHaven.Faux.HttpSupport.DiscoveryAwareBase.ConvertToObjectAsync<{CompilerUtils.ToCompilableName(returnType)}>(仮response);" : $"return DHaven.Faux.HttpSupport.DiscoveryAwareBase.ConvertToObject<{CompilerUtils.ToCompilableName(returnType)}>(仮response);"); break; case Format.Raw: contentBuilder.AppendLine(isAsyncCall ? "return await 仮response.Content.ReadAsStreamAsync();" : "return 仮response.Content.ReadAsStreamAsync().Result;"); break; default: return; } }
private bool ParameterBehavior(IHttpBehavior behavior, string paramName, BodyAttribute attr, int argIndex) { if (attr == null) { return(false); } if (behavior.BodyKey != null) { throw new Exception("只能设置一次body"); } behavior.BodyKey = new HttpBodyBehavior(argIndex); return(true); }
public string GenerateMethodClass(MethodInfo method, out string fullMethodClassName) { var typeInfo = method.DeclaringType; Debug.Assert(typeInfo != null, nameof(typeInfo) + " is null"); var className = $"{typeInfo.FullName?.Replace(".", string.Empty)}_{method.Name}"; fullMethodClassName = $"{Config.RootNamespace}.{className}"; var sealedString = Config.GenerateSealedClasses ? "sealed" : string.Empty; var isAsyncCall = typeof(Task).IsAssignableFrom(method.ReturnType); var returnType = method.ReturnType; var serviceName = typeInfo.GetCustomAttribute <FauxClientAttribute>().Name; if (isAsyncCall && method.ReturnType.IsConstructedGenericType) { returnType = method.ReturnType.GetGenericArguments()[0]; } var isVoid = returnType == typeof(void) || (isAsyncCall && !method.ReturnType.IsConstructedGenericType); var treturn = isVoid ? string.Empty : $"<{CompilerUtils.ToCompilableName(returnType)}>"; var inParams = method.GetParameters().Where(p => !p.IsOut).ToList(); var outParams = method.GetParameters().Where(p => p.IsOut).ToList(); var attribute = method.GetCustomAttribute <HttpMethodAttribute>(); using (logger.BeginScope("Generator {0}.{1}:", className, method.Name)) using (var namespaceBuilder = new IndentBuilder()) { namespaceBuilder.AppendLine($"namespace {Config.RootNamespace}"); namespaceBuilder.AppendLine("{"); using (var classBuilder = namespaceBuilder.Indent()) { classBuilder.AppendLine("// Generated by DHaven.Faux"); classBuilder.AppendLine($"public {sealedString} class {className} : Steeltoe.CircuitBreaker.Hystrix.HystrixCommand{treturn}"); classBuilder.AppendLine("{"); using (var fieldBuilder = classBuilder.Indent()) { fieldBuilder.AppendLine("private readonly DHaven.Faux.HttpSupport.DiscoveryAwareBase 仮core;"); fieldBuilder.AppendLine("private readonly Microsoft.Extensions.Logging.ILogger 仮logger;"); fieldBuilder.AppendLine($"private readonly {typeInfo.FullName} 仮fallback;"); foreach (var inField in inParams) { fieldBuilder.AppendLine($"private readonly {CompilerUtils.ToCompilableName(inField.ParameterType)} {inField.Name};"); } } using (var constructorBuilder = classBuilder.Indent()) { constructorBuilder.AppendLine($"public {className}("); constructorBuilder.AppendLine(" DHaven.Faux.HttpSupport.DiscoveryAwareBase core,"); constructorBuilder.AppendLine($" {typeInfo.FullName} fallback,"); foreach (var inparam in inParams) { constructorBuilder.AppendLine( $" {CompilerUtils.ToCompilableName(inparam.ParameterType)} {inparam.Name},"); } constructorBuilder.AppendLine(" Microsoft.Extensions.Logging.ILogger logger)"); constructorBuilder.AppendLine($" : base(new Steeltoe.CircuitBreaker.Hystrix.HystrixCommandOptions(Steeltoe.CircuitBreaker.Hystrix.HystrixCommandGroupKeyDefault.AsKey(\"{serviceName}\"), Steeltoe.CircuitBreaker.Hystrix.HystrixCommandKeyDefault.AsKey(\"{method.Name}\")), null, null, logger)"); constructorBuilder.AppendLine("{"); using (var insideBuilder = constructorBuilder.Indent()) { insideBuilder.AppendLine("仮core = core;"); insideBuilder.AppendLine("仮logger = logger;"); insideBuilder.AppendLine("仮fallback = fallback;"); foreach (var inparam in inParams) { insideBuilder.AppendLine($"this.{inparam.Name} = {inparam.Name};"); } } constructorBuilder.AppendLine("}"); } using (var propertyBuilder = classBuilder.Indent()) { foreach (var property in outParams) { propertyBuilder.AppendLine($"public {CompilerUtils.ToCompilableName(property.ParameterType)} {property.Name} {{ get; private set; }}"); } } var taskType = isVoid ? "System.Reactive.Unit" : CompilerUtils.ToCompilableName(returnType); using (var runBuilder = classBuilder.Indent()) { runBuilder.AppendLine($"protected override async System.Threading.Tasks.Task<{taskType}> RunAsync()"); runBuilder.AppendLine("{"); using (var contentBuilder = runBuilder.Indent()) { contentBuilder.AppendLine("var 仮variables = new System.Collections.Generic.Dictionary<string,object>();"); contentBuilder.AppendLine("var 仮reqParams = new System.Collections.Generic.Dictionary<string,string>();"); var contentHeaders = new Dictionary <string, ParameterInfo>(); var requestHeaders = new Dictionary <string, ParameterInfo>(); var responseHeaders = new Dictionary <string, ParameterInfo>(); ParameterInfo bodyParam = null; BodyAttribute bodyAttr = null; foreach (var parameter in method.GetParameters()) { AttributeInterpreter.InterpretPathValue(parameter, contentBuilder); AttributeInterpreter.InterpretRequestHeader(parameter, requestHeaders, contentHeaders); AttributeInterpreter.InterpretBodyParameter(parameter, ref bodyParam, ref bodyAttr); AttributeInterpreter.InterpretRequestParameter(parameter, contentBuilder); AttributeInterpreter.InterpretResponseHeaderInParameters(parameter, false, ref responseHeaders); } contentBuilder.AppendLine($"var 仮request = 仮core.CreateRequest({CompilerUtils.ToCompilableName(attribute.Method)}, \"{attribute.Path}\", 仮variables, 仮reqParams);"); var hasContent = AttributeInterpreter.CreateContentObjectIfSpecified(bodyAttr, bodyParam, contentBuilder); foreach (var entry in requestHeaders) { contentBuilder.AppendLine($"仮request.Headers.Add(\"{entry.Key}\", {entry.Value.Name}{(entry.Value.ParameterType.IsClass ? "?" : "")}.ToString());"); } if (hasContent) { // when setting content we can apply the contentHeaders foreach (var entry in contentHeaders) { contentBuilder.AppendLine($"仮content.Headers.Add(\"{entry.Key}\", {entry.Value.Name}{(entry.Value.ParameterType.IsClass ? "?" : "")}.ToString());"); } contentBuilder.AppendLine("仮request.Content = 仮content;"); } contentBuilder.AppendLine("var 仮response = await 仮core.InvokeAsync(仮request);"); foreach (var entry in responseHeaders) { contentBuilder.AppendLine( $"{entry.Value.Name} = DHaven.Faux.HttpSupport.DiscoveryAwareBase.GetHeaderValue<{CompilerUtils.ToCompilableName(entry.Value.ParameterType)}>(仮response, \"{entry.Key}\");"); } if (isVoid) { contentBuilder.AppendLine("return System.Reactive.Unit.Default;"); } else { var returnBodyAttribute = method.ReturnParameter?.GetCustomAttribute <BodyAttribute>(); var returnResponseAttribute = method.ReturnParameter?.GetCustomAttribute <ResponseHeaderAttribute>(); if (returnResponseAttribute != null && returnBodyAttribute != null) { throw new WebServiceCompileException( $"Cannot have different types of response attributes. You had [{string.Join(", ", "Body", "ResponseHeader")}]"); } if (returnResponseAttribute != null) { AttributeInterpreter.ReturnResponseHeader(returnResponseAttribute, returnType, contentBuilder); } else { if (returnBodyAttribute == null) { returnBodyAttribute = new BodyAttribute(); } AttributeInterpreter.ReturnContentObject(returnBodyAttribute, returnType, isAsyncCall, contentBuilder); } } } runBuilder.AppendLine("}"); } using (var fallbackBuilder = classBuilder.Indent()) { fallbackBuilder.AppendLine($"protected override async System.Threading.Tasks.Task<{taskType}> RunFallbackAsync()"); fallbackBuilder.AppendLine("{"); using (var contentBuilder = fallbackBuilder.Indent()) { foreach (var value in outParams) { contentBuilder.AppendLine($"{CompilerUtils.ToCompilableName(value.ParameterType)} {value.Name} = default({CompilerUtils.ToCompilableName(value.ParameterType)});"); } if (!isVoid) { contentBuilder.Append("var 仮value = "); } if (isAsyncCall) { contentBuilder.Append("await "); } contentBuilder.Append($"仮fallback?.{method.Name}("); contentBuilder.Append(string.Join(", ", method.GetParameters().Select(CompilerUtils.ToParameterUsage))); contentBuilder.Append(")"); if (!isVoid && method.ReturnType.IsValueType) { contentBuilder.Append($" ?? default({CompilerUtils.ToCompilableName(method.ReturnType)})"); } contentBuilder.AppendLine(";"); foreach (var value in outParams) { contentBuilder.AppendLine($"this.{value.Name} = {value.Name};"); } var returnVal = isVoid ? "System.Reactive.Unit.Default" : "仮value"; contentBuilder.AppendLine($"return {returnVal};"); } fallbackBuilder.AppendLine("}"); } classBuilder.AppendLine("}"); } namespaceBuilder.AppendLine("}"); var sourceCode = namespaceBuilder.ToString(); logger.LogTrace("Source generated"); if (Config.OutputSourceFiles) { var fullPath = Path.Combine(Config.SourceFilePath, $"{className}.cs"); try { logger.LogTrace("Writing source file: {0}", fullPath); File.WriteAllText(fullPath, sourceCode, Encoding.UTF8); } catch (Exception ex) { logger.LogWarning(ex, "Could not write the source code for {0}", fullPath); } } return(sourceCode); } }
private void BuildMethod(IndentBuilder classBuilder, MethodInfo method) { var isAsyncCall = typeof(Task).IsAssignableFrom(method.ReturnType); var returnType = method.ReturnType; if (isAsyncCall && method.ReturnType.IsConstructedGenericType) { returnType = method.ReturnType.GetGenericArguments()[0]; } var isVoid = returnType == typeof(void) || (isAsyncCall && !method.ReturnType.IsConstructedGenericType); // Write the method declaration classBuilder.Append("public "); if (isAsyncCall) { classBuilder.Append("async "); classBuilder.Append(typeof(Task).FullName); if (!isVoid) { classBuilder.Append($"<{CompilerUtils.ToCompilableName(returnType)}>"); } } else { classBuilder.Append(isVoid ? "void" : CompilerUtils.ToCompilableName(returnType)); } var attribute = method.GetCustomAttribute <HttpMethodAttribute>(); classBuilder.Append($" {method.Name}("); classBuilder.Append(string.Join(", ", method.GetParameters().Select(CompilerUtils.ToParameterDeclaration))); classBuilder.AppendLine(")"); classBuilder.AppendLine("{"); using (var methodBuilder = classBuilder.Indent()) { methodBuilder.AppendLine( "var 仮variables = new System.Collections.Generic.Dictionary<string,object>();"); methodBuilder.AppendLine( "var 仮reqParams = new System.Collections.Generic.Dictionary<string,string>();"); var contentHeaders = new Dictionary <string, ParameterInfo>(); var requestHeaders = new Dictionary <string, ParameterInfo>(); var responseHeaders = new Dictionary <string, ParameterInfo>(); ParameterInfo bodyParam = null; BodyAttribute bodyAttr = null; foreach (var parameter in method.GetParameters()) { AttributeInterpreter.InterpretPathValue(parameter, methodBuilder); AttributeInterpreter.InterpretRequestHeader(parameter, requestHeaders, contentHeaders); AttributeInterpreter.InterpretBodyParameter(parameter, ref bodyParam, ref bodyAttr); AttributeInterpreter.InterpretRequestParameter(parameter, methodBuilder); AttributeInterpreter.InterpretResponseHeaderInParameters(parameter, isAsyncCall, ref responseHeaders); } methodBuilder.AppendLine( $"var 仮request = CreateRequest({CompilerUtils.ToCompilableName(attribute.Method)}, \"{attribute.Path}\", 仮variables, 仮reqParams);"); var hasContent = AttributeInterpreter.CreateContentObjectIfSpecified(bodyAttr, bodyParam, methodBuilder); foreach (var entry in requestHeaders) { methodBuilder.AppendLine( $"仮request.Headers.Add(\"{entry.Key}\", {entry.Value.Name}{(entry.Value.ParameterType.IsClass ? "?" : "")}.ToString());"); } if (hasContent) { // when setting content we can apply the contentHeaders foreach (var entry in contentHeaders) { methodBuilder.AppendLine( $"仮content.Headers.Add(\"{entry.Key}\", {entry.Value.Name}{(entry.Value.ParameterType.IsClass ? "?" : "")}.ToString());"); } methodBuilder.AppendLine("仮request.Content = 仮content;"); } methodBuilder.AppendLine(isAsyncCall ? "var 仮response = await InvokeAsync(仮request);" : "var 仮response = Invoke(仮request);"); foreach (var entry in responseHeaders) { methodBuilder.AppendLine( $"{entry.Value.Name} = GetHeaderValue<{CompilerUtils.ToCompilableName(entry.Value.ParameterType)}>(仮response, \"{entry.Key}\");"); } if (!isVoid) { var returnBodyAttribute = method.ReturnParameter?.GetCustomAttribute <BodyAttribute>(); var returnResponseAttribute = method.ReturnParameter?.GetCustomAttribute <ResponseHeaderAttribute>(); if (returnResponseAttribute != null && returnBodyAttribute != null) { throw new WebServiceCompileException( $"Cannot have different types of response attributes. You had [{string.Join(", ", "Body", "ResponseHeader")}]"); } if (returnResponseAttribute != null) { AttributeInterpreter.ReturnResponseHeader(returnResponseAttribute, returnType, methodBuilder); } else { if (returnBodyAttribute == null) { returnBodyAttribute = new BodyAttribute(); } AttributeInterpreter.ReturnContentObject(returnBodyAttribute, returnType, isAsyncCall, methodBuilder); } } } classBuilder.AppendLine("}"); }
public static JSBFunction CreateLinkFunction(string baseApiPath, string controller, MethodInfo info, bool useName) { List <ParameterInfo> paras = info.GetParameters().Where(x => !BodyAttribute.HasAttribute(x)).ToList(); ParameterInfo bodyParameter = info.GetParameters().FirstOrDefault(x => BodyAttribute.HasAttribute(x)); string bodyParaName = (bodyParameter != null) ? bodyParameter.Name : ""; BodyAttribute bodyAttr = null; if (bodyParameter != null) { bodyAttr = BodyAttribute.GetAttribute(bodyParameter); } List <string> stringParas = paras.Select(x => x.Name).ToList(); MethodDescriptorAttribute descriptor = MethodDescriptorAttribute.GetDescriptor(info); if (descriptor != null) { //stringParas = new List<string>(); foreach (string para in descriptor.Parameters) { if (!stringParas.Contains(para)) { stringParas.Add(para); } } if (descriptor.HasPostParameter) { bodyParaName = descriptor.PostParameter; } } if (RequiresTokenAttribute.HasAttribute(info)) { stringParas.Add("t"); } JSBuilder code = new JSBuilder(); StringBuilder paraString = new StringBuilder(); for (int i = 0; i < stringParas.Count; i++) { if (i == 0) { paraString.Append("?"); } else { paraString.Append("&"); } paraString.Append(stringParas[i] + "=' + " + stringParas[i] + " + '"); } if (RequiresTokenAttribute.HasAttribute(info)) { code.AddCode("if(!t) t = Sync.Token;"); } string baseUrlPrepend = ((APIBaseUrl != "") ? $"{APIBaseUrl}/" : ""); if (!string.IsNullOrEmpty(bodyParaName)) { if (bodyAttr != null && bodyAttr.BodyType == BodyType.Raw) { if (descriptor != null && descriptor.ResponseType == BodyType.Raw) { code.AddCode($"SyncPostRawRaw('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', {bodyParaName}, callback);"); } else { code.AddCode($"SyncPostRawJson('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', {bodyParaName}, callback);"); } } else { if (descriptor != null && descriptor.ResponseType == BodyType.Raw) { code.AddCode($"SyncPostJsonRaw('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', {"JSON.stringify(" + bodyParaName + ")"}, callback);"); } else { code.AddCode($"SyncPostJson('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', {"JSON.stringify(" + bodyParaName + ")"}, callback);"); } } } else { if (descriptor != null && descriptor.ResponseType == BodyType.Raw) { code.AddCode($"SyncGetRaw('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', callback);"); } else { code.AddCode($"SyncGetJson('{baseUrlPrepend + controller}/{info.Name}{paraString.ToString()}', callback);"); } } if (!string.IsNullOrEmpty(bodyParaName)) { if (stringParas.LastOrDefault() == "t") { stringParas.Insert(stringParas.Count - 1, bodyParaName); } else { stringParas.Add(bodyParaName); } } if (stringParas.LastOrDefault() == "t") { stringParas.Insert(stringParas.Count - 1, "callback"); } else { stringParas.Add("callback"); } JSBFunction func = new JSBFunction(((useName) ? info.Name : null), code, stringParas.ToArray()); return(func); }
internal static void InterpretBodyParameter(ParameterInfo parameter, ref ParameterInfo bodyParam, ref BodyAttribute bodyAttr) { var attr = parameter.GetCustomAttribute <BodyAttribute>(); if (attr == null) { return; } if (bodyAttr != null) { throw new WebServiceCompileException("Cannot have more than one body parameter"); } bodyAttr = attr; bodyParam = parameter; }
public void Intercept(IInvocation invocation) { ServiceRquestInfo rquestInfo = new ServiceRquestInfo(); IList <System.Reflection.CustomAttributeData> customAttributeDatas = invocation.Method.GetCustomAttributesData(); for (int j = 0; j < customAttributeDatas.Count; j++) { System.Reflection.CustomAttributeData customAttribute = customAttributeDatas[j]; if (customAttribute.AttributeType == typeof(POSTAttribute)) { rquestInfo.HttpMethod = HttpMethod.Post; if (customAttribute.ConstructorArguments[0].Value is string) { rquestInfo.Url = customAttribute.ConstructorArguments[0].Value as string; } } else if (customAttribute.AttributeType == typeof(GETAttribute)) { rquestInfo.HttpMethod = HttpMethod.Get; if (customAttribute.ConstructorArguments[0].Value is string) { rquestInfo.Url = customAttribute.ConstructorArguments[0].Value as string; } } else if (customAttribute.AttributeType == typeof(HeaderAttribute)) { if (customAttribute.ConstructorArguments[0].Value is string) { rquestInfo.Header.Add(customAttribute.ConstructorArguments[0].Value as string); } } else if (customAttribute.AttributeType == typeof(UploadFileAttribute)) { rquestInfo.IsUploadFile = true; } } if (invocation.Arguments.Count() > 0)//这个请求方法有传参 { //获取参数 ParameterInfo[] parameterInfos = invocation.Method.GetParameters(); for (int j = 0; j < parameterInfos.Length; j++) { ParameterInfo parameter = parameterInfos[j]; IEnumerable <Attribute> attributes = parameter.GetCustomAttributes(); if (attributes.Count() == 0)//这个参数没有使用我们的特性,过滤掉这个参数值 { continue; } string paramName = parameter.Name; //参数原始名字 object paramValue = invocation.Arguments[j]; //参数值 for (int z = 0; z < attributes.Count(); z++) { Attribute a = attributes.ElementAt(z); //Query属性 if (a is QueryAttribute) { if (!(paramValue is string)) { throw new Exception("Query的请求非String"); } QueryAttribute query = a as QueryAttribute; string cfgParamName = query.ParamName; //在自定义特性中定义的属性名 if (string.IsNullOrEmpty(cfgParamName)) //如果没有配置Query的参数名,默认使用参数的㡳名称 { rquestInfo.Param.Add(paramName, paramValue as string); } else { rquestInfo.Param.Add(cfgParamName, paramValue as string); } } else if (a is BodyAttribute) { BodyAttribute body = a as BodyAttribute; //将这个参数序列化成json string json = Newtonsoft.Json.JsonConvert.SerializeObject(paramValue); rquestInfo.Body = json; } else if (a is DynamicHeaderAttribute) { DynamicHeaderAttribute dynamicHeader = a as DynamicHeaderAttribute; string headername = dynamicHeader.Header; if (string.IsNullOrEmpty(headername))//如果没有配置Header的参数名,默认使用参数的㡳名称 { rquestInfo.Header.Add(paramName + ":" + paramValue); } else { rquestInfo.Header.Add(headername + ":" + paramValue); } } else if (a is FilePathAttribute) { rquestInfo.FilePath = paramValue as string; } } } } Console.WriteLine("拦截了"); Call call = new Call(); call.RquestInfo = rquestInfo; call.Msg = "测试"; call.Client = RetrofitClientCache.Instance.GetClient(invocation.Proxy.GetHashCode()); invocation.ReturnValue = call; //不用实现方法 //invocation.Proceed(); }