[Fixes #] DeveloperExceptionPage throws when SourceFileContent is null in an ICompilationException

This commit is contained in:
Kiran Challa 2017-03-09 12:25:54 -08:00
parent 52a388e0ec
commit ee1cfdf41e
2 changed files with 133 additions and 18 deletions

View File

@ -126,20 +126,48 @@ namespace Microsoft.AspNetCore.Diagnostics
Options = _options, Options = _options,
}; };
var errorPage = new CompilationErrorPage
{
Model = model
};
if (compilationException.CompilationFailures == null)
{
return errorPage.ExecuteAsync(context);
}
foreach (var compilationFailure in compilationException.CompilationFailures) foreach (var compilationFailure in compilationException.CompilationFailures)
{ {
if (compilationFailure == null)
{
continue;
}
var stackFrames = new List<StackFrameSourceCodeInfo>(); var stackFrames = new List<StackFrameSourceCodeInfo>();
var exceptionDetails = new ExceptionDetails var exceptionDetails = new ExceptionDetails
{ {
StackFrames = stackFrames, StackFrames = stackFrames,
ErrorMessage = compilationFailure.FailureSummary, ErrorMessage = compilationFailure.FailureSummary,
}; };
var fileContent = compilationFailure model.ErrorDetails.Add(exceptionDetails);
.SourceFileContent model.CompiledContent.Add(compilationFailure.CompiledContent);
.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
if (compilationFailure.Messages == null)
{
continue;
}
var sourceLines = compilationFailure
.SourceFileContent?
.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
foreach (var item in compilationFailure.Messages) foreach (var item in compilationFailure.Messages)
{ {
if (item == null)
{
continue;
}
var frame = new StackFrameSourceCodeInfo var frame = new StackFrameSourceCodeInfo
{ {
File = compilationFailure.SourceFilePath, File = compilationFailure.SourceFilePath,
@ -147,21 +175,17 @@ namespace Microsoft.AspNetCore.Diagnostics
Function = string.Empty 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; frame.ErrorDetails = item.Message;
stackFrames.Add(frame); stackFrames.Add(frame);
} }
model.ErrorDetails.Add(exceptionDetails);
model.CompiledContent.Add(compilationFailure.CompiledContent);
} }
var errorPage = new CompilationErrorPage
{
Model = model
};
return errorPage.ExecuteAsync(context); return errorPage.ExecuteAsync(context);
} }

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -37,17 +39,106 @@ namespace Microsoft.AspNetCore.Diagnostics
// Act // Act
await server.CreateClient().GetAsync("/path"); await server.CreateClient().GetAsync("/path");
// This ensures that all diagnostics are completely written to the diagnostic listener
Thread.Sleep(1000);
// Assert // 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?.HttpContext);
Assert.NotNull(listener.DiagnosticUnhandledException?.Exception); Assert.NotNull(listener.DiagnosticUnhandledException?.Exception);
Assert.Null(listener.DiagnosticHandledException?.HttpContext); Assert.Null(listener.DiagnosticHandledException?.HttpContext);
Assert.Null(listener.DiagnosticHandledException?.Exception); Assert.Null(listener.DiagnosticHandledException?.Exception);
} }
public static TheoryData CompilationExceptionData
{
get
{
var variations = new TheoryData<List<CompilationFailure>>();
var failures = new List<CompilationFailure>();
var diagnosticMessages = new List<DiagnosticMessage>();
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages)
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(null, "source file content", "compiled content", diagnosticMessages)
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", null, "compiled content", diagnosticMessages)
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", null, diagnosticMessages)
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(null, null, null, diagnosticMessages)
});
variations.Add(new List<CompilationFailure>()
{
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<CompilationFailure>()
{
null
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages),
null
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", null)
});
variations.Add(new List<CompilationFailure>()
{
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", new List<DiagnosticMessage>(){ null })
});
return variations;
}
}
[Theory]
[MemberData(nameof(CompilationExceptionData))]
public async Task NullInfoInCompilationException_ShouldNotThrowExceptionGeneratingExceptionPage(
List<CompilationFailure> failures)
{
// Arrange
DiagnosticListener diagnosticListener = null;
var builder = new WebHostBuilder()
.Configure(app =>
{
diagnosticListener = app.ApplicationServices.GetRequiredService<DiagnosticListener>();
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<CompilationFailure> compilationFailures)
{
CompilationFailures = compilationFailures;
}
public IEnumerable<CompilationFailure> CompilationFailures { get; }
}
} }
} }