From ee1cfdf41e2f9d5cf56bffb4e90a8fc59938e4ba Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Thu, 9 Mar 2017 12:25:54 -0800 Subject: [PATCH] [Fixes #] DeveloperExceptionPage throws when SourceFileContent is null in an ICompilationException --- .../DeveloperExceptionPageMiddleware.cs | 48 ++++++-- .../DeveloperExceptionPageMiddlewareTest.cs | 103 +++++++++++++++++- 2 files changed, 133 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs b/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs index d05f0cc182..adaa9bd443 100644 --- a/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs +++ b/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs @@ -126,20 +126,48 @@ namespace Microsoft.AspNetCore.Diagnostics Options = _options, }; + var errorPage = new CompilationErrorPage + { + Model = model + }; + + if (compilationException.CompilationFailures == null) + { + return errorPage.ExecuteAsync(context); + } + foreach (var compilationFailure in compilationException.CompilationFailures) { + if (compilationFailure == null) + { + continue; + } + var stackFrames = new List(); var exceptionDetails = new ExceptionDetails { StackFrames = stackFrames, ErrorMessage = compilationFailure.FailureSummary, }; - var fileContent = compilationFailure - .SourceFileContent - .Split(new[] { Environment.NewLine }, StringSplitOptions.None); + model.ErrorDetails.Add(exceptionDetails); + model.CompiledContent.Add(compilationFailure.CompiledContent); + + if (compilationFailure.Messages == null) + { + continue; + } + + var sourceLines = compilationFailure + .SourceFileContent? + .Split(new[] { Environment.NewLine }, StringSplitOptions.None); foreach (var item in compilationFailure.Messages) { + if (item == null) + { + continue; + } + var frame = new StackFrameSourceCodeInfo { File = compilationFailure.SourceFilePath, @@ -147,21 +175,17 @@ namespace Microsoft.AspNetCore.Diagnostics Function = string.Empty }; - _exceptionDetailsProvider.ReadFrameContent(frame, fileContent, item.StartLine, item.EndLine); + if (sourceLines != null) + { + _exceptionDetailsProvider.ReadFrameContent(frame, sourceLines, item.StartLine, item.EndLine); + } + frame.ErrorDetails = item.Message; stackFrames.Add(frame); } - - model.ErrorDetails.Add(exceptionDetails); - model.CompiledContent.Add(compilationFailure.CompiledContent); } - var errorPage = new CompilationErrorPage - { - Model = model - }; - return errorPage.ExecuteAsync(context); } diff --git a/test/Microsoft.AspNetCore.Diagnostics.Tests/DeveloperExceptionPageMiddlewareTest.cs b/test/Microsoft.AspNetCore.Diagnostics.Tests/DeveloperExceptionPageMiddlewareTest.cs index ef903e3e7f..2d0f6b42db 100644 --- a/test/Microsoft.AspNetCore.Diagnostics.Tests/DeveloperExceptionPageMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Diagnostics.Tests/DeveloperExceptionPageMiddlewareTest.cs @@ -2,6 +2,8 @@ // 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 System.Linq; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -37,17 +39,106 @@ namespace Microsoft.AspNetCore.Diagnostics // Act await server.CreateClient().GetAsync("/path"); - // This ensures that all diagnostics are completely written to the diagnostic listener - Thread.Sleep(1000); - // Assert - Assert.NotNull(listener.EndRequest?.HttpContext); - Assert.Null(listener.HostingUnhandledException?.HttpContext); - Assert.Null(listener.HostingUnhandledException?.Exception); Assert.NotNull(listener.DiagnosticUnhandledException?.HttpContext); Assert.NotNull(listener.DiagnosticUnhandledException?.Exception); Assert.Null(listener.DiagnosticHandledException?.HttpContext); Assert.Null(listener.DiagnosticHandledException?.Exception); } + + public static TheoryData CompilationExceptionData + { + get + { + var variations = new TheoryData>(); + var failures = new List(); + var diagnosticMessages = new List(); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages) + }); + variations.Add(new List() + { + new CompilationFailure(null, "source file content", "compiled content", diagnosticMessages) + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", null, "compiled content", diagnosticMessages) + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", null, diagnosticMessages) + }); + variations.Add(new List() + { + new CompilationFailure(null, null, null, diagnosticMessages) + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages), + new CompilationFailure(@"c:\sourcefilepath.cs", null, "compiled content", diagnosticMessages) + }); + variations.Add(null); + variations.Add(new List() + { + null + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages), + null + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", null) + }); + variations.Add(new List() + { + new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", new List(){ null }) + }); + return variations; + } + } + + [Theory] + [MemberData(nameof(CompilationExceptionData))] + public async Task NullInfoInCompilationException_ShouldNotThrowExceptionGeneratingExceptionPage( + List failures) + { + // Arrange + DiagnosticListener diagnosticListener = null; + var builder = new WebHostBuilder() + .Configure(app => + { + diagnosticListener = app.ApplicationServices.GetRequiredService(); + app.UseDeveloperExceptionPage(); + app.Run(context => + { + throw new CustomCompilationException(failures); + }); + }); + var server = new TestServer(builder); + var listener = new TestDiagnosticListener(); + diagnosticListener.SubscribeWithAdapter(listener); + + // Act + await server.CreateClient().GetAsync("/path"); + + // Assert + Assert.NotNull(listener.DiagnosticUnhandledException?.HttpContext); + Assert.NotNull(listener.DiagnosticUnhandledException?.Exception); + Assert.Null(listener.DiagnosticHandledException?.HttpContext); + Assert.Null(listener.DiagnosticHandledException?.Exception); + } + + public class CustomCompilationException : Exception, ICompilationException + { + public CustomCompilationException(IEnumerable compilationFailures) + { + CompilationFailures = compilationFailures; + } + + public IEnumerable CompilationFailures { get; } + } } }