[Fixes #] DeveloperExceptionPage throws when SourceFileContent is null in an ICompilationException
This commit is contained in:
parent
52a388e0ec
commit
ee1cfdf41e
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue