Skip to content

Commit ee1cfdf

Browse files
committed
[Fixes #] DeveloperExceptionPage throws when SourceFileContent is null in an ICompilationException
1 parent 52a388e commit ee1cfdf

2 files changed

Lines changed: 132 additions & 17 deletions

File tree

src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,42 +126,66 @@ private Task DisplayCompilationException(
126126
Options = _options,
127127
};
128128

129+
var errorPage = new CompilationErrorPage
130+
{
131+
Model = model
132+
};
133+
134+
if (compilationException.CompilationFailures == null)
135+
{
136+
return errorPage.ExecuteAsync(context);
137+
}
138+
129139
foreach (var compilationFailure in compilationException.CompilationFailures)
130140
{
141+
if (compilationFailure == null)
142+
{
143+
continue;
144+
}
145+
131146
var stackFrames = new List<StackFrameSourceCodeInfo>();
132147
var exceptionDetails = new ExceptionDetails
133148
{
134149
StackFrames = stackFrames,
135150
ErrorMessage = compilationFailure.FailureSummary,
136151
};
137-
var fileContent = compilationFailure
138-
.SourceFileContent
139-
.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
152+
model.ErrorDetails.Add(exceptionDetails);
153+
model.CompiledContent.Add(compilationFailure.CompiledContent);
154+
155+
if (compilationFailure.Messages == null)
156+
{
157+
continue;
158+
}
159+
160+
var sourceLines = compilationFailure
161+
.SourceFileContent?
162+
.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
140163

141164
foreach (var item in compilationFailure.Messages)
142165
{
166+
if (item == null)
167+
{
168+
continue;
169+
}
170+
143171
var frame = new StackFrameSourceCodeInfo
144172
{
145173
File = compilationFailure.SourceFilePath,
146174
Line = item.StartLine,
147175
Function = string.Empty
148176
};
149177

150-
_exceptionDetailsProvider.ReadFrameContent(frame, fileContent, item.StartLine, item.EndLine);
178+
if (sourceLines != null)
179+
{
180+
_exceptionDetailsProvider.ReadFrameContent(frame, sourceLines, item.StartLine, item.EndLine);
181+
}
182+
151183
frame.ErrorDetails = item.Message;
152184

153185
stackFrames.Add(frame);
154186
}
155-
156-
model.ErrorDetails.Add(exceptionDetails);
157-
model.CompiledContent.Add(compilationFailure.CompiledContent);
158187
}
159188

160-
var errorPage = new CompilationErrorPage
161-
{
162-
Model = model
163-
};
164-
165189
return errorPage.ExecuteAsync(context);
166190
}
167191

test/Microsoft.AspNetCore.Diagnostics.Tests/DeveloperExceptionPageMiddlewareTest.cs

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
57
using System.Diagnostics;
68
using System.Threading;
79
using System.Threading.Tasks;
@@ -37,17 +39,106 @@ public async Task UnhandledErrorsWriteToDiagnosticWhenUsingExceptionPage()
3739
// Act
3840
await server.CreateClient().GetAsync("/path");
3941

40-
// This ensures that all diagnostics are completely written to the diagnostic listener
41-
Thread.Sleep(1000);
42+
// Assert
43+
Assert.NotNull(listener.DiagnosticUnhandledException?.HttpContext);
44+
Assert.NotNull(listener.DiagnosticUnhandledException?.Exception);
45+
Assert.Null(listener.DiagnosticHandledException?.HttpContext);
46+
Assert.Null(listener.DiagnosticHandledException?.Exception);
47+
}
48+
49+
public static TheoryData CompilationExceptionData
50+
{
51+
get
52+
{
53+
var variations = new TheoryData<List<CompilationFailure>>();
54+
var failures = new List<CompilationFailure>();
55+
var diagnosticMessages = new List<DiagnosticMessage>();
56+
variations.Add(new List<CompilationFailure>()
57+
{
58+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages)
59+
});
60+
variations.Add(new List<CompilationFailure>()
61+
{
62+
new CompilationFailure(null, "source file content", "compiled content", diagnosticMessages)
63+
});
64+
variations.Add(new List<CompilationFailure>()
65+
{
66+
new CompilationFailure(@"c:\sourcefilepath.cs", null, "compiled content", diagnosticMessages)
67+
});
68+
variations.Add(new List<CompilationFailure>()
69+
{
70+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", null, diagnosticMessages)
71+
});
72+
variations.Add(new List<CompilationFailure>()
73+
{
74+
new CompilationFailure(null, null, null, diagnosticMessages)
75+
});
76+
variations.Add(new List<CompilationFailure>()
77+
{
78+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages),
79+
new CompilationFailure(@"c:\sourcefilepath.cs", null, "compiled content", diagnosticMessages)
80+
});
81+
variations.Add(null);
82+
variations.Add(new List<CompilationFailure>()
83+
{
84+
null
85+
});
86+
variations.Add(new List<CompilationFailure>()
87+
{
88+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", diagnosticMessages),
89+
null
90+
});
91+
variations.Add(new List<CompilationFailure>()
92+
{
93+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", null)
94+
});
95+
variations.Add(new List<CompilationFailure>()
96+
{
97+
new CompilationFailure(@"c:\sourcefilepath.cs", "source file content", "compiled content", new List<DiagnosticMessage>(){ null })
98+
});
99+
return variations;
100+
}
101+
}
102+
103+
[Theory]
104+
[MemberData(nameof(CompilationExceptionData))]
105+
public async Task NullInfoInCompilationException_ShouldNotThrowExceptionGeneratingExceptionPage(
106+
List<CompilationFailure> failures)
107+
{
108+
// Arrange
109+
DiagnosticListener diagnosticListener = null;
110+
var builder = new WebHostBuilder()
111+
.Configure(app =>
112+
{
113+
diagnosticListener = app.ApplicationServices.GetRequiredService<DiagnosticListener>();
114+
app.UseDeveloperExceptionPage();
115+
app.Run(context =>
116+
{
117+
throw new CustomCompilationException(failures);
118+
});
119+
});
120+
var server = new TestServer(builder);
121+
var listener = new TestDiagnosticListener();
122+
diagnosticListener.SubscribeWithAdapter(listener);
123+
124+
// Act
125+
await server.CreateClient().GetAsync("/path");
42126

43127
// Assert
44-
Assert.NotNull(listener.EndRequest?.HttpContext);
45-
Assert.Null(listener.HostingUnhandledException?.HttpContext);
46-
Assert.Null(listener.HostingUnhandledException?.Exception);
47128
Assert.NotNull(listener.DiagnosticUnhandledException?.HttpContext);
48129
Assert.NotNull(listener.DiagnosticUnhandledException?.Exception);
49130
Assert.Null(listener.DiagnosticHandledException?.HttpContext);
50131
Assert.Null(listener.DiagnosticHandledException?.Exception);
51132
}
133+
134+
public class CustomCompilationException : Exception, ICompilationException
135+
{
136+
public CustomCompilationException(IEnumerable<CompilationFailure> compilationFailures)
137+
{
138+
CompilationFailures = compilationFailures;
139+
}
140+
141+
public IEnumerable<CompilationFailure> CompilationFailures { get; }
142+
}
52143
}
53144
}

0 commit comments

Comments
 (0)