/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Shared/StackTrace/ExceptionDetails/ExceptionDetailsProvider.cs
181 строка
6 KB
Brennan
Add rule to seal internal and private types (#41457)
05 май 2022, 19:26
Не верифицирован
05 май 2022, 19:26
3ea008c
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; #nullable enable namespace Microsoft.Extensions.StackTrace.Sources; internal sealed class ExceptionDetailsProvider { private readonly IFileProvider _fileProvider; private readonly ILogger? _logger; private readonly int _sourceCodeLineCount; public ExceptionDetailsProvider(IFileProvider fileProvider, ILogger? logger, int sourceCodeLineCount) { _fileProvider = fileProvider; _logger = logger; _sourceCodeLineCount = sourceCodeLineCount; } public IEnumerable<ExceptionDetails> GetDetails(Exception exception) { var exceptions = FlattenAndReverseExceptionTree(exception); foreach (var ex in exceptions) { yield return new ExceptionDetails(ex, GetStackFrames(ex)); } } private IEnumerable<StackFrameSourceCodeInfo> GetStackFrames(Exception original) { var stackFrames = StackTraceHelper.GetFrames(original, out var exception) .Select(frame => GetStackFrameSourceCodeInfo( frame.MethodDisplayInfo?.ToString(), frame.FilePath, frame.LineNumber)); if (exception != null) { _logger?.FailedToReadStackTraceInfo(exception); } return stackFrames; } private static IEnumerable<Exception> FlattenAndReverseExceptionTree(Exception? ex) { // ReflectionTypeLoadException is special because the details are in // the LoaderExceptions property var typeLoadException = ex as ReflectionTypeLoadException; if (typeLoadException != null) { var typeLoadExceptions = new List<Exception>(); foreach (var loadException in typeLoadException.LoaderExceptions) { typeLoadExceptions.AddRange(FlattenAndReverseExceptionTree(loadException)); } typeLoadExceptions.Add(typeLoadException); return typeLoadExceptions; } var list = new List<Exception>(); if (ex is AggregateException aggregateException) { list.Add(ex); foreach (var innerException in aggregateException.Flatten().InnerExceptions) { list.Add(innerException); } } else { while (ex != null) { list.Add(ex); ex = ex.InnerException; } list.Reverse(); } return list; } // make it internal to enable unit testing internal StackFrameSourceCodeInfo GetStackFrameSourceCodeInfo(string? method, string? filePath, int lineNumber) { var stackFrame = new StackFrameSourceCodeInfo { Function = method, File = filePath, Line = lineNumber }; if (string.IsNullOrEmpty(stackFrame.File)) { return stackFrame; } IEnumerable<string>? lines = null; if (File.Exists(stackFrame.File)) { lines = File.ReadLines(stackFrame.File); } else { // Handle relative paths and embedded files var fileInfo = _fileProvider.GetFileInfo(stackFrame.File); if (fileInfo.Exists) { // ReadLines doesn't accept a stream. Use ReadLines as its more efficient // relative to reading lines via stream reader if (!string.IsNullOrEmpty(fileInfo.PhysicalPath)) { lines = File.ReadLines(fileInfo.PhysicalPath); } else { lines = ReadLines(fileInfo); } } } if (lines != null) { ReadFrameContent(stackFrame, lines, stackFrame.Line, stackFrame.Line); } return stackFrame; } // make it internal to enable unit testing internal void ReadFrameContent( StackFrameSourceCodeInfo frame, IEnumerable<string> allLines, int errorStartLineNumberInFile, int errorEndLineNumberInFile) { // Get the line boundaries in the file to be read and read all these lines at once into an array. var preErrorLineNumberInFile = Math.Max(errorStartLineNumberInFile - _sourceCodeLineCount, 1); var postErrorLineNumberInFile = errorEndLineNumberInFile + _sourceCodeLineCount; var codeBlock = allLines .Skip(preErrorLineNumberInFile - 1) .Take(postErrorLineNumberInFile - preErrorLineNumberInFile + 1) .ToArray(); var numOfErrorLines = (errorEndLineNumberInFile - errorStartLineNumberInFile) + 1; var errorStartLineNumberInArray = errorStartLineNumberInFile - preErrorLineNumberInFile; frame.PreContextLine = preErrorLineNumberInFile; frame.PreContextCode = codeBlock.Take(errorStartLineNumberInArray).ToArray(); frame.ContextCode = codeBlock .Skip(errorStartLineNumberInArray) .Take(numOfErrorLines) .ToArray(); frame.PostContextCode = codeBlock .Skip(errorStartLineNumberInArray + numOfErrorLines) .ToArray(); } private static IEnumerable<string> ReadLines(IFileInfo fileInfo) { using (var reader = new StreamReader(fileInfo.CreateReadStream())) { string? line; while ((line = reader.ReadLine()) != null) { yield return line; } } } }