diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
index 8e2fcb3042..d11b9c58b2 100644
--- a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
+++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
@@ -27,8 +27,13 @@ namespace Microsoft.Blazor.Build.Core.RazorCompilation
/// If not null, additional information will be written to this .
/// A collection of instances representing any warnings or errors that were encountered.
public ICollection CompileFiles(IEnumerable inputPaths, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
- => inputPaths.SelectMany(
- path => CompileSingleFile(path, outputNamespace, resultOutput, verboseOutput)).ToList();
+ => inputPaths.SelectMany(path =>
+ {
+ using (var reader = File.OpenText(path))
+ {
+ return CompileSingleFile(path, reader, outputNamespace, resultOutput, verboseOutput);
+ }
+ }).ToList();
///
/// Writes C# source code representing a Blazor component defined by a Razor file.
@@ -38,7 +43,7 @@ namespace Microsoft.Blazor.Build.Core.RazorCompilation
/// A to which C# source code will be written.
/// If not null, additional information will be written to this .
/// An enumerable of instances representing any warnings or errors that were encountered.
- public IEnumerable CompileSingleFile(string inputFilePath, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
+ public IEnumerable CompileSingleFile(string inputFilePath, TextReader inputFileReader, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
{
if (resultOutput == null)
{
diff --git a/test/Microsoft.Blazor.Build.Test/Microsoft.Blazor.Build.Test.csproj b/test/Microsoft.Blazor.Build.Test/Microsoft.Blazor.Build.Test.csproj
index 35f4292050..6ca55b304f 100644
--- a/test/Microsoft.Blazor.Build.Test/Microsoft.Blazor.Build.Test.csproj
+++ b/test/Microsoft.Blazor.Build.Test/Microsoft.Blazor.Build.Test.csproj
@@ -8,6 +8,7 @@
+
diff --git a/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs b/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs
new file mode 100644
index 0000000000..f8985451b7
--- /dev/null
+++ b/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs
@@ -0,0 +1,134 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.Blazor.Build.Core.RazorCompilation;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Xunit;
+
+namespace Microsoft.Blazor.Build.Test
+{
+ public class RazorCompilerTest
+ {
+ [Fact]
+ public void RejectsInvalidClassName()
+ {
+ // Arrange/Act
+ var result = CompileToCSharp(
+ "x:\\dir\\subdir\\Filename with spaces.cshtml",
+ "ignored code",
+ "ignored namespace");
+
+ // Assert
+ Assert.Collection(result.Diagnostics,
+ item =>
+ {
+ Assert.Equal(RazorCompilerDiagnostic.DiagnosticType.Error, item.Type);
+ Assert.StartsWith($"Invalid name 'Filename with spaces'", item.Message);
+ });
+ }
+
+ [Fact]
+ public void CreatesClassWithCorrectNameAndNamespace()
+ {
+ // Arrange/Act
+ var result = CompileToAssembly(
+ "x:\\dir\\subdir\\Filename.cshtml",
+ "{* No code *}",
+ "MyCompany.MyNamespace");
+
+ // Assert
+ Assert.Empty(result.Diagnostics);
+ Assert.Collection(result.Assembly.GetTypes(),
+ type =>
+ {
+ Assert.Equal("Filename", type.Name);
+ Assert.Equal("MyCompany.MyNamespace", type.Namespace);
+ });
+ }
+
+ private static CompileToAssemblyResult CompileToAssembly(string cshtmlFilename, string cshtmlContent, string outputNamespace)
+ {
+ var csharpResult = CompileToCSharp(cshtmlFilename, cshtmlContent, outputNamespace);
+ if (csharpResult.Diagnostics.Any())
+ {
+ var diagnosticsLog = string.Join(Environment.NewLine,
+ csharpResult.Diagnostics.Select(d => d.FormatForConsole()).ToArray());
+ throw new InvalidOperationException($"Aborting compilation to assembly because RazorCompiler returned nonempty diagnostics: {diagnosticsLog}");
+ }
+
+ var syntaxTrees = new[]
+ {
+ CSharpSyntaxTree.ParseText(csharpResult.Code)
+ };
+ var references = new[]
+ {
+ MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)
+ };
+ var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
+ var assemblyName = "TestAssembly" + Guid.NewGuid().ToString("N");
+ var compilation = CSharpCompilation.Create(assemblyName,
+ syntaxTrees,
+ references,
+ options);
+
+ using (var peStream = new MemoryStream())
+ {
+ compilation.Emit(peStream);
+
+ return new CompileToAssemblyResult
+ {
+ Diagnostics = compilation.GetDiagnostics(),
+ VerboseLog = csharpResult.VerboseLog,
+ Assembly = Assembly.Load(peStream.ToArray())
+ };
+ }
+ }
+
+ private static CompileToCSharpResult CompileToCSharp(string cshtmlFilename, string cshtmlContent, string outputNamespace)
+ {
+ using (var resultStream = new MemoryStream())
+ using (var resultWriter = new StreamWriter(resultStream))
+ using (var verboseLogStream = new MemoryStream())
+ using (var verboseWriter = new StreamWriter(verboseLogStream))
+ using (var inputReader = new StringReader(cshtmlContent))
+ {
+ var diagnostics = new RazorCompiler().CompileSingleFile(
+ cshtmlFilename,
+ inputReader,
+ outputNamespace,
+ resultWriter,
+ verboseWriter);
+
+ resultWriter.Flush();
+ verboseWriter.Flush();
+ return new CompileToCSharpResult
+ {
+ Code = Encoding.UTF8.GetString(resultStream.ToArray()),
+ VerboseLog = Encoding.UTF8.GetString(verboseLogStream.ToArray()),
+ Diagnostics = diagnostics
+ };
+ }
+ }
+
+ private class CompileToCSharpResult
+ {
+ public string Code { get; set; }
+ public string VerboseLog { get; set; }
+ public IEnumerable Diagnostics { get; set; }
+ }
+
+ private class CompileToAssemblyResult
+ {
+ public Assembly Assembly { get; set; }
+ public string VerboseLog { get; set; }
+ public IEnumerable Diagnostics { get; set; }
+ }
+ }
+}