public static string DiagName(this IReturn value, DiagContextInternal ctx) { var unknown = $"<UNKNOWN|{value.GetType().DiagName()}>"; if (value is ReturnValue rvs) { return(ReflectionReader.ReadFieldValue( rvs, "_value", (object o) => o.GetObjectId(ctx), "<VALUE|CANNOT_READ>")); } var valueType = value.GetType(); if (!valueType.IsGenericType) { return(unknown); } var gtd = valueType.GetGenericTypeDefinition(); if (gtd == typeof(ReturnMultipleValues <>)) { return(ReflectionReader.ReadFieldValue( value, "_valuesToReturn", (IEnumerable objs) => objs.Cast <object>().Print(o => o.GetObjectId(ctx)), "<MVALUES|CANNOT_READ>")); } if (gtd == typeof(ReturnValueFromFunc <>)) { return(ReflectionReader.ReadFieldValue( value, "_funcToReturnValue", (Delegate d) => $"<FUNC|{d.DiagName()}>", "<FVALUE|CANNOT_READ>")); } if (gtd == typeof(ReturnMultipleFuncsValues <>)) { return(ReflectionReader.ReadFieldValue( value, "_funcsToReturn", (IEnumerable <Delegate> ds) => $"<FUNCS|{ds.Print(DiagName)}>", "<FMVALUES|CANNOT_READ>")); } return(unknown); }
internal string BuildUri <T>(IReturn <T> request, Method method) { var type = request.GetType().GetTypeInfo(); var attrs = type.GetCustomAttributes <RouteAttribute>(true); var validRoutes = attrs .Where(attr => (attr.AcceptedMethods & method) == method) .Select(attr => attr.UrlTemplate); var properties = type.DeclaredProperties .ToDictionary( prop => String.Format("{{{0}}}", prop.Name), prop => prop.GetValue(request)) .Where(kvp => kvp.Value != null) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var matchedRoutes = validRoutes.Select(route => MatchRoute(route, properties)).ToList(); var highest = matchedRoutes.Max(t => t.Item1); var bestRoutes = matchedRoutes.Where(t => t.Item1 == highest); if (bestRoutes.Count() > 1) { // TODO: class throw new Exception("Ambiguous routes on type " + type.Name + ": " + String.Join(", ", validRoutes)); } if (!bestRoutes.Any()) { // TODO: class throw new Exception("Could not find any matching route on type " + type.Name); } return(baseUri + bestRoutes.Single().Item2); }
public static string GetUrlFromRoute <T>(this IReturn <T> request, bool setPropertiesAsUrlParams = false) { var requestType = request.GetType(); var properties = requestType.GetTypeInfo().DeclaredProperties .Select(property => new { property.Name, Value = property.GetValue(request) }) .Where(property => property.Value != null) .ToArray(); var routeAttributes = requestType.GetTypeInfo().GetCustomAttributes(typeof(RouteAttribute), true) .OfType <RouteAttribute>() .ToArray(); if (routeAttributes.None()) { return(string.Empty); } var routeAttribute = routeAttributes.Length == 1 ? routeAttributes.First() : routeAttributes.SelectCorrectRouteAttribute(properties.Select(p => p.Name)); // before PCL: var matches = Regex.Matches(routeAttribute.Address, "\\{[a-zA-Z]+\\}", RegexOptions.Compiled) var matches = Regex.Matches(routeAttribute.Address, "\\{[a-zA-Z]+\\}") .Cast <Match>() .Select(match => new { PropertyName = match.Value.Replace("{", "").Replace("}", ""), Tag = match.Value }) .ToArray(); var address = routeAttribute.Address; foreach (var match in matches) { var property = properties.First(p => p.Name == match.PropertyName); address = address.Replace(match.Tag, property.Value.ToString()); } if (!setPropertiesAsUrlParams) { return(address); } var parameters = properties .Where(prop => matches.None(match => prop.Name == match.PropertyName)) .Select(prop => prop.Name + "=" + Uri.EscapeUriString(prop.Value.ToString())) .ToArray(); return(parameters.Any() ? address + "?" + parameters.JoinBy("&") : address); }
/// <summary> /// 获取请求url /// </summary> /// <param name="request"></param> /// <returns></returns> public static string GetUrl(this IReturn request, IRPCContext context = null) { var assemblyName = request.GetType().Assembly.GetName().Name; //这里约定配置BaseUrl (优先级 3) var baseUrl = ConfigurationManager.GetConfig($"ApiHost.{assemblyName}"); //优先使用代码设置的bashUrl (优先级 2) if (!string.IsNullOrWhiteSpace(context?.RPCBaseUrl?.Trim())) { baseUrl = context.RPCBaseUrl; } var partUrl = request.GetType() .GetCustomAttributes(false) .OfType <RpcRouteAttribute>() .Select(attr => attr).FirstOrDefault()?.Path ?? string.Empty; return(new Uri(new Uri(baseUrl), partUrl).ToString()); }
protected TResponse ProcessRequest <TResponse>(IReturn <TResponse> request, HttpStatusCode code, Func <TResponse> action) where TResponse : class { string requestType = (request != null) ? request.GetType().Name : string.Empty; //TODO: Audit this call in your analytics try { Guard.NotNull(() => request, request); TResponse response = null; response = action(); if (response == null) { throw new NotSupportedException(); } SetResponseCode(code); //TODO: Audit this response in your analytics return(response); } catch (ArgumentException ex) { throw HttpErrorThrower.BadRequest(ex.Message); } catch (ResourceNotFoundException ex) { throw HttpErrorThrower.NotFound(ex.Message); } catch (ResourceConflictException ex) { throw HttpErrorThrower.Conflict(ex.Message); } catch (RuleViolationException ex) { throw HttpErrorThrower.BadRequest(ex.Message); } catch (Exception) { throw HttpErrorThrower.InternalServerError(); } }
public static string ToUrl(this IReturn request, string httpMethod, string formatFallbackToPredefinedRoute = null) { httpMethod = httpMethod.ToUpper(); var requestType = request.GetType(); var requestRoutes = routesCache.GetOrAdd(requestType, GetRoutesForType); if (!requestRoutes.Any()) { if (formatFallbackToPredefinedRoute == null) { throw new InvalidOperationException("There is no rest routes mapped for '{0}' type. ".Fmt(requestType) + "(Note: The automatic route selection only works with [Route] attributes on the request DTO and" + "not with routes registered in the IAppHost!)"); } var predefinedRoute = "/{0}/syncreply/{1}".Fmt(formatFallbackToPredefinedRoute, request.GetType().Name); if (httpMethod == "GET" || httpMethod == "DELETE" || httpMethod == "OPTIONS") { var queryString = "?{0}".Fmt(request.GetType().GetProperties().ToQueryString(request)); predefinedRoute += queryString; } return(predefinedRoute); } var routesApplied = requestRoutes.Select(route => new { Route = route, Result = route.Apply(request, httpMethod) }).ToList(); var matchingRoutes = routesApplied.Where(x => x.Result.Matches).ToList(); if (!matchingRoutes.Any()) { var errors = string.Join(String.Empty, routesApplied.Select(x => "\r\n\t{0}:\t{1}".Fmt(x.Route.Path, x.Result.FailReason)).ToArray()); var errMsg = "None of the given rest routes matches '{0}' request:{1}" .Fmt(requestType.Name, errors); throw new InvalidOperationException(errMsg); } var matchingRoute = matchingRoutes[0]; // hack to determine variable type. if (matchingRoutes.Count > 1) { var mostSpecificRoute = FindMostSpecificRoute(matchingRoutes.Select(x => x.Route)); if (mostSpecificRoute == null) { var errors = String.Join(String.Empty, matchingRoutes.Select(x => "\r\n\t" + x.Route.Path).ToArray()); var errMsg = "Ambiguous matching routes found for '{0}' request:{1}".Fmt(requestType.Name, errors); throw new InvalidOperationException(errMsg); } matchingRoute = matchingRoutes.Single(x => x.Route == mostSpecificRoute); } else { matchingRoute = matchingRoutes.Single(); } var url = matchingRoute.Result.Uri; if (httpMethod == HttpMethod.Get || httpMethod == HttpMethod.Delete) { var queryParams = matchingRoute.Route.FormatQueryParameters(request); if (!String.IsNullOrEmpty(queryParams)) { url += "?" + queryParams; } } return(url); }