public async Task<MapResult> MapAsync(HttpContextBase context, Type type, MethodInfo method, ParameterInfo parameter) { context.ThrowIfNull("context"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); parameter.ThrowIfNull("parameter"); Type parameterType = parameter.ParameterType; object model = _container != null ? _container.GetInstance(parameterType) : Activator.CreateInstance(parameterType); Type modelType = model.GetType(); foreach (PropertyInfo property in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { object mappedValue = await GetMappedValueAsync(context, modelType, property); if (mappedValue == null) { throw new ApplicationException(String.Format("Unable to map property '{0} {1}' of type '{2}'.", property.PropertyType.FullName, property.Name, modelType.FullName)); } property.SetValue(model, mappedValue, null); } return MapResult.ValueMapped(model); }
public Task<bool> CanMapTypeAsync(HttpContextBase context, Type parameterType) { context.ThrowIfNull("context"); parameterType.ThrowIfNull("parameterType"); return true.AsCompletedTask(); }
public Task<ResponseResult> GetResponseAsync(HttpContextBase context, IEnumerable<RouteMatchResult> routeMatchResults) { context.ThrowIfNull("context"); routeMatchResults.ThrowIfNull("routeMatchResults"); return ResponseResult.ResponseGenerated(new Response().NotFound()).AsCompletedTask(); }
public override Task<bool> CanMapTypeAsync(HttpContextBase context, Type parameterType) { context.ThrowIfNull("context"); parameterType.ThrowIfNull("parameterType"); return parameterType.ImplementsInterface<IConvertible>().AsCompletedTask(); }
public Task<bool> CanMapTypeAsync(HttpContextBase context, Type parameterType) { context.ThrowIfNull("context"); parameterType.ThrowIfNull("parameterType"); return (parameterType == typeof(HttpServerUtilityBase)).AsCompletedTask(); }
public Task<MapResult> MapAsync(HttpContextBase context, Type type, MethodInfo method, ParameterInfo parameter) { context.ThrowIfNull("request"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); parameter.ThrowIfNull("parameter"); Type parameterType = parameter.ParameterType; var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding); string json = reader.ReadToEnd(); object jsonModel; try { jsonModel = JsonConvert.DeserializeObject(json, parameterType, _serializerSettings); } catch (Exception exception) { if (_errorHandling == DataConversionErrorHandling.ThrowException) { throw new ApplicationException(String.Format("Request content could not be deserialized to '{0}'.", parameterType.FullName), exception); } jsonModel = parameterType.GetDefaultValue(); } return MapResult.ValueMapped(jsonModel).AsCompletedTask(); }
public async Task<bool> CanMapTypeAsync(HttpContextBase context, Type parameterType) { context.ThrowIfNull("context"); parameterType.ThrowIfNull("parameterType"); return await Task.Run(() => _parameterTypeMatchDelegate(parameterType)); }
public async Task<bool> CanMapTypeAsync(HttpContextBase context, Type parameterType) { context.ThrowIfNull("context"); parameterType.ThrowIfNull("parameterType"); return context.Request.ContentType == "application/json" && await Task.Run(() => _parameterTypeMatchDelegate(parameterType)); }
protected override Task<MapResult> OnMapAsync(HttpContextBase context, string value, Type parameterType) { context.ThrowIfNull("context"); value.ThrowIfNull("value"); parameterType.ThrowIfNull("parameterType"); return MapResult.ValueMapped(((IConvertible)value).ToType(parameterType, CultureInfo.InvariantCulture)).AsCompletedTask(); }
public async Task<IEnumerable<object>> GetParameterValuesAsync(HttpContextBase context, Type type, MethodInfo method) { context.ThrowIfNull("context"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); ParameterInfo[] parameterInfos = method.GetParameters(); var parameterValues = new List<object>(); foreach (ParameterInfo parameterInfo in parameterInfos) { Type parameterType = parameterInfo.ParameterType; string parameterName = parameterInfo.Name; Type currentParameterType = parameterType; do { bool mapped = false; foreach (IParameterMapper parameterMapper in _parameterMappers) { if (!await parameterMapper.CanMapTypeAsync(context, parameterType)) { continue; } MapResult mapResult = await parameterMapper.MapAsync(context, type, method, parameterInfo); if (mapResult.ResultType == MapResultType.ValueNotMapped) { continue; } parameterValues.Add(mapResult.Value); mapped = true; break; } if (mapped) { break; } currentParameterType = currentParameterType.BaseType; } while (currentParameterType != null); if (currentParameterType == null) { throw new ApplicationException( String.Format( "No request parameter mapper was found for parameter '{0} {1}' of {2}.{3}.", parameterType.FullName, parameterName, type.FullName, method.Name)); } } return parameterValues; }
public Task<MapResult> MapAsync(HttpContextBase context, Type type, MethodInfo method, ParameterInfo parameter) { context.ThrowIfNull("context"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); parameter.ThrowIfNull("parameter"); return MapResult.ValueMapped(context.Server).AsCompletedTask(); }
public async Task<ResponseHandlerResult> HandleResponseAsync(HttpContextBase context, IResponse suggestedResponse, ICache cache, string cacheKey) { context.ThrowIfNull("context"); suggestedResponse.ThrowIfNull("suggestedResponse"); await new CacheResponse(suggestedResponse).WriteResponseAsync(context.Response); return ResponseHandlerResult.ResponseWritten(); }
public Task<ResponseResult> GetResponseAsync(HttpContextBase context, IEnumerable<RouteMatchResult> routeMatchResults) { context.ThrowIfNull("context"); routeMatchResults.ThrowIfNull("routeMatchResults"); RouteMatchResult[] unmatchedResults = routeMatchResults.Where(arg => arg.MatchResult.ResultType == MatchResultType.RouteNotMatched).ToArray(); if (!unmatchedResults.Any()) { return ResponseResult.ResponseNotGenerated().AsCompletedTask(); } RouteMatchResult[] unmatchedResultsThatMatchedOnUrlRelativePath = unmatchedResults.Where(arg1 => RouteMatchedUrlRelativePath(arg1.MatchResult)).ToArray(); int minimumUnmatchedRestrictions = unmatchedResultsThatMatchedOnUrlRelativePath.Any() ? unmatchedResultsThatMatchedOnUrlRelativePath.Min(arg => arg.MatchResult.UnmatchedRestrictions.Count()) : 0; RouteMatchResult[] closestMatches = unmatchedResultsThatMatchedOnUrlRelativePath.Where(arg => arg.MatchResult.UnmatchedRestrictions.Count() == minimumUnmatchedRestrictions).ToArray(); if (closestMatches.Length != 1) { return ResponseResult.ResponseNotGenerated().AsCompletedTask(); } RouteMatchResult closestMatch = closestMatches[0]; IRestriction[] unmatchedRestrictions = closestMatch.MatchResult.UnmatchedRestrictions.ToArray(); MethodRestriction[] methodRestrictions = unmatchedRestrictions.OfType<MethodRestriction>().ToArray(); if (methodRestrictions.Any()) { IEnumerable<string> methods = methodRestrictions .Select(arg => arg.Method) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(arg => arg); return ResponseResult.ResponseGenerated(new Response().MethodNotAllowed().Header("Allow", String.Join(", ", methods))).AsCompletedTask(); } if (unmatchedRestrictions.OfType<HeaderRestriction<AcceptHeader>>().Any()) { return ResponseResult.ResponseGenerated(new Response().NotAcceptable()).AsCompletedTask(); } if (unmatchedRestrictions.OfType<HeaderRestriction<AcceptCharsetHeader>>().Any()) { return ResponseResult.ResponseGenerated(new Response().NotAcceptable()).AsCompletedTask(); } if (unmatchedRestrictions.OfType<HeaderRestriction<AcceptEncodingHeader>>().Any()) { return ResponseResult.ResponseGenerated(new Response().NotAcceptable()).AsCompletedTask(); } if (unmatchedRestrictions.OfType<HeaderRestriction<ContentEncodingHeader>>().Any()) { return ResponseResult.ResponseGenerated(new Response().UnsupportedMediaType()).AsCompletedTask(); } return ResponseResult.ResponseNotGenerated().AsCompletedTask(); }
public Task<MapResult> MapAsync(HttpContextBase context, Type modelType, PropertyInfo property) { context.ThrowIfNull("context"); modelType.ThrowIfNull("modelType"); property.ThrowIfNull("property"); Type propertyType = property.PropertyType; string propertyName = property.Name; NameValueCollection nameValueCollection; switch (_source) { case NameValueCollectionSource.Form: nameValueCollection = context.Request.Form; break; case NameValueCollectionSource.QueryString: nameValueCollection = context.Request.QueryString; break; default: throw new InvalidOperationException(String.Format("Unexpected name-value collection source {0}.", _source)); } string field = nameValueCollection.AllKeys.LastOrDefault(arg => String.Equals(arg, propertyName, _caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)); if (field == null) { return MapResult.ValueNotMapped().AsCompletedTask(); } string value = nameValueCollection[field]; try { return OnMapAsync(context, value, propertyType); } catch (Exception exception) { if (_errorHandling == DataConversionErrorHandling.ThrowException) { throw new ApplicationException( String.Format( "Value of form field '{0}' could not be converted to property '{1} {2}' of type '{3}'.", field, propertyType.FullName, propertyName, modelType.FullName), exception); } return MapResult.ValueMapped(propertyType.GetDefaultValue()).AsCompletedTask(); } }
public Task<MapResult> MapAsync(HttpContextBase context, Type type, MethodInfo method, ParameterInfo parameter) { context.ThrowIfNull("context"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); parameter.ThrowIfNull("parameter"); Type parameterType = parameter.ParameterType; string parameterName = parameter.Name; string field = context.Request.Form.AllKeys.LastOrDefault(arg => String.Equals(arg, parameterName, _caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)); if (field == null) { return MapResult.ValueNotMapped().AsCompletedTask(); } IConvertible value = context.Request.Form[field]; object convertedValue; try { convertedValue = value.ToType(parameterType, CultureInfo.InvariantCulture); } catch (Exception exception) { if (_errorHandling == DataConversionErrorHandling.ThrowException) { throw new ApplicationException( String.Format( "Value for form field '{0}' could not be converted to parameter '{1} {2}' of {3}.{4}.", field, parameterType.FullName, parameterName, type.FullName, method.Name), exception); } convertedValue = parameterType.GetDefaultValue(); } return MapResult.ValueMapped(convertedValue).AsCompletedTask(); }
public async Task<ResponseResult> GetResponseAsync(HttpContextBase context, IEnumerable<RouteMatchResult> routeMatchResults) { context.ThrowIfNull("context"); routeMatchResults.ThrowIfNull("routeMatchResults"); routeMatchResults = routeMatchResults.ToArray(); RouteMatchResult[] matchedResults = routeMatchResults.Where(arg => arg.MatchResult.ResultType == MatchResultType.RouteMatched).ToArray(); if (!matchedResults.Any()) { return ResponseResult.ResponseNotGenerated(); } int maximumMatchedRestrictions = matchedResults.Max(arg => arg.MatchResult.MatchedRestrictions.Count()); RouteMatchResult[] bestMatches = matchedResults.Where(arg => arg.MatchResult.MatchedRestrictions.CountEqual(maximumMatchedRestrictions)).ToArray(); if (bestMatches.Length > 1) { return ResponseResult.ResponseGenerated(new Response().MultipleChoices()); } if (bestMatches.Length == 0) { return ResponseResult.ResponseNotGenerated(); } RouteMatchResult bestMatch = bestMatches[0]; AuthenticateResult authenticateResult = await bestMatch.Route.AuthenticateAsync(context.Request, context.Response); if (authenticateResult.ResultType == AuthenticateResultType.AuthenticationFailed) { return ResponseResult.ResponseGenerated(authenticateResult.FailedResponse ?? new Response().Unauthorized()); } Task<IResponse> responseTask = bestMatch.Route.ProcessResponseAsync(context); return ResponseResult.ResponseGenerated(responseTask, bestMatch.MatchResult.CacheKey); }
public async Task<ResponseHandlerResult> HandleResponseAsync(HttpContextBase context, IResponse suggestedResponse, ICache cache, string cacheKey) { context.ThrowIfNull("context"); suggestedResponse.ThrowIfNull("suggestedResponse"); StatusAndSubStatusCode statusCode = suggestedResponse.StatusCode; if (!_statusCodes.Contains(statusCode)) { return ResponseHandlerResult.ResponseNotHandled(); } AcceptHeader[] acceptHeaders = AcceptHeader.ParseMany(context.Request.Headers["Accept"]).ToArray(); if (acceptHeaders.Any() && !acceptHeaders.Any(arg => arg.MediaTypeMatches("text/plain"))) { return ResponseHandlerResult.ResponseNotHandled(); } string content = String.Format( "HTTP {0}{1} {2}", statusCode.StatusCode, statusCode.SubStatusCode == 0 ? "" : "." + statusCode.SubStatusCode.ToString(CultureInfo.InvariantCulture), statusCode.StatusDescription.Length > 0 ? String.Format("({0})", statusCode.StatusDescription) : ""); Response response = new Response(statusCode) .TextPlain() .Content(content); response.CachePolicy.NoClientCaching(); await new CacheResponse(response).WriteResponseAsync(context.Response); context.Response.TrySkipIisCustomErrors = true; return ResponseHandlerResult.ResponseWritten(); }
public async Task<ResponseHandlerResult> HandleResponseAsync(HttpContextBase context, IResponse suggestedResponse, ICache cache, string cacheKey) { context.ThrowIfNull("context"); suggestedResponse.ThrowIfNull("suggestedResponse"); if (!suggestedResponse.CachePolicy.HasPolicy || cache == null || cacheKey == null) { return ResponseHandlerResult.ResponseNotHandled(); } CacheItem cacheItem = await cache.GetAsync(cacheKey); string responseETag = suggestedResponse.CachePolicy.ETag; #region If-Match precondition header IfMatchHeader[] ifMatchHeaders = IfMatchHeader.ParseMany(context.Request.Headers["If-Match"]).ToArray(); // Only consider If-Match headers if response status code is 2xx or 412 if (ifMatchHeaders.Any() && ((suggestedResponse.StatusCode.StatusCode >= 200 && suggestedResponse.StatusCode.StatusCode <= 299) || suggestedResponse.StatusCode.StatusCode == 412)) { // Return 412 if no If-Match header matches the response ETag // Return 412 if an "If-Match: *" header is present and the response has no ETag if (ifMatchHeaders.All(arg => arg.EntityTag.Value != responseETag) || (responseETag == null && ifMatchHeaders.Any(arg => arg.EntityTag.Value == "*"))) { return await WriteResponseAsync(context.Response, new Response().PreconditionFailed()); } } #endregion #region If-None-Match precondition header IfNoneMatchHeader[] ifNoneMatchHeaders = IfNoneMatchHeader.ParseMany(context.Request.Headers["If-None-Match"]).ToArray(); if (ifNoneMatchHeaders.Any()) { // Return 304 if an If-None-Match header matches the response ETag and the request method was GET or HEAD // Return 304 if an "If-None-Match: *" header is present, the response has an ETag and the request method was GET or HEAD // Return 412 if an "If-None-Match: *" header is present, the response has an ETag and the request method was not GET or HEAD if (ifNoneMatchHeaders.Any(arg => arg.EntityTag.Value == responseETag) || (ifNoneMatchHeaders.Any(arg => arg.EntityTag.Value == "*") && responseETag != null)) { if (String.Equals(context.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase) || String.Equals(context.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase)) { if (cacheItem != null) { cacheItem.Response.CachePolicy.Apply(context.Response.Cache); } else { suggestedResponse.CachePolicy.Apply(context.Response.Cache); } return await WriteResponseAsync(context.Response, new Response().NotModified()); } return await WriteResponseAsync(context.Response, new Response().PreconditionFailed()); } } #endregion #region If-Modified-Since precondition header IfModifiedSinceHeader ifModifiedSinceHeader = IfModifiedSinceHeader.Parse(context.Request.Headers["If-Modified-Since"]); bool validIfModifiedSinceHttpDate = ifModifiedSinceHeader != null && ifModifiedSinceHeader.HttpDate <= _systemClock.UtcDateTime; // Only consider an If-Modified-Since header if response status code is 200 and the HTTP-date is valid if (suggestedResponse.StatusCode.ParsedStatusCode == HttpStatusCode.OK && validIfModifiedSinceHttpDate) { // Return 304 if the response was cached before the HTTP-date if (cacheItem != null && cacheItem.CachedUtcTimestamp < ifModifiedSinceHeader.HttpDate) { return await WriteResponseAsync(context.Response, new Response().NotModified()); } } #endregion #region If-Unmodified-Since precondition header IfUnmodifiedSinceHeader ifUnmodifiedSinceHeader = IfUnmodifiedSinceHeader.Parse(context.Request.Headers["If-Unmodified-Since"]); bool validIfUnmodifiedSinceHttpDate = ifUnmodifiedSinceHeader != null && ifUnmodifiedSinceHeader.HttpDate <= _systemClock.UtcDateTime; // Only consider an If-Unmodified-Since header if response status code is 2xx or 412 and the HTTP-date is valid if (((suggestedResponse.StatusCode.StatusCode >= 200 && suggestedResponse.StatusCode.StatusCode <= 299) || suggestedResponse.StatusCode.StatusCode == 412) && validIfUnmodifiedSinceHttpDate) { // Return 412 if the previous response was removed from the cache or was cached again at a later time if (cacheItem == null || cacheItem.CachedUtcTimestamp >= ifUnmodifiedSinceHeader.HttpDate) { return await WriteResponseAsync(context.Response, new Response().PreconditionFailed()); } } #endregion #region No server caching // Do not cache the response when the response sends a non-cacheable status code, or when an Authorization header is present if (!_cacheableStatusCodes.Contains(suggestedResponse.StatusCode) || context.Request.Headers["Authorization"] != null) { return await WriteResponseAsync(context.Response, suggestedResponse); } CacheControlHeader cacheControlHeader = CacheControlHeader.Parse(context.Request.Headers["Cache-Control"]); // Do not cache the response if a "Cache-Control: no-cache" or "Cache-Control: no-store" header is present if (cacheControlHeader != null && (cacheControlHeader.NoCache || cacheControlHeader.NoStore)) { return await WriteResponseAsync(context.Response, suggestedResponse); } IEnumerable<PragmaHeader> pragmaHeader = PragmaHeader.ParseMany(context.Request.Headers["Pragma"]); // Do not cache the response if a "Pragma: no-cache" header is present if (pragmaHeader.Any(arg => String.Equals(arg.Name, "no-cache", StringComparison.OrdinalIgnoreCase))) { return await WriteResponseAsync(context.Response, suggestedResponse); } #endregion // Return 504 if the response has not been cached but the client is requesting to receive only a cached response if (cacheItem == null && cacheControlHeader != null && cacheControlHeader.OnlyIfCached) { return await WriteResponseAsync(context.Response, new Response().GatewayTimeout()); } if (cacheItem != null) { // Write the cached response if no Cache-Control header is present // Write the cached response if a "Cache-Control: max-age" header is validated // Write the cached response if a "Cache-Control: max-stale" header is validated // Write the cached response if a "Cache-Control: min-fresh" header is validated if (cacheControlHeader == null || _systemClock.UtcDateTime - cacheItem.CachedUtcTimestamp <= cacheControlHeader.MaxAge || cacheControlHeader.OnlyIfCached || cacheItem.ExpiresUtcTimestamp == null || _systemClock.UtcDateTime - cacheItem.ExpiresUtcTimestamp.Value <= cacheControlHeader.MaxStale || cacheItem.ExpiresUtcTimestamp.Value - _systemClock.UtcDateTime < cacheControlHeader.MinFresh) { return await WriteResponseInCacheAsync(context.Response, cacheItem); } } bool cacheOnServer = suggestedResponse.CachePolicy.AllowsServerCaching; var cacheResponse = new CacheResponse(suggestedResponse); if (cacheOnServer) { DateTime expirationUtcTimestamp = suggestedResponse.CachePolicy.ServerCacheExpirationUtcTimestamp != null ? suggestedResponse.CachePolicy.ServerCacheExpirationUtcTimestamp.Value : _systemClock.UtcDateTime + suggestedResponse.CachePolicy.ServerCacheMaxAge.Value; await cache.AddAsync(cacheKey, cacheResponse, expirationUtcTimestamp); } return await WriteResponseAsync(context.Response, cacheResponse); }