示例#1
0
        /// <summary>
        /// Determines whether the route constraint matches the specified criteria.
        /// </summary>
        /// <param name="httpContext">The current <see cref="HttpContext">HTTP context</see>.</param>
        /// <param name="route">The current <see cref="IRouter">route</see>.</param>
        /// <param name="routeKey">The key of the route parameter to match.</param>
        /// <param name="values">The current <see cref="RouteValueDictionary">collection</see> of route values.</param>
        /// <param name="routeDirection">The <see cref="RouteDirection">route direction</see> to match.</param>
        /// <returns>True if the route constraint is matched; otherwise, false.</returns>
        public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (IsNullOrEmpty(routeKey))
            {
                return(false);
            }

            var properties = httpContext.ApiVersionProperties();

            if (values.TryGetValue(routeKey, out string value))
            {
                properties.RawApiVersion = value;
            }
            else
            {
                return(false);
            }

            if (routeDirection == UrlGeneration)
            {
                return(!IsNullOrEmpty(value));
            }

            if (TryParse(value, out var requestedVersion))
            {
                properties.ApiVersion = requestedVersion;
                return(true);
            }

            return(false);
        }
示例#2
0
        RequestHandler ClientError(HttpContext httpContext, ActionSelectionResult selectionResult)
        {
            Contract.Requires(httpContext != null);
            Contract.Requires(selectionResult != null);

            const RequestHandler NotFound = default(RequestHandler);
            var candidates = selectionResult.CandidateActions.OrderBy(kvp => kvp.Key).SelectMany(kvp => kvp.Value).Distinct().ToArray();

            if (candidates.Length == 0)
            {
                return(NotFound);
            }

            var properties       = httpContext.ApiVersionProperties();
            var method           = httpContext.Request.Method;
            var requestUrl       = new Lazy <string>(httpContext.Request.GetDisplayUrl);
            var requestedVersion = properties.RawApiVersion;
            var parsedVersion    = properties.ApiVersion;
            var actionNames      = new Lazy <string>(() => Join(NewLine, candidates.Select(a => a.DisplayName)));
            var allowedMethods   = new Lazy <HashSet <string> >(() => AllowedMethodsFromCandidates(candidates));
            var apiVersions      = new Lazy <ApiVersionModel>(selectionResult.CandidateActions.SelectMany(l => l.Value.Select(a => a.GetProperty <ApiVersionModel>()).Where(m => m != null)).Aggregate);
            var handlerContext   = new RequestHandlerContext(ErrorResponseProvider, ApiVersionReporter, apiVersions);

            if (parsedVersion == null)
            {
                if (IsNullOrEmpty(requestedVersion))
                {
                    if (Options.AssumeDefaultVersionWhenUnspecified || candidates.Any(c => c.IsApiVersionNeutral()))
                    {
                        return(VersionNeutralUnmatched(handlerContext, requestUrl.Value, method, allowedMethods.Value, actionNames.Value));
                    }

                    return(UnspecifiedApiVersion(handlerContext, actionNames.Value));
                }
                else if (!TryParse(requestedVersion, out parsedVersion))
                {
                    return(MalformedApiVersion(handlerContext, requestUrl.Value, requestedVersion));
                }
            }
            else if (IsNullOrEmpty(requestedVersion))
            {
                return(VersionNeutralUnmatched(handlerContext, requestUrl.Value, method, allowedMethods.Value, actionNames.Value));
            }
            else
            {
                requestedVersion = parsedVersion.ToString();
            }

            return(Unmatched(handlerContext, requestUrl.Value, method, allowedMethods.Value, actionNames.Value, parsedVersion, requestedVersion));
        }
示例#3
0
 /// <summary>
 /// Gets the current API version requested.
 /// </summary>
 /// <param name="context">The current <see cref="HttpContext">HTTP context</see> to get the API version for.</param>
 /// <returns>The requested <see cref="ApiVersion">API version</see> or <c>null</c>.</returns>
 /// <remarks>This method will return <c>null</c> no service API version was requested or the requested
 /// service API version is in an invalid format.</remarks>
 /// <exception cref="AmbiguousApiVersionException">Multiple, different API versions were requested.</exception>
 public static ApiVersion GetRequestedApiVersion(this HttpContext context)
 {
     Arg.NotNull(context, nameof(context));
     return(context.ApiVersionProperties().ApiVersion);
 }
示例#4
0
        RequestHandler ClientError(HttpContext httpContext, ActionSelectionResult selectionResult)
        {
            Contract.Requires(httpContext != null);
            Contract.Requires(selectionResult != null);

            const RequestHandler NotFound = default(RequestHandler);
            var candidates = selectionResult.CandidateActions.OrderBy(kvp => kvp.Key).SelectMany(kvp => kvp.Value).Distinct().ToArray();

            if (candidates.Length == 0)
            {
                return(NotFound);
            }

            var properties        = httpContext.ApiVersionProperties();
            var requestedVersion  = default(string);
            var parsedVersion     = properties.ApiVersion;
            var actionNames       = new Lazy <string>(() => Join(NewLine, candidates.Select(a => a.DisplayName)));
            var allowedMethods    = new Lazy <HashSet <string> >(() => AllowedMethodsFromCandidates(candidates));
            var newRequestHandler = default(Func <RequestHandlerContext, RequestHandler>);
            var apiVersions       = new Lazy <ApiVersionModel>(selectionResult.CandidateActions.SelectMany(l => l.Value.Select(a => a.GetProperty <ApiVersionModel>()).Where(m => m != null)).Aggregate);
            var handlerContext    = new RequestHandlerContext(ErrorResponseProvider, ApiVersionReporter, apiVersions);

            if (parsedVersion == null)
            {
                var versionNeutral = new Lazy <bool>(() => candidates.Any(c => c.IsApiVersionNeutral()));

                requestedVersion = properties.RawApiVersion;

                if (IsNullOrEmpty(requestedVersion) && !versionNeutral.Value)
                {
                    Logger.ApiVersionUnspecified(actionNames.Value);
                    handlerContext.Code    = ApiVersionUnspecified;
                    handlerContext.Message = SR.ApiVersionUnspecified;
                    return(new BadRequestHandler(handlerContext));
                }
                else if (TryParse(requestedVersion, out parsedVersion))
                {
                    Logger.ApiVersionUnmatched(parsedVersion, actionNames.Value);
                    handlerContext.Code = UnsupportedApiVersion;

                    if (allowedMethods.Value.Contains(httpContext.Request.Method))
                    {
                        newRequestHandler = c => new BadRequestHandler(c);
                    }
                    else
                    {
                        handlerContext.AllowedMethods = allowedMethods.Value.ToArray();
                        newRequestHandler             = c => new MethodNotAllowedHandler(c);
                    }
                }
                else if (versionNeutral.Value)
                {
                    Logger.ApiVersionUnspecified(actionNames.Value);
                    handlerContext.Code    = UnsupportedApiVersion;
                    handlerContext.Message = SR.VersionNeutralResourceNotSupported.FormatDefault(httpContext.Request.GetDisplayUrl());

                    if (allowedMethods.Value.Contains(httpContext.Request.Method))
                    {
                        return(new BadRequestHandler(handlerContext));
                    }

                    handlerContext.AllowedMethods = allowedMethods.Value.ToArray();
                    return(new MethodNotAllowedHandler(handlerContext));
                }
                else
                {
                    Logger.ApiVersionInvalid(requestedVersion);
                    handlerContext.Code = InvalidApiVersion;
                    newRequestHandler   = c => new BadRequestHandler(c);
                }
            }
            else
            {
                Logger.ApiVersionUnmatched(parsedVersion, actionNames.Value);
                requestedVersion    = parsedVersion.ToString();
                handlerContext.Code = UnsupportedApiVersion;

                if (allowedMethods.Value.Contains(httpContext.Request.Method))
                {
                    newRequestHandler = c => new BadRequestHandler(c);
                }
                else
                {
                    handlerContext.AllowedMethods = allowedMethods.Value.ToArray();
                    newRequestHandler             = c => new MethodNotAllowedHandler(c);
                }
            }

            handlerContext.Message = SR.VersionedResourceNotSupported.FormatDefault(httpContext.Request.GetDisplayUrl(), requestedVersion);
            return(newRequestHandler(handlerContext));
        }
        public async Task Invoke(HttpContext context)
        {
            var reqestUrl = context.Request.GetDisplayUrl();

            var response = context.Response;

            var currentBody = response.Body;

            using (var memoryStream = new MemoryStream())
            {
                response.Body = memoryStream;

                await _next(context);

                var apiVersionProperties = context.ApiVersionProperties();

                var apiVersion = apiVersionProperties.RawApiVersion;

                response.Body = currentBody;

                memoryStream.Seek(0, SeekOrigin.Begin);

                var readToEnd = new StreamReader(memoryStream).ReadToEnd();

                var statusCode = response.StatusCode;

                object objResult = null;

                try
                {
                    objResult = statusCode < 400 ? JsonConvert.DeserializeObject(readToEnd) : JsonConvert.DeserializeObject <ApiError>(readToEnd);
                }
                catch (Exception ex)
                {
                    //TODO: Log Unknown Error Response Content

                    objResult = JsonConvert.DeserializeObject(readToEnd);
                }

                string statusMessage;

                var sb = new StringBuilder();

                sb.Append(Enum.GetName(typeof(HttpStatusCode), statusCode));

                if (statusCode > 399)
                {
                    if (statusCode == 401)
                    {
                        var authErrors = response.Headers["WWW-Authenticate"];

                        foreach (var authErr in authErrors)
                        {
                            sb.Append($" - {authErr.Replace("\"", "'")}");
                        }
                    }
                }

                statusMessage = sb.ToString();

                var result = new ApiResponse((HttpStatusCode)statusCode, statusMessage, reqestUrl, apiVersion, objResult);

                response.ContentType = response.ContentType ?? "application/json; charset=utf-8";

                await response.WriteAsync(JsonConvert.SerializeObject(result));
            }
        }