[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,
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue