CredentialProvider.Microsoft/RequestHandlers/RequestHandlerBase.cs (66 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // // Licensed under the MIT license. using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using NuGet.Common; using NuGet.Protocol.Plugins; using NuGetCredentialProvider.Util; using ILogger = NuGetCredentialProvider.Logging.ILogger; namespace NuGetCredentialProvider.RequestHandlers { /// <summary> /// A base class for implementations of <see cref="IRequestHandler"/>. /// </summary> /// <typeparam name="TRequest">The type of the request message.</typeparam> /// <typeparam name="TResponse">The type of the response message.</typeparam> internal abstract class RequestHandlerBase<TRequest, TResponse> : IRequestHandler where TResponse : class { /// <summary> /// Initializes a new instance of the <see cref="RequestHandlerBase{TRequest, TResponse}"/> class. /// </summary> /// <param name="logger">A <see cref="Logging.ILogger"/> to use for logging.</param> protected RequestHandlerBase(ILogger logger) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// <summary> /// Gets a <see cref="CancellationToken"/> to use. /// </summary> public virtual CancellationToken CancellationToken { get; private set; } = CancellationToken.None; /// <summary> /// Gets the current <see cref="IConnection"/>. /// </summary> public IConnection Connection { get; private set; } /// <summary> /// Gets the current <see cref="ILogger"/> to use for logging. /// </summary> public ILogger Logger { get; } /// <inheritdoc cref="IRequestHandler.HandleResponseAsync"/> public async Task HandleResponseAsync(IConnection connection, Message message, IResponseHandler responseHandler, CancellationToken cancellationToken) { Stopwatch timer = new Stopwatch(); timer.Start(); Connection = connection; TRequest request = MessageUtilities.DeserializePayload<TRequest>(message); try { TResponse response = null; Logger.Verbose(string.Format(Resources.HandlingRequest, message.Type, message.Method, timer.ElapsedMilliseconds, message.Payload.ToString(Formatting.None))); try { using (GetProgressReporter(connection, message, cancellationToken)) { response = await HandleRequestAsync(request).ConfigureAwait(continueOnCapturedContext: false); } } catch (Exception ex) when (cancellationToken.IsCancellationRequested) { // NuGet will handle canceling event but verbose logs in this case might be interesting. Logger.Verbose(string.Format(Resources.RequestHandlerCancelingExceptionMessage, ex.InnerException, ex.Message)); return; } Logger.Verbose(string.Format(Resources.SendingResponse, message.Type, message.Method, timer.ElapsedMilliseconds)); // If we did not send a cancel message, we must submit the response even if cancellationToken is canceled. await responseHandler.SendResponseAsync(message, response, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false); Logger.Verbose(string.Format(Resources.TimeElapsedAfterSendingResponse, message.Type, message.Method, timer.ElapsedMilliseconds)); } catch (Exception ex) { // don't report cancellations to the console during shutdown, they're most likely not interesting. bool cancelingDuringShutdown = ex is OperationCanceledException && Program.IsShuttingDown; if (cancelingDuringShutdown) { Logger.Log(LogLevel.Verbose, allowOnConsole: false, Resources.WhileShuttingDown); } Logger.Log(LogLevel.Verbose, allowOnConsole: !cancelingDuringShutdown, string.Format(Resources.ResponseHandlerException, message.Method, message.RequestId)); Logger.Log(LogLevel.Verbose, allowOnConsole: !cancelingDuringShutdown, ex.ToString()); throw; } timer.Stop(); } public abstract Task<TResponse> HandleRequestAsync(TRequest request); protected virtual AutomaticProgressReporter GetProgressReporter(IConnection connection, Message message, CancellationToken cancellationToken) { return null; } } }