Logging for content-negotiation

This commit is contained in:
Kiran Challa 2015-04-13 10:43:13 -07:00
parent 7576116969
commit c3f10f4a0f
14 changed files with 74 additions and 3 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -11,6 +10,7 @@ using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Microsoft.Net.Http.Headers;
@ -40,9 +40,12 @@ namespace Microsoft.AspNet.Mvc
public override async Task ExecuteResultAsync(ActionContext context)
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>();
// See if the list of content types added to this object result is valid.
ThrowIfUnsupportedContentType();
var formatters = GetDefaultFormatters(context);
var formatterContext = new OutputFormatterContext()
{
DeclaredType = DeclaredType,
@ -55,10 +58,18 @@ namespace Microsoft.AspNet.Mvc
if (selectedFormatter == null)
{
// No formatter supports this.
logger.LogWarning("No output formatter was found to write the response.");
context.HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
return;
}
logger.LogVerbose(
"Selected output formatter '{OutputFormatter}'and content type " +
"'{ContentType}' to write the response.",
selectedFormatter.GetType().FullName,
formatterContext.SelectedContentType);
if (StatusCode.HasValue)
{
context.HttpContext.Response.StatusCode = StatusCode.Value;
@ -72,10 +83,17 @@ namespace Microsoft.AspNet.Mvc
OutputFormatterContext formatterContext,
IEnumerable<IOutputFormatter> formatters)
{
var logger = formatterContext.ActionContext.HttpContext.RequestServices
.GetRequiredService<ILogger<ObjectResult>>();
// Check if any content-type was explicitly set (for example, via ProducesAttribute
// or Url path extension mapping). If yes, then ignore content-negotiation and use this content-type.
if (ContentTypes.Count == 1)
{
logger.LogVerbose(
"Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.",
ContentTypes[0]);
return SelectFormatterUsingAnyAcceptableContentType(formatterContext,
formatters,
ContentTypes);
@ -94,6 +112,8 @@ namespace Microsoft.AspNet.Mvc
out requestContentType);
if (!sortedAcceptHeaderMediaTypes.Any() && requestContentType == null)
{
logger.LogVerbose("No information found on request to perform content negotiation.");
return SelectFormatterBasedOnTypeMatch(formatterContext, formatters);
}
@ -123,6 +143,8 @@ namespace Microsoft.AspNet.Mvc
// fallback on type based match.
if (selectedFormatter == null)
{
logger.LogVerbose("Could not find an output formatter based on content negotiation.");
// Set this flag to indicate that content-negotiation has failed to let formatters decide
// if they want to write the response or not.
formatterContext.FailedContentNegotiation = true;

View File

@ -12,6 +12,7 @@ using Microsoft.AspNet.Http.Core.Collections;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -101,6 +102,8 @@ namespace Microsoft.AspNet.Mvc
optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter());
services.Setup(p => p.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor

View File

@ -11,6 +11,7 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -105,6 +106,8 @@ namespace Microsoft.AspNet.Mvc
optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter());
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
httpContext.Setup(o => o.Response)
.Returns(response);

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -94,6 +95,9 @@ namespace Microsoft.AspNet.Mvc
httpContext
.Setup(p => p.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext
.Setup(p => p.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
mockActionBindingContext

View File

@ -12,6 +12,7 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -104,6 +105,8 @@ namespace Microsoft.AspNet.Mvc
.Returns(mockContextAccessor.Object);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
}

View File

@ -13,10 +13,10 @@ using Microsoft.AspNet.Mvc.Xml;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Microsoft.Net.Http.Headers;
using Moq;
using Newtonsoft.Json.Utilities;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
@ -671,10 +671,11 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
var objectResult = new ObjectResult(new Person() { Name = "John" });
objectResult.ContentTypes = contentTypes.Select(contentType => MediaTypeHeaderValue.Parse(contentType))
.ToList();
var actionContext = CreateMockActionContext();
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => objectResult.ExecuteResultAsync(null));
() => objectResult.ExecuteResultAsync(actionContext));
var expectedMessage = string.Format("The content-type '{0}' added in the 'ContentTypes' property is " +
"invalid. Media types which match all types or match all subtypes are not supported.",
@ -896,6 +897,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader;
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();

View File

@ -14,6 +14,8 @@ using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -1995,6 +1997,8 @@ namespace Microsoft.AspNet.Mvc
httpContext.SetupGet(c => c.Response).Returns(httpResponse);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary)))
.Returns(tempData);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
httpResponse.Body = new MemoryStream();
var options = new MvcOptions();
@ -2078,6 +2082,8 @@ namespace Microsoft.AspNet.Mvc
.Returns(new Dictionary<object, object>());
context.Setup(c => c.RequestServices.GetService(typeof(ITempDataDictionary)))
.Returns(new Mock<ITempDataDictionary>().Object);
context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(new NullLoggerFactory());
var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);

View File

@ -15,6 +15,7 @@ using Microsoft.Framework.OptionsModel;
using Microsoft.Net.Http.Headers;
using Moq;
using Xunit;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
@ -200,6 +201,8 @@ namespace Microsoft.AspNet.Mvc
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
// This is the ultimate fallback, it will be used if none of the formatters from options
// work.

View File

@ -10,6 +10,8 @@ using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -86,6 +88,9 @@ namespace System.Web.Http
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}
}

View File

@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -86,6 +87,8 @@ namespace System.Web.Http
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}

View File

@ -11,6 +11,8 @@ using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -100,6 +102,9 @@ namespace System.Web.Http
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}
}

View File

@ -10,6 +10,8 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -87,6 +89,9 @@ namespace System.Web.Http
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}

View File

@ -9,6 +9,8 @@ using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
@ -60,6 +62,9 @@ namespace System.Web.Http
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}

View File

@ -5,6 +5,7 @@
"dependencies": {
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
"Microsoft.AspNet.Testing": "1.0.0-*",
"Microsoft.Framework.Logging.Testing": "1.0.0-*",
"Moq": "4.2.1312.1622",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
},