* Refactoring RazorFileInfoCollectionGenerator to not be instantiated.

* Adding CompilerGeneratedAttribute to generated code.
* Adding unit tests for RazorFileInfoCollectionGenerator.
This commit is contained in:
Pranav K 2015-08-06 07:36:53 -07:00
parent 1723ef0e97
commit c631d533c4
4 changed files with 211 additions and 135 deletions

View File

@ -0,0 +1,71 @@
// 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 System.Runtime.CompilerServices;
using System.Text;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor.Internal
{
/// <summary>
/// Utility type to code generate <see cref="RazorFileInfoCollection"/> types.
/// </summary>
public static class RazorFileInfoCollectionGenerator
{
/// <summary>
/// Generates CSharp code for the specified <paramref name="fileInfoCollection"/>.
/// </summary>
/// <param name="fileInfoCollection">The <see cref="RazorFileInfoCollection"/>.</param>
/// <returns></returns>
public static string GenerateCode([NotNull] RazorFileInfoCollection fileInfoCollection)
{
var builder = new StringBuilder();
builder.Append(
$@"namespace __ASP_ASSEMBLY
{{
[{typeof(CompilerGeneratedAttribute).FullName}]
public class __PreGeneratedViewCollection : {typeof(RazorFileInfoCollection).FullName}
{{
public __PreGeneratedViewCollection()
{{
{nameof(RazorFileInfoCollection.AssemblyResourceName)} = @""{fileInfoCollection.AssemblyResourceName}"";
{nameof(RazorFileInfoCollection.SymbolsResourceName)} = @""{fileInfoCollection.SymbolsResourceName}"";
FileInfos = new System.Collections.Generic.List<{typeof(RazorFileInfo).FullName}>
{{");
foreach (var fileInfo in fileInfoCollection.FileInfos)
{
builder.Append(
$@"
new {typeof(RazorFileInfo).FullName}
{{
{nameof(RazorFileInfo.FullTypeName)} = @""{fileInfo.FullTypeName}"",
{nameof(RazorFileInfo.RelativePath)} = @""{fileInfo.RelativePath}""
}},");
}
builder.Append(
$@"
}};
}}
private static {typeof(System.Reflection.Assembly).FullName} _loadedAssembly;
public override {typeof(System.Reflection.Assembly).FullName} LoadAssembly(
{typeof(IAssemblyLoadContext).FullName} loadContext)
{{
if (_loadedAssembly == null)
{{
_loadedAssembly = base.LoadAssembly(loadContext);
}}
return _loadedAssembly;
}}
}}
}}");
return builder.ToString();
}
}
}

View File

@ -1,129 +0,0 @@
// 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 System.Globalization;
using System.Text;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{
public class RazorFileInfoCollectionGenerator
{
private string _fileFormat;
public RazorFileInfoCollectionGenerator([NotNull] RazorFileInfoCollection fileInfoCollection,
[NotNull] CompilationSettings compilationSettings)
{
RazorFileInfoCollection = fileInfoCollection;
CompilationSettings = compilationSettings;
}
protected RazorFileInfoCollection RazorFileInfoCollection { get; }
protected CompilationSettings CompilationSettings { get; }
public virtual SyntaxTree GenerateCollection()
{
var builder = new StringBuilder();
builder.AppendFormat(CultureInfo.InvariantCulture,
TopFormat,
RazorFileInfoCollection.AssemblyResourceName,
RazorFileInfoCollection.SymbolsResourceName);
foreach (var fileInfo in RazorFileInfoCollection.FileInfos)
{
var perFileEntry = GenerateFile(fileInfo);
builder.Append(perFileEntry);
}
builder.Append(Bottom);
var sourceCode = builder.ToString();
var syntaxTree = SyntaxTreeGenerator.Generate(sourceCode,
"__AUTO__GeneratedViewsCollection.cs",
CompilationSettings);
return syntaxTree;
}
protected virtual string GenerateFile([NotNull] RazorFileInfo fileInfo)
{
return string.Format(FileFormat,
fileInfo.RelativePath,
fileInfo.FullTypeName);
}
protected virtual string TopFormat
{
get
{
return
$@"using System;
using System.Collections.Generic;
using System.Reflection;
using {typeof(RazorFileInfoCollection).Namespace};
namespace __ASP_ASSEMBLY
{{{{
public class __PreGeneratedViewCollection : {nameof(RazorFileInfoCollection)}
{{{{
public __PreGeneratedViewCollection()
{{{{
{nameof(RazorFileInfoCollection.AssemblyResourceName)} = ""{{0}}"";
{nameof(RazorFileInfoCollection.SymbolsResourceName)} = ""{{1}}"";
var fileInfos = new List<{nameof(RazorFileInfo)}>();
{nameof(RazorFileInfoCollection.FileInfos)} = fileInfos;
{nameof(RazorFileInfo)} info;
";
}
}
protected virtual string Bottom
{
get
{
return
$@"
}}
private static Assembly _loadedAssembly;
public override Assembly LoadAssembly({typeof(IAssemblyLoadContext).FullName} loadContext)
{{
if (_loadedAssembly == null)
{{
_loadedAssembly = base.LoadAssembly(loadContext);
}}
return _loadedAssembly;
}}
}}
}}
";
}
}
protected virtual string FileFormat
{
get
{
if (_fileFormat == null)
{
_fileFormat =
$@"
info = new {nameof(RazorFileInfo)}
{{{{
{nameof(RazorFileInfo.RelativePath)} = @""{{0}}"",
{nameof(RazorFileInfo.FullTypeName)} = @""{{1}}""
}}}};
fileInfos.Add(info);
";
}
return _fileFormat;
}
}
}
}

View File

@ -64,12 +64,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
var result = CreateFileInfoCollection();
if (result != null)
{
var collectionGenerator = new RazorFileInfoCollectionGenerator(
result,
CompilationSettings);
var tree = collectionGenerator.GenerateCollection();
CompileContext.Compilation = CompileContext.Compilation.AddSyntaxTrees(tree);
var generatedCode = RazorFileInfoCollectionGenerator.GenerateCode(result);
var syntaxTree = CSharpSyntaxTree.ParseText(
generatedCode,
SyntaxTreeGenerator.GetParseOptions(CompilationSettings));
CompileContext.Compilation = CompileContext.Compilation.AddSyntaxTrees(syntaxTree);
}
}

View File

@ -0,0 +1,135 @@
// 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 System.Collections.Generic;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor.Internal
{
public class RazorFileInfoCollectionGeneratorTest
{
public static TheoryData GenerateCollection_ProducesExpectedCodeData
{
get
{
var expected1 =
@"namespace __ASP_ASSEMBLY
{
[System.Runtime.CompilerServices.CompilerGeneratedAttribute]
public class __PreGeneratedViewCollection : Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfoCollection
{
public __PreGeneratedViewCollection()
{
AssemblyResourceName = @""EmptyAssembly"";
SymbolsResourceName = @"""";
FileInfos = new System.Collections.Generic.List<Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo>
{
};
}
private static System.Reflection.Assembly _loadedAssembly;
public override System.Reflection.Assembly LoadAssembly(
Microsoft.Dnx.Runtime.IAssemblyLoadContext loadContext)
{
if (_loadedAssembly == null)
{
_loadedAssembly = base.LoadAssembly(loadContext);
}
return _loadedAssembly;
}
}
}";
var expected2 =
@"namespace __ASP_ASSEMBLY
{
[System.Runtime.CompilerServices.CompilerGeneratedAttribute]
public class __PreGeneratedViewCollection : Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfoCollection
{
public __PreGeneratedViewCollection()
{
AssemblyResourceName = @""TestAssembly"";
SymbolsResourceName = @""SymbolsResource"";
FileInfos = new System.Collections.Generic.List<Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo>
{
new Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo
{
FullTypeName = @""SomeType.Name"",
RelativePath = @""Views/Home/Index.cshtml""
},
new Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo
{
FullTypeName = @""Different.Name"",
RelativePath = @""Views/Home/Different.cshtml""
},
};
}
private static System.Reflection.Assembly _loadedAssembly;
public override System.Reflection.Assembly LoadAssembly(
Microsoft.Dnx.Runtime.IAssemblyLoadContext loadContext)
{
if (_loadedAssembly == null)
{
_loadedAssembly = base.LoadAssembly(loadContext);
}
return _loadedAssembly;
}
}
}";
return new TheoryData<RazorFileInfoCollection, string>
{
{ new EmptyCollection(), expected1 },
{ new TestCollection(), expected2 },
};
}
}
[Theory]
[MemberData(nameof(GenerateCollection_ProducesExpectedCodeData))]
public void GenerateCollection_ProducesExpectedCode(RazorFileInfoCollection collection, string expected)
{
// Act
var actual = RazorFileInfoCollectionGenerator.GenerateCode(collection);
// Assert
Assert.Equal(expected, actual);
}
private class EmptyCollection : RazorFileInfoCollection
{
public EmptyCollection()
{
AssemblyResourceName = "EmptyAssembly";
FileInfos = new List<RazorFileInfo>();
}
}
private class TestCollection : RazorFileInfoCollection
{
public TestCollection()
{
AssemblyResourceName = "TestAssembly";
SymbolsResourceName = "SymbolsResource";
FileInfos = new List<RazorFileInfo>
{
new RazorFileInfo
{
FullTypeName = "SomeType.Name",
RelativePath = @"Views/Home/Index.cshtml"
},
new RazorFileInfo
{
FullTypeName = "Different.Name",
RelativePath = @"Views/Home/Different.cshtml"
},
};
}
}
}
}