Add logging and scope for ViewComponent
This commit is contained in:
parent
eb398c811d
commit
cea8d019f1
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNet.Localization;
|
|||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MvcSample.Web.Filters;
|
||||
using MvcSample.Web.Services;
|
||||
|
||||
|
|
@ -34,8 +35,18 @@ namespace MvcSample.Web
|
|||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||
{
|
||||
loggerFactory.AddConsole((category, level) =>
|
||||
{
|
||||
if (category.StartsWith("Microsoft."))
|
||||
{
|
||||
return level >= LogLevel.Information;
|
||||
}
|
||||
|
||||
return level >= LogLevel.Verbose;
|
||||
});
|
||||
|
||||
app.UseStatusCodePages();
|
||||
app.UseFileServer();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,37 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||
"Microsoft.AspNet.Localization": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.Session": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"exclude": [
|
||||
"wwwroot",
|
||||
"node_modules",
|
||||
"bower_components"
|
||||
],
|
||||
"publishExclude": [
|
||||
"**.user",
|
||||
"**.vspscc"
|
||||
],
|
||||
"webroot": "wwwroot"
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||
"Microsoft.AspNet.Localization": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.Session": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0-*",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"exclude": [
|
||||
"wwwroot",
|
||||
"node_modules",
|
||||
"bower_components"
|
||||
],
|
||||
"publishExclude": [
|
||||
"**.user",
|
||||
"**.vspscc"
|
||||
],
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Logging
|
||||
{
|
||||
public static class DefaultViewComponentInvokerLoggerExtensions
|
||||
{
|
||||
private static readonly Action<ILogger, string, Exception> _viewComponentExecuting;
|
||||
private static readonly Action<ILogger, string, double, string, Exception> _viewComponentExecuted;
|
||||
|
||||
static DefaultViewComponentInvokerLoggerExtensions()
|
||||
{
|
||||
_viewComponentExecuting = LoggerMessage.Define<string>(
|
||||
LogLevel.Verbose,
|
||||
1,
|
||||
"Executing view component {ViewComponentName}");
|
||||
|
||||
_viewComponentExecuted = LoggerMessage.Define<string, double, string>(
|
||||
LogLevel.Verbose,
|
||||
2,
|
||||
"Executed view component {ViewComponentName} in {ElapsedMilliseconds}ms and returned " +
|
||||
"{ViewComponentResult}");
|
||||
}
|
||||
|
||||
public static IDisposable ViewComponentScope(this ILogger logger, ViewComponentContext context)
|
||||
{
|
||||
return logger.BeginScopeImpl(new ViewComponentLogScope(context.ViewComponentDescriptor));
|
||||
}
|
||||
|
||||
public static void ViewComponentExecuting(this ILogger logger, ViewComponentContext context)
|
||||
{
|
||||
_viewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, null);
|
||||
}
|
||||
|
||||
public static void ViewComponentExecuted(
|
||||
this ILogger logger,
|
||||
ViewComponentContext context,
|
||||
int startTime,
|
||||
object result)
|
||||
{
|
||||
var elapsed = new TimeSpan(Environment.TickCount - startTime);
|
||||
_viewComponentExecuted(
|
||||
logger,
|
||||
context.ViewComponentDescriptor.DisplayName,
|
||||
elapsed.TotalMilliseconds,
|
||||
Convert.ToString(result),
|
||||
null);
|
||||
}
|
||||
|
||||
private class ViewComponentLogScope : ILogValues
|
||||
{
|
||||
private readonly ViewComponentDescriptor _descriptor;
|
||||
|
||||
public ViewComponentLogScope(ViewComponentDescriptor descriptor)
|
||||
{
|
||||
_descriptor = descriptor;
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, object>> GetValues()
|
||||
{
|
||||
return new KeyValuePair<string, object>[]
|
||||
{
|
||||
new KeyValuePair<string, object>("ViewComponentName", _descriptor.DisplayName),
|
||||
new KeyValuePair<string, object>("ViewComponentId", _descriptor.Id),
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _descriptor.DisplayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,8 @@ using Microsoft.AspNet.Mvc.Diagnostics;
|
|||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
|
|
@ -19,11 +21,13 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
private readonly DiagnosticSource _diagnosticSource;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public DefaultViewComponentInvoker(
|
||||
ITypeActivatorCache typeActivatorCache,
|
||||
IViewComponentActivator viewComponentActivator,
|
||||
DiagnosticSource diagnosticSource)
|
||||
DiagnosticSource diagnosticSource,
|
||||
ILogger logger)
|
||||
{
|
||||
if (typeActivatorCache == null)
|
||||
{
|
||||
|
|
@ -40,9 +44,15 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
throw new ArgumentNullException(nameof(diagnosticSource));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
_diagnosticSource = diagnosticSource;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Invoke(ViewComponentContext context)
|
||||
|
|
@ -135,15 +145,20 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
var component = CreateComponent(context);
|
||||
|
||||
_diagnosticSource.BeforeViewComponent(context, component);
|
||||
using (_logger.ViewComponentScope(context))
|
||||
{
|
||||
_diagnosticSource.BeforeViewComponent(context, component);
|
||||
_logger.ViewComponentExecuting(context);
|
||||
|
||||
var result = await ControllerActionExecutor.ExecuteAsync(method, component, context.Arguments);
|
||||
var startTime = Environment.TickCount;
|
||||
var result = await ControllerActionExecutor.ExecuteAsync(method, component, context.Arguments);
|
||||
|
||||
var viewComponentResult = CoerceToViewComponentResult(result);
|
||||
var viewComponentResult = CoerceToViewComponentResult(result);
|
||||
_logger.ViewComponentExecuted(context, startTime, viewComponentResult);
|
||||
_diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
|
||||
|
||||
_diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
|
||||
|
||||
return viewComponentResult;
|
||||
return viewComponentResult;
|
||||
}
|
||||
}
|
||||
|
||||
public IViewComponentResult InvokeSyncCore(MethodInfo method, ViewComponentContext context)
|
||||
|
|
@ -162,24 +177,30 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
object result = null;
|
||||
|
||||
_diagnosticSource.BeforeViewComponent(context, component);
|
||||
|
||||
try
|
||||
using (_logger.ViewComponentScope(context))
|
||||
{
|
||||
result = method.Invoke(component, context.Arguments);
|
||||
_diagnosticSource.BeforeViewComponent(context, component);
|
||||
_logger.ViewComponentExecuting(context);
|
||||
|
||||
try
|
||||
{
|
||||
var startTime = Environment.TickCount;
|
||||
result = method.Invoke(component, context.Arguments);
|
||||
|
||||
var viewComponentResult = CoerceToViewComponentResult(result);
|
||||
_logger.ViewComponentExecuted(context, startTime, viewComponentResult);
|
||||
_diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
|
||||
|
||||
return viewComponentResult;
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
// Preserve callstack of any user-thrown exceptions.
|
||||
var exceptionInfo = ExceptionDispatchInfo.Capture(ex.InnerException);
|
||||
exceptionInfo.Throw();
|
||||
return null; // Unreachable
|
||||
}
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
// Preserve callstack of any user-thrown exceptions.
|
||||
var exceptionInfo = ExceptionDispatchInfo.Capture(ex.InnerException);
|
||||
exceptionInfo.Throw();
|
||||
}
|
||||
|
||||
var viewComponentResult = CoerceToViewComponentResult(result);
|
||||
|
||||
_diagnosticSource.AfterViewComponent(context, viewComponentResult, component);
|
||||
|
||||
return viewComponentResult;
|
||||
}
|
||||
|
||||
private static IViewComponentResult CoerceToViewComponentResult(object value)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
|
|
@ -11,16 +12,20 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
{
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
private readonly ILogger _logger;
|
||||
private readonly DiagnosticSource _diagnosticSource;
|
||||
|
||||
public DefaultViewComponentInvokerFactory(
|
||||
ITypeActivatorCache typeActivatorCache,
|
||||
IViewComponentActivator viewComponentActivator,
|
||||
DiagnosticSource diagnosticSource)
|
||||
DiagnosticSource diagnosticSource,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
_diagnosticSource = diagnosticSource;
|
||||
|
||||
_logger = loggerFactory.CreateLogger<DefaultViewComponentInvoker>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -37,7 +42,8 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
return new DefaultViewComponentInvoker(
|
||||
_typeActivatorCache,
|
||||
_viewComponentActivator,
|
||||
_diagnosticSource);
|
||||
_diagnosticSource,
|
||||
_logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,52 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// A descriptor for a View Component.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DisplayName}")]
|
||||
public class ViewComponentDescriptor
|
||||
{
|
||||
private string _displayName;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ViewComponentDescriptor"/>.
|
||||
/// </summary>
|
||||
public ViewComponentDescriptor()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the View Component.
|
||||
/// </summary>
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_displayName == null)
|
||||
{
|
||||
_displayName = Type?.FullName;
|
||||
}
|
||||
|
||||
return _displayName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
_displayName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the full name.
|
||||
/// </summary>
|
||||
|
|
@ -41,6 +79,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
/// </remarks>
|
||||
public string FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the generated unique identifier for this <see cref="ViewComponentDescriptor"/>.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the short name.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Reference in New Issue