[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,
};
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<StackFrameSourceCodeInfo>();
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);
}

View File

@ -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<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; }
}
}
}