Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@ -0,0 +1,147 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Net.Http.Formatting;
using System.Text;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ModelBinding.Binders;
using System.Web.Http.Properties;
using System.Web.Http.Routing;
using System.Web.Http.ValueProviders;
using System.Web.Http.ValueProviders.Providers;
namespace System.Web.Http.Tracing
{
/// <summary>
/// General purpose utilities to format strings used in tracing.
/// </summary>
internal static class FormattingUtilities
{
public static readonly string NullMessage = "null";
public static string ActionArgumentsToString(IDictionary<string, object> actionArguments)
{
Contract.Assert(actionArguments != null);
return string.Join(", ",
actionArguments.Keys.Select<string, string>(
(k) => k + "=" + ValueToString(actionArguments[k], CultureInfo.CurrentCulture)));
}
public static string ActionDescriptorToString(HttpActionDescriptor actionDescriptor)
{
Contract.Assert(actionDescriptor != null);
string parameterList = string.Join(", ",
actionDescriptor.GetParameters().Select<HttpParameterDescriptor, string>(
(p) => p.ParameterType.Name + " " + p.ParameterName));
return actionDescriptor.ActionName + "(" + parameterList + ")";
}
public static string ActionInvokeToString(HttpActionContext actionContext)
{
Contract.Assert(actionContext != null);
return ActionInvokeToString(actionContext.ActionDescriptor.ActionName, actionContext.ActionArguments);
}
public static string ActionInvokeToString(string actionName, IDictionary<string, object> arguments)
{
Contract.Assert(actionName != null);
Contract.Assert(arguments != null);
return actionName + "(" + ActionArgumentsToString(arguments) + ")";
}
public static string FormattersToString(IEnumerable<MediaTypeFormatter> formatters)
{
Contract.Assert(formatters != null);
return String.Join(", ", formatters.Select<MediaTypeFormatter, string>((f) => f.GetType().Name));
}
public static string ModelBinderToString(ModelBinderProvider provider)
{
Contract.Assert(provider != null);
CompositeModelBinderProvider composite = provider as CompositeModelBinderProvider;
if (composite == null)
{
return provider.GetType().Name;
}
string modelBinderList = string.Join(", ", composite.Providers.Select<ModelBinderProvider, string>(ModelBinderToString));
return provider.GetType().Name + "(" + modelBinderList + ")";
}
public static string ModelStateToString(ModelStateDictionary modelState)
{
Contract.Assert(modelState != null);
if (modelState.IsValid)
{
return String.Empty;
}
StringBuilder modelStateBuilder = new StringBuilder();
foreach (string key in modelState.Keys)
{
ModelState state = modelState[key];
if (state.Errors.Count > 0)
{
foreach (ModelError error in state.Errors)
{
string errorString = Error.Format(SRResources.TraceModelStateErrorMessage,
key,
error.ErrorMessage);
if (modelStateBuilder.Length > 0)
{
modelStateBuilder.Append(',');
}
modelStateBuilder.Append(errorString);
}
}
}
return modelStateBuilder.ToString();
}
public static string RouteToString(IHttpRouteData routeData)
{
Contract.Assert(routeData != null);
return String.Join(",", routeData.Values.Select((pair) => Error.Format("{0}:{1}", pair.Key, pair.Value)));
}
public static string ValueProviderToString(IValueProvider provider)
{
Contract.Assert(provider != null);
CompositeValueProvider composite = provider as CompositeValueProvider;
if (composite == null)
{
return provider.GetType().Name;
}
string providerList = string.Join(", ", composite.Select<IValueProvider, string>(ValueProviderToString));
return provider.GetType().Name + "(" + providerList + ")";
}
public static string ValueToString(object value, CultureInfo cultureInfo)
{
Contract.Assert(cultureInfo != null);
if (value == null)
{
return NullMessage;
}
return Convert.ToString(value, cultureInfo);
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Tracing.Tracers;
namespace System.Web.Http.Tracing
{
/// <summary>
/// Interface used to mark <see cref="MediaTypeFormatterTracer"/> classes.
/// </summary>
internal interface IFormatterTracer
{
/// <summary>
/// Gets the associated <see cref="HttpRequestMessage"/>.
/// </summary>
HttpRequestMessage Request { get; }
/// <summary>
/// Gets the inner <see cref="MediaTypeFormatter"/> this tracer is monitoring.
/// </summary>
MediaTypeFormatter InnerFormatter { get; }
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Http.Tracing
{
/// <summary>
/// Interface to initialize the tracing layer.
/// </summary>
/// <remarks>
/// This is an extensibility interface that may be inserted into
/// <see cref="HttpConfiguration.Services"/> to provide a replacement for the
/// entire tracing layer.
/// </remarks>
public interface ITraceManager
{
void Initialize(HttpConfiguration configuration);
}
}

View File

@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
namespace System.Web.Http.Tracing
{
/// <summary>
/// Interface to write <see cref="TraceRecord"/> instances.
/// </summary>
public interface ITraceWriter
{
/// <summary>
/// Determines whether tracing is currently enabled for the given <paramref name="category"/>
/// and <paramref name="level"/>.
/// </summary>
/// <param name="category">The trace category.</param>
/// <param name="level">The <see cref="TraceLevel"/></param>
/// <returns>Returns <c>true</c> if tracing is currently enabled for the category and level,
/// otherwise returns <c>false</c>.</returns>
bool IsEnabled(string category, TraceLevel level);
/// <summary>
/// Invokes the specified <paramref name="traceAction"/> to allow setting values in
/// a new <see cref="TraceRecord"/> if and only if tracing is permitted at the given
/// <paramref name="category"/> and <paramref name="level"/>.
/// </summary>
/// <remarks>
/// If tracing is permitted at the given category and level, the <see cref="ITraceWriter"/>
/// will construct a <see cref="TraceRecord"/> and invoke the caller's action to allow
/// it to set values in the <see cref="TraceRecord"/> provided to it.
/// When the caller's action returns, the <see cref="TraceRecord"/>
/// will be recorded. If tracing is not enabled, <paramref name="traceAction"/> will not be called.
/// </remarks>
/// <param name="request">The current <see cref="HttpRequestMessage"/>.
/// It may be <c>null</c> but doing so will prevent subsequent trace analysis
/// from correlating the trace to a particular request.</param>
/// <param name="category">The logical category for the trace. Users can define their own.</param>
/// <param name="level">The <see cref="TraceLevel"/> at which to write this trace.</param>
/// <param name="traceAction">The action to invoke if tracing is enabled. The caller is expected
/// to fill in the fields of the given <see cref="TraceRecord"/> in this action.</param>
void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Http.Tracing
{
/// <summary>
/// Category names traced by the default tracing implementation.
/// </summary>
/// <remarks>
/// The list of permitted category names is open-ended, and users may define their own.
/// It is recommended that category names reflect the namespace of their
/// respective area. This prevents name conflicts and allows external
/// logging tools to enable or disable tracing by namespace.
/// </remarks>
public static class TraceCategories
{
public static readonly string ActionCategory = "System.Web.Http.Action";
public static readonly string ControllersCategory = "System.Web.Http.Controllers";
public static readonly string FiltersCategory = "System.Web.Http.Filters";
public static readonly string FormattingCategory = "System.Net.Http.Formatting";
public static readonly string MessageHandlersCategory = "System.Web.Http.MessageHandlers";
public static readonly string ModelBindingCategory = "System.Web.Http.ModelBinding";
public static readonly string RequestCategory = "System.Web.Http.Request";
public static readonly string RoutingCategory = "System.Web.Http.Routing";
}
}

View File

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Http.Tracing
{
/// <summary>
/// Describes the kind of <see cref="TraceRecord"/> for an individual trace operation.
/// </summary>
public enum TraceKind
{
/// <summary>
/// Single trace, not part of a Begin/End trace pair
/// </summary>
Trace,
/// <summary>
/// Trace marking the beginning of some operation.
/// </summary>
Begin,
/// <summary>
/// Trace marking the end of some operation.
/// </summary>
End,
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.Http.Tracing
{
/// <summary>
/// Available trace levels.
/// </summary>
/// <remarks>
/// The interpretation of these levels is the responsibility of the
/// <see cref="ITraceWriter"/> implementation. The general convention is that
/// enabling a particular trace level also enables all levels greater than or
/// equal to it. For example, tracing at <see cref="Warn"/> level would
/// generally trace if the trace writer was enabled to trace at level <see cref="Info"/>.
/// </remarks>
public enum TraceLevel
{
/// <summary>
/// Tracing is disabled
/// </summary>
Off = 0,
/// <summary>
/// Trace level for debugging traces
/// </summary>
Debug = 1,
/// <summary>
/// Trace level for informational traces
/// </summary>
Info = 2,
/// <summary>
/// Trace level for warning traces
/// </summary>
Warn = 3,
/// <summary>
/// Trace level for error traces
/// </summary>
Error = 4,
/// <summary>
/// Trace level for fatal traces
/// </summary>
Fatal = 5
}
}

View File

@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using System.Web.Http.Tracing.Tracers;
namespace System.Web.Http.Tracing
{
internal class TraceManager : ITraceManager
{
public void Initialize(HttpConfiguration configuration)
{
ITraceWriter traceWriter = configuration.Services.GetTraceWriter();
if (traceWriter != null)
{
// Install tracers only when a custom trace writer has been registered
CreateAllTracers(configuration, traceWriter);
}
}
private static void CreateAllTracers(HttpConfiguration configuration, ITraceWriter traceWriter)
{
CreateActionInvokerTracer(configuration, traceWriter);
CreateActionSelectorTracer(configuration, traceWriter);
CreateActionValueBinderTracer(configuration, traceWriter);
CreateContentNegotiatorTracer(configuration, traceWriter);
CreateControllerActivatorTracer(configuration, traceWriter);
CreateControllerSelectorTracer(configuration, traceWriter);
CreateMessageHandlerTracers(configuration, traceWriter);
CreateMediaTypeFormatterTracers(configuration, traceWriter);
}
private static void CreateActionInvokerTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IHttpActionInvoker invoker = configuration.Services.GetActionInvoker();
HttpActionInvokerTracer tracer = new HttpActionInvokerTracer(invoker, traceWriter);
configuration.Services.Replace(typeof(IHttpActionInvoker), tracer);
}
private static void CreateActionSelectorTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IHttpActionSelector selector = configuration.Services.GetActionSelector();
HttpActionSelectorTracer tracer = new HttpActionSelectorTracer(selector, traceWriter);
configuration.Services.Replace(typeof(IHttpActionSelector), tracer);
}
private static void CreateActionValueBinderTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IActionValueBinder binder = configuration.Services.GetActionValueBinder();
ActionValueBinderTracer tracer = new ActionValueBinderTracer(binder, traceWriter);
configuration.Services.Replace(typeof(IActionValueBinder), tracer);
}
private static void CreateContentNegotiatorTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IContentNegotiator negotiator = configuration.Services.GetContentNegotiator();
ContentNegotiatorTracer tracer = new ContentNegotiatorTracer(negotiator, traceWriter);
configuration.Services.Replace(typeof(IContentNegotiator), tracer);
}
private static void CreateControllerActivatorTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IHttpControllerActivator activator = configuration.Services.GetHttpControllerActivator();
HttpControllerActivatorTracer tracer = new HttpControllerActivatorTracer(activator, traceWriter);
configuration.Services.Replace(typeof(IHttpControllerActivator), tracer);
}
private static void CreateControllerSelectorTracer(HttpConfiguration configuration, ITraceWriter traceWriter)
{
IHttpControllerSelector controllerSelector = configuration.Services.GetHttpControllerSelector();
HttpControllerSelectorTracer tracer = new HttpControllerSelectorTracer(controllerSelector, traceWriter);
configuration.Services.Replace(typeof(IHttpControllerSelector), tracer);
}
private static void CreateMediaTypeFormatterTracers(HttpConfiguration configuration, ITraceWriter traceWriter)
{
for (int i = 0; i < configuration.Formatters.Count; i++)
{
configuration.Formatters[i] = MediaTypeFormatterTracer.CreateTracer(
configuration.Formatters[i],
traceWriter,
request: null);
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Will be disposed when pipeline is disposed.")]
private static void CreateMessageHandlerTracers(HttpConfiguration configuration, ITraceWriter traceWriter)
{
// Insert a tracing handler before each existing message handler (in execution order)
int handlerCount = configuration.MessageHandlers.Count;
for (int i = 0; i < handlerCount * 2; i += 2)
{
DelegatingHandler innerHandler = configuration.MessageHandlers[i];
DelegatingHandler handlerTracer = new MessageHandlerTracer(innerHandler, traceWriter);
configuration.MessageHandlers.Insert(i + 1, handlerTracer);
}
configuration.MessageHandlers.Add(new RequestMessageHandlerTracer(traceWriter));
}
}
}

View File

@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
namespace System.Web.Http.Tracing
{
/// <summary>
/// Data object used by <see cref="ITraceWriter"/> to record traces.
/// </summary>
public class TraceRecord
{
private Lazy<Dictionary<object, object>> _properties = new Lazy<Dictionary<object, object>>(
() => new Dictionary<object, object>());
public TraceRecord(HttpRequestMessage request, string category, TraceLevel level)
{
Timestamp = DateTime.UtcNow;
Request = request;
RequestId = request != null ? request.GetCorrelationId() : Guid.Empty;
Category = category;
Level = level;
}
/// <summary>
/// Gets or sets the tracing category.
/// </summary>
public string Category { get; set; }
/// <summary>
/// Gets or sets the exception.
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// Gets or sets the kind of trace.
/// </summary>
public TraceKind Kind { get; set; }
/// <summary>
/// Gets or sets the tracing level.
/// </summary>
public TraceLevel Level { get; set; }
/// <summary>
/// Gets or sets the message.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Gets or sets the logical operation name being performed.
/// </summary>
public string Operation { get; set; }
/// <summary>
/// Gets or sets the logical name of the object performing the operation
/// </summary>
public string Operator { get; set; }
/// <summary>
/// Optional user-defined property bag.
/// </summary>
public Dictionary<object, object> Properties
{
get { return _properties.Value; }
}
/// <summary>
/// Gets the <see cref="HttpRequestMessage"/>
/// </summary>
public HttpRequestMessage Request { get; private set; }
/// <summary>
/// Gets the correlation ID from the <see cref="Request"/>.
/// </summary>
public Guid RequestId { get; private set; }
/// <summary>
/// Gets or sets the <see cref="HttpStatusCode"/> associated with the <see cref="HttpResponseMessage"/>.
/// </summary>
public HttpStatusCode Status { get; set; }
/// <summary>
/// Gets the <see cref="DateTime"/> of this trace (via <see cref="DateTime.UtcNow"/>)
/// </summary>
public DateTime Timestamp { get; private set; }
}
}

View File

@ -0,0 +1,114 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.Properties;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="ActionFilterAttribute"/>.
/// </summary>
internal sealed class ActionFilterAttributeTracer : ActionFilterAttribute
{
private const string ActionExecutedMethodName = "ActionExecuted";
private const string ActionExecutingMethodName = "ActionExecuting";
private readonly ActionFilterAttribute _innerFilter;
private readonly ITraceWriter _traceWriter;
public ActionFilterAttributeTracer(ActionFilterAttribute innerFilter, ITraceWriter traceWriter)
{
_innerFilter = innerFilter;
_traceWriter = traceWriter;
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
_traceWriter.TraceBeginEnd(
actionExecutedContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
_innerFilter.GetType().Name,
ActionExecutedMethodName,
beginTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceActionFilterMessage,
FormattingUtilities.ActionDescriptorToString(
actionExecutedContext.ActionContext.ActionDescriptor));
tr.Exception = actionExecutedContext.Exception;
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
execute: () =>
{
_innerFilter.OnActionExecuted(actionExecutedContext);
},
endTrace: (tr) =>
{
tr.Exception = actionExecutedContext.Exception;
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: (tr) =>
{
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
});
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
_traceWriter.TraceBeginEnd(
actionContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
_innerFilter.GetType().Name,
ActionExecutingMethodName,
beginTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceActionFilterMessage,
FormattingUtilities.ActionDescriptorToString(
actionContext.ActionDescriptor));
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
execute: () =>
{
_innerFilter.OnActionExecuting(actionContext);
},
endTrace: (tr) =>
{
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: (tr) =>
{
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
});
}
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="IActionFilter"/>.
/// </summary>
internal class ActionFilterTracer : FilterTracer, IActionFilter
{
private const string ExecuteActionFilterAsyncMethodName = "ExecuteActionFilterAsync";
public ActionFilterTracer(IActionFilter innerFilter, ITraceWriter traceWriter)
: base(innerFilter, traceWriter)
{
}
private IActionFilter InnerActionFilter
{
get { return InnerFilter as IActionFilter; }
}
Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
return TraceWriter.TraceBeginEndAsync<HttpResponseMessage>(
actionContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
InnerActionFilter.GetType().Name,
ExecuteActionFilterAsyncMethodName,
beginTrace: null,
execute: () => InnerActionFilter.ExecuteActionFilterAsync(actionContext, cancellationToken, continuation),
endTrace: (tr, response) =>
{
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: null);
}
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="IActionValueBinder"/>
/// </summary>
internal class ActionValueBinderTracer : IActionValueBinder
{
private readonly IActionValueBinder _innerBinder;
private readonly ITraceWriter _traceWriter;
public ActionValueBinderTracer(IActionValueBinder innerBinder, ITraceWriter traceWriter)
{
_innerBinder = innerBinder;
_traceWriter = traceWriter;
}
// Creates wrapping tracers for all HttpParameterBindings
HttpActionBinding IActionValueBinder.GetBinding(HttpActionDescriptor actionDescriptor)
{
HttpActionBinding actionBinding = _innerBinder.GetBinding(actionDescriptor);
HttpParameterBinding[] parameterBindings = actionBinding.ParameterBindings;
HttpParameterBinding[] newParameterBindings = new HttpParameterBinding[parameterBindings.Length];
for (int i = 0; i < newParameterBindings.Length; i++)
{
HttpParameterBinding parameterBinding = parameterBindings[i];
// Itercept FormatterParameterBinding to replace its formatters
FormatterParameterBinding formatterParameterBinding = parameterBinding as FormatterParameterBinding;
newParameterBindings[i] = formatterParameterBinding != null
? (HttpParameterBinding)new FormatterParameterBindingTracer(formatterParameterBinding, _traceWriter)
: (HttpParameterBinding)new HttpParameterBindingTracer(parameterBinding, _traceWriter);
}
// Replace the inner HttpActionBinding's parameter bindings with our tracing versions.
// This allows each individual parameter binding to trace.
actionBinding.ParameterBindings = newParameterBindings;
// Then create an HttpActionBindingTracer to wrap the actual HttpActionBinding
return new HttpActionBindingTracer(actionBinding, _traceWriter);
}
}
}

View File

@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="AuthorizationFilterAttribute"/>
/// </summary>
internal sealed class AuthorizationFilterAttributeTracer : AuthorizationFilterAttribute
{
private const string OnAuthorizationMethodName = "OnAuthorization";
private readonly AuthorizationFilterAttribute _innerFilter;
private readonly ITraceWriter _traceStore;
public AuthorizationFilterAttributeTracer(AuthorizationFilterAttribute innerFilter, ITraceWriter traceStore)
{
_innerFilter = innerFilter;
_traceStore = traceStore;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
_traceStore.TraceBeginEnd(
actionContext.ControllerContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
_innerFilter.GetType().Name,
OnAuthorizationMethodName,
beginTrace: (tr) =>
{
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
execute: () => { _innerFilter.OnAuthorization(actionContext); },
endTrace: (tr) =>
{
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: (tr) =>
{
HttpResponseMessage response = actionContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
});
}
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="IAuthorizationFilter"/>.
/// </summary>
internal class AuthorizationFilterTracer : FilterTracer, IAuthorizationFilter
{
private const string ExecuteAuthorizationFilterAsyncMethodName = "ExecuteAuthorizationFilterAsync";
public AuthorizationFilterTracer(IAuthorizationFilter innerFilter, ITraceWriter traceWriter)
: base(innerFilter, traceWriter)
{
}
private IAuthorizationFilter InnerAuthorizationFilter
{
get { return InnerFilter as IAuthorizationFilter; }
}
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
return TraceWriter.TraceBeginEndAsync<HttpResponseMessage>(
actionContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
InnerAuthorizationFilter.GetType().Name,
ExecuteAuthorizationFilterAsyncMethodName,
beginTrace: null,
execute: () => InnerAuthorizationFilter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation),
endTrace: (tr, response) =>
{
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: null);
}
}
}

View File

@ -0,0 +1,123 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web.Http.Properties;
namespace System.Web.Http.Tracing.Tracers
{
internal class BufferedMediaTypeFormatterTracer : BufferedMediaTypeFormatter, IFormatterTracer
{
private const string OnReadFromStreamMethodName = "ReadFromStream";
private const string OnWriteToStreamMethodName = "WriteToStream";
private MediaTypeFormatterTracer _innerTracer;
public BufferedMediaTypeFormatterTracer(MediaTypeFormatter innerFormatter, ITraceWriter traceWriter, HttpRequestMessage request)
{
_innerTracer = new MediaTypeFormatterTracer(innerFormatter, traceWriter, request);
}
private BufferedMediaTypeFormatter InnerBufferedFormatter
{
get { return _innerTracer.InnerFormatter as BufferedMediaTypeFormatter; }
}
HttpRequestMessage IFormatterTracer.Request
{
get { return _innerTracer.Request; }
}
MediaTypeFormatter IFormatterTracer.InnerFormatter
{
get { return _innerTracer.InnerFormatter; }
}
public override bool CanReadType(Type type)
{
return _innerTracer.CanReadType(type);
}
public override bool CanWriteType(Type type)
{
return _innerTracer.CanWriteType(type);
}
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
return _innerTracer.GetPerRequestFormatterInstance(type, request, mediaType);
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, string mediaType)
{
_innerTracer.SetDefaultContentHeaders(type, headers, mediaType);
}
public override object ReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
BufferedMediaTypeFormatter innerFormatter = InnerBufferedFormatter;
MediaTypeHeaderValue contentType = contentHeaders == null ? null : contentHeaders.ContentType;
object value = null;
_innerTracer.TraceWriter.TraceBeginEnd(
_innerTracer.Request,
TraceCategories.FormattingCategory,
TraceLevel.Info,
_innerTracer.InnerFormatter.GetType().Name,
OnReadFromStreamMethodName,
beginTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceReadFromStreamMessage,
type.Name,
contentType == null ? SRResources.TraceNoneObjectMessage : contentType.ToString());
},
execute: () =>
{
value = innerFormatter.ReadFromStream(type, stream, contentHeaders, formatterLogger);
},
endTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceReadFromStreamValueMessage,
FormattingUtilities.ValueToString(value, CultureInfo.CurrentCulture));
},
errorTrace: null);
return value;
}
public override void WriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
{
BufferedMediaTypeFormatter innerFormatter = InnerBufferedFormatter;
MediaTypeHeaderValue contentType = contentHeaders == null
? null
: contentHeaders.ContentType;
_innerTracer.TraceWriter.TraceBeginEnd(
_innerTracer.Request,
TraceCategories.FormattingCategory,
TraceLevel.Info,
_innerTracer.InnerFormatter.GetType().Name,
OnWriteToStreamMethodName,
beginTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceWriteToStreamMessage,
FormattingUtilities.ValueToString(value, CultureInfo.CurrentCulture),
type.Name,
contentType == null ? SRResources.TraceNoneObjectMessage : contentType.ToString());
},
execute: () =>
{
innerFormatter.WriteToStream(type, value, stream, contentHeaders);
},
endTrace: null,
errorTrace: null);
}
}
}

View File

@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Properties;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="IContentNegotiator"/>.
/// </summary>
internal class ContentNegotiatorTracer : IContentNegotiator
{
private const string NegotiateMethodName = "Negotiate";
private readonly IContentNegotiator _innerNegotiator;
private readonly ITraceWriter _traceWriter;
public ContentNegotiatorTracer(IContentNegotiator innerNegotiator, ITraceWriter traceWriter)
{
_innerNegotiator = innerNegotiator;
_traceWriter = traceWriter;
}
public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
ContentNegotiationResult result = null;
_traceWriter.TraceBeginEnd(
request,
TraceCategories.FormattingCategory,
TraceLevel.Info,
_innerNegotiator.GetType().Name,
NegotiateMethodName,
beginTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceNegotiateFormatter,
type.Name,
FormattingUtilities.FormattersToString(formatters));
},
execute: () =>
{
result = _innerNegotiator.Negotiate(type, request, formatters);
},
endTrace: (tr) =>
{
tr.Message = Error.Format(
SRResources.TraceSelectedFormatter,
result == null
? SRResources.TraceNoneObjectMessage
: MediaTypeFormatterTracer.ActualMediaTypeFormatter(result.Formatter).GetType().Name,
result == null || result.MediaType == null
? SRResources.TraceNoneObjectMessage
: result.MediaType.ToString());
},
errorTrace: null);
if (result != null)
{
result.Formatter = MediaTypeFormatterTracer.CreateTracer(result.Formatter, _traceWriter, request);
}
return result;
}
}
}

View File

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="ExceptionFilterAttribute"/>.
/// </summary>
internal sealed class ExceptionFilterAttributeTracer : ExceptionFilterAttribute
{
private const string OnExceptionMethodName = "OnException";
private readonly ExceptionFilterAttribute _innerFilter;
private readonly ITraceWriter _traceStore;
public ExceptionFilterAttributeTracer(ExceptionFilterAttribute innerFilter, ITraceWriter traceStore)
{
_innerFilter = innerFilter;
_traceStore = traceStore;
}
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
_traceStore.TraceBeginEnd(
actionExecutedContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
_innerFilter.GetType().Name,
OnExceptionMethodName,
beginTrace: (tr) =>
{
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
execute: () =>
{
_innerFilter.OnException(actionExecutedContext);
},
endTrace: (tr) =>
{
Exception returnedException = actionExecutedContext.Exception;
tr.Level = returnedException == null ? TraceLevel.Info : TraceLevel.Error;
tr.Exception = returnedException;
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
},
errorTrace: (tr) =>
{
HttpResponseMessage response = actionExecutedContext.Response;
if (response != null)
{
tr.Status = response.StatusCode;
}
});
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Tracer for <see cref="IExceptionFilter"/>.
/// </summary>
internal class ExceptionFilterTracer : FilterTracer, IExceptionFilter
{
private const string ExecuteExceptionFilterAsyncMethodName = "ExecuteExceptionFilterAsync";
public ExceptionFilterTracer(IExceptionFilter innerFilter, ITraceWriter traceWriter)
: base(innerFilter, traceWriter)
{
}
public IExceptionFilter InnerExceptionFilter
{
get { return InnerFilter as IExceptionFilter; }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.WebAPI", "CR4001:DoNotCallProblematicMethodsOnTask", Justification = "This layer needs to observe all completion paths")]
public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext,
CancellationToken cancellationToken)
{
return TraceWriter.TraceBeginEndAsync(
actionExecutedContext.Request,
TraceCategories.FiltersCategory,
TraceLevel.Info,
InnerExceptionFilter.GetType().Name,
ExecuteExceptionFilterAsyncMethodName,
beginTrace: (tr) =>
{
tr.Exception = actionExecutedContext.Exception;
},
execute: () => InnerExceptionFilter.ExecuteExceptionFilterAsync(actionExecutedContext, cancellationToken),
endTrace: (tr) =>
{
tr.Exception = actionExecutedContext.Exception;
},
errorTrace: null);
}
}
}

View File

@ -0,0 +1,106 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Http.Filters;
namespace System.Web.Http.Tracing.Tracers
{
/// <summary>
/// Base class and helper for the creation of filter tracers.
/// </summary>
internal class FilterTracer : IFilter
{
public FilterTracer(IFilter innerFilter, ITraceWriter traceWriter)
{
InnerFilter = innerFilter;
TraceWriter = traceWriter;
}
public IFilter InnerFilter { get; set; }
public ITraceWriter TraceWriter { get; set; }
public bool AllowMultiple
{
get { return InnerFilter.AllowMultiple; }
}
public static IEnumerable<IFilter> CreateFilterTracers(IFilter filter, ITraceWriter traceWriter)
{
List<IFilter> filters = new List<IFilter>();
bool addedActionAttributeTracer = false;
bool addedAuthorizationAttributeTracer = false;
bool addedExceptionAttributeTracer = false;
ActionFilterAttribute actionFilterAttribute = filter as ActionFilterAttribute;
if (actionFilterAttribute != null)
{
filters.Add(new ActionFilterAttributeTracer(actionFilterAttribute, traceWriter));
addedActionAttributeTracer = true;
}
AuthorizationFilterAttribute authorizationFilterAttribute = filter as AuthorizationFilterAttribute;
if (authorizationFilterAttribute != null)
{
filters.Add(new AuthorizationFilterAttributeTracer(authorizationFilterAttribute, traceWriter));
addedAuthorizationAttributeTracer = true;
}
ExceptionFilterAttribute exceptionFilterAttribute = filter as ExceptionFilterAttribute;
if (exceptionFilterAttribute != null)
{
filters.Add(new ExceptionFilterAttributeTracer(exceptionFilterAttribute, traceWriter));
addedExceptionAttributeTracer = true;
}
// Do not add an IActionFilter tracer if we already added an ActionFilterAttribute tracer
IActionFilter actionFilter = filter as IActionFilter;
if (actionFilter != null && !addedActionAttributeTracer)
{
filters.Add(new ActionFilterTracer(actionFilter, traceWriter));
}
// Do not add an IAuthorizationFilter tracer if we already added an AuthorizationFilterAttribute tracer
IAuthorizationFilter authorizationFilter = filter as IAuthorizationFilter;
if (authorizationFilter != null && !addedAuthorizationAttributeTracer)
{
filters.Add(new AuthorizationFilterTracer(authorizationFilter, traceWriter));
}
// Do not add an IExceptionFilter tracer if we already added an ExceptoinFilterAttribute tracer
IExceptionFilter exceptionFilter = filter as IExceptionFilter;
if (exceptionFilter != null && !addedExceptionAttributeTracer)
{
filters.Add(new ExceptionFilterTracer(exceptionFilter, traceWriter));
}
if (filters.Count == 0)
{
filters.Add(new FilterTracer(filter, traceWriter));
}
return filters;
}
public static IEnumerable<FilterInfo> CreateFilterTracers(FilterInfo filter, ITraceWriter traceWriter)
{
IFilter filterInstance = filter.Instance;
IEnumerable<IFilter> filterTracers = CreateFilterTracers(filterInstance, traceWriter);
List<FilterInfo> filters = new List<FilterInfo>();
foreach (IFilter filterTracer in filterTracers)
{
filters.Add(new FilterInfo(filterTracer, filter.Scope));
}
return filters;
}
public static bool IsFilterTracer(IFilter filter)
{
return filter is FilterTracer ||
filter is ActionFilterAttributeTracer ||
filter is AuthorizationFilterAttributeTracer ||
filter is ExceptionFilterAttributeTracer;
}
}
}

Some files were not shown because too many files have changed in this diff Show More