Add Visual Studio specific RC1 binaries.

- This is needed for Visual Studio RC1 backwards compatibility.
This commit is contained in:
N. Taylor Mullen 2016-04-01 17:08:57 -07:00
Родитель 701869fd53
Коммит 687fd72efd
35 изменённых файлов: 3091 добавлений и 1 удалений

Просмотреть файл

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@ -103,6 +103,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "sam
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Mvc.Dnx", "src\Microsoft.AspNetCore.Mvc.Dnx\Microsoft.AspNetCore.Mvc.Dnx.xproj", "{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor.Host.VSRC1", "src\Microsoft.AspNet.Mvc.Razor.Host.VSRC1\Microsoft.AspNet.Mvc.Razor.Host.VSRC1.xproj", "{85C54A84-3E60-40E1-BE39-C2F514DD922E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -619,6 +621,18 @@ Global
{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.ActiveCfg = Release|Any CPU
{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.Build.0 = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|x86.ActiveCfg = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Debug|x86.Build.0 = Debug|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|Any CPU.Build.0 = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|x86.ActiveCfg = Release|Any CPU
{85C54A84-3E60-40E1-BE39-C2F514DD922E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -668,5 +682,6 @@ Global
{EE0BD773-4D47-4AA8-8472-5A938A3953BA} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{45F6B3B6-D114-4D77-84D6-561B3957F341} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{8FB691C2-DFD8-4FEE-9628-2BB8466A691C} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{85C54A84-3E60-40E1-BE39-C2F514DD922E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -16,6 +16,7 @@
"Microsoft.AspNetCore.Mvc.Localization": { },
"Microsoft.AspNetCore.Mvc.Razor": { },
"Microsoft.AspNetCore.Mvc.Razor.Host": { },
"Microsoft.AspNet.Mvc.Razor.Host.VSRC1": { },
"Microsoft.AspNetCore.Mvc.TagHelpers": { },
"Microsoft.AspNetCore.Mvc.ViewFeatures": { },
"Microsoft.AspNetCore.Mvc.WebApiCompatShim": { }

Просмотреть файл

@ -0,0 +1,93 @@
// 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;
using System.Linq;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// Contains helper methods for dealing with Chunks
/// </summary>
public static class ChunkHelper
{
/// <summary>
/// Token that is replaced by the model name in <c>@inherits</c> and <c>@inject</c>
/// chunks as part of <see cref="ChunkInheritanceUtility"/>.
/// </summary>
public static readonly string TModelToken = "TModel";
private static readonly string TModelReplaceToken = $"<{TModelToken}>";
/// <summary>
/// Returns the <see cref="ModelChunk"/> used to determine the model name for the page generated
/// using the specified <paramref name="chunkTree"/>
/// </summary>
/// <param name="chunkTree">The <see cref="ChunkTree"/> to scan for <see cref="ModelChunk"/>s in.</param>
/// <returns>The last <see cref="ModelChunk"/> in the <see cref="ChunkTree"/> if found, <c>null</c> otherwise.
/// </returns>
public static ModelChunk GetModelChunk(ChunkTree chunkTree)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
// If there's more than 1 model chunk there will be a Razor error BUT we want intellisense to show up on
// the current model chunk that the user is typing.
return chunkTree
.Chunks
.OfType<ModelChunk>()
.LastOrDefault();
}
/// <summary>
/// Returns the type name of the Model specified via a <see cref="ModelChunk"/> in the
/// <paramref name="chunkTree"/> if specified or the default model type.
/// </summary>
/// <param name="chunkTree">The <see cref="ChunkTree"/> to scan for <see cref="ModelChunk"/>s in.</param>
/// <param name="defaultModelName">The <see cref="Type"/> name of the default model.</param>
/// <returns>The model type name for the generated page.</returns>
public static string GetModelTypeName(
ChunkTree chunkTree,
string defaultModelName)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (defaultModelName == null)
{
throw new ArgumentNullException(nameof(defaultModelName));
}
var modelChunk = GetModelChunk(chunkTree);
return modelChunk != null ? modelChunk.ModelType : defaultModelName;
}
/// <summary>
/// Returns a string with the &lt;TModel&gt; token replaced with the value specified in
/// <paramref name="modelName"/>.
/// </summary>
/// <param name="value">The string to replace the token in.</param>
/// <param name="modelName">The model name to replace with.</param>
/// <returns>A string with the token replaced.</returns>
public static string ReplaceTModel(
string value,
string modelName)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (modelName == null)
{
throw new ArgumentNullException(nameof(modelName));
}
return value.Replace(TModelReplaceToken, modelName);
}
}
}

Просмотреть файл

@ -0,0 +1,193 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNet.FileProviders.VSRC1;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// A utility type for supporting inheritance of directives into a page from applicable <c>_ViewImports</c> pages.
/// </summary>
public class ChunkInheritanceUtility
{
private readonly MvcRazorHost _razorHost;
private readonly IReadOnlyList<Chunk> _defaultInheritedChunks;
private readonly IChunkTreeCache _chunkTreeCache;
/// <summary>
/// Initializes a new instance of <see cref="ChunkInheritanceUtility"/>.
/// </summary>
/// <param name="razorHost">The <see cref="MvcRazorHost"/> used to parse <c>_ViewImports</c> pages.</param>
/// <param name="chunkTreeCache"><see cref="IChunkTreeCache"/> that caches <see cref="ChunkTree"/> instances.
/// </param>
/// <param name="defaultInheritedChunks">Sequence of <see cref="Chunk"/>s inherited by default.</param>
public ChunkInheritanceUtility(
MvcRazorHost razorHost,
IChunkTreeCache chunkTreeCache,
IReadOnlyList<Chunk> defaultInheritedChunks)
{
if (razorHost == null)
{
throw new ArgumentNullException(nameof(razorHost));
}
if (chunkTreeCache == null)
{
throw new ArgumentNullException(nameof(chunkTreeCache));
}
if (defaultInheritedChunks == null)
{
throw new ArgumentNullException(nameof(defaultInheritedChunks));
}
_razorHost = razorHost;
_defaultInheritedChunks = defaultInheritedChunks;
_chunkTreeCache = chunkTreeCache;
}
/// <summary>
/// Gets an ordered <see cref="IReadOnlyList{ChunkTreeResult}"/> of parsed <see cref="ChunkTree"/>s and
/// file paths for each <c>_ViewImports</c> that is applicable to the page located at
/// <paramref name="pagePath"/>. The list is ordered so that the <see cref="ChunkTreeResult"/>'s
/// <see cref="ChunkTreeResult.ChunkTree"/> for the <c>_ViewImports</c> closest to the
/// <paramref name="pagePath"/> in the file system appears first.
/// </summary>
/// <param name="pagePath">The path of the page to locate inherited chunks for.</param>
/// <returns>A <see cref="IReadOnlyList{ChunkTreeResult}"/> of parsed <c>_ViewImports</c>
/// <see cref="ChunkTree"/>s and their file paths.</returns>
/// <remarks>
/// The resulting <see cref="IReadOnlyList{ChunkTreeResult}"/> is ordered so that the result
/// for a _ViewImport closest to the application root appears first and the _ViewImport
/// closest to the page appears last i.e.
/// [ /_ViewImport, /Views/_ViewImport, /Views/Home/_ViewImport ]
/// </remarks>
public virtual IReadOnlyList<ChunkTreeResult> GetInheritedChunkTreeResults(string pagePath)
{
if (pagePath == null)
{
throw new ArgumentNullException(nameof(pagePath));
}
var inheritedChunkTreeResults = new List<ChunkTreeResult>();
var templateEngine = new RazorTemplateEngine(_razorHost);
foreach (var viewImportsPath in ViewHierarchyUtility.GetViewImportsLocations(pagePath))
{
// viewImportsPath contains the app-relative path of the _ViewImports.
// Since the parsing of a _ViewImports would cause parent _ViewImports to be parsed
// we need to ensure the paths are app-relative to allow the GetGlobalFileLocations
// for the current _ViewImports to succeed.
var chunkTree = _chunkTreeCache.GetOrAdd(
viewImportsPath,
fileInfo => ParseViewFile(
templateEngine,
fileInfo,
viewImportsPath));
if (chunkTree != null)
{
var result = new ChunkTreeResult(chunkTree, viewImportsPath);
inheritedChunkTreeResults.Insert(0, result);
}
}
return inheritedChunkTreeResults;
}
/// <summary>
/// Merges <see cref="Chunk"/> inherited by default and <see cref="ChunkTree"/> instances produced by parsing
/// <c>_ViewImports</c> files into the specified <paramref name="chunkTree"/>.
/// </summary>
/// <param name="chunkTree">The <see cref="ChunkTree"/> to merge in to.</param>
/// <param name="inheritedChunkTrees"><see cref="IReadOnlyList{ChunkTree}"/> inherited from <c>_ViewImports</c>
/// files.</param>
/// <param name="defaultModel">The default model <see cref="Type"/> name.</param>
public void MergeInheritedChunkTrees(
ChunkTree chunkTree,
IReadOnlyList<ChunkTree> inheritedChunkTrees,
string defaultModel)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (inheritedChunkTrees == null)
{
throw new ArgumentNullException(nameof(inheritedChunkTrees));
}
var chunkMergers = GetChunkMergers(chunkTree, defaultModel);
// We merge chunks into the ChunkTree in two passes. In the first pass, we traverse the ChunkTree visiting
// a mapped IChunkMerger for types that are registered.
foreach (var chunk in chunkTree.Chunks)
{
foreach (var merger in chunkMergers)
{
merger.VisitChunk(chunk);
}
}
var inheritedChunks = _defaultInheritedChunks.Concat(
inheritedChunkTrees.SelectMany(tree => tree.Chunks)).ToArray();
foreach (var merger in chunkMergers)
{
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
}
}
private static IChunkMerger[] GetChunkMergers(ChunkTree chunkTree, string defaultModel)
{
var modelType = ChunkHelper.GetModelTypeName(chunkTree, defaultModel);
return new IChunkMerger[]
{
new UsingChunkMerger(),
new InjectChunkMerger(modelType),
new SetBaseTypeChunkMerger(modelType)
};
}
private static ChunkTree ParseViewFile(
RazorTemplateEngine engine,
IFileInfo fileInfo,
string viewImportsPath)
{
using (var stream = fileInfo.CreateReadStream())
{
using (var streamReader = new StreamReader(stream))
{
var parseResults = engine.ParseTemplate(streamReader, viewImportsPath);
var className = ParserHelpers.SanitizeClassName(fileInfo.Name);
var language = engine.Host.CodeLanguage;
var chunkGenerator = language.CreateChunkGenerator(
className,
engine.Host.DefaultNamespace,
viewImportsPath,
engine.Host);
chunkGenerator.Visit(parseResults);
// Rewrite the location of inherited chunks so they point to the global import file.
var chunkTree = chunkGenerator.Context.ChunkTreeBuilder.ChunkTree;
foreach (var chunk in chunkTree.Chunks)
{
chunk.Start = new SourceLocation(
viewImportsPath,
chunk.Start.AbsoluteIndex,
chunk.Start.LineIndex,
chunk.Start.CharacterIndex);
}
return chunkTree;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
// 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;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// Contains <see cref="AspNet.Razor.Chunks.ChunkTree"/> information.
/// </summary>
public class ChunkTreeResult
{
/// <summary>
/// Initializes a new instance of <see cref="ChunkTreeResult"/>.
/// </summary>
/// <param name="chunkTree">The <see cref="AspNet.Razor.Chunks.ChunkTree"/> generated from the file at the
/// given <paramref name="filePath"/>.</param>
/// <param name="filePath">The path to the file that generated the given <paramref name="chunkTree"/>.</param>
public ChunkTreeResult(ChunkTree chunkTree, string filePath)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
ChunkTree = chunkTree;
FilePath = filePath;
}
/// <summary>
/// The <see cref="AspNet.Razor.Chunks.ChunkTree"/> generated from the file at <see cref="FilePath"/>.
/// </summary>
public ChunkTree ChunkTree { get; }
/// <summary>
/// The path to the file that generated the <see cref="ChunkTree"/>.
/// </summary>
public string FilePath { get; }
}
}

Просмотреть файл

@ -0,0 +1,77 @@
// 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;
using Microsoft.AspNet.FileProviders.VSRC1;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.Extensions.Caching.Memory.VSRC1;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// Default implementation of <see cref="IChunkTreeCache"/>.
/// </summary>
public class DefaultChunkTreeCache : IChunkTreeCache
{
private static readonly MemoryCacheOptions MemoryCacheOptions = new MemoryCacheOptions
{
CompactOnMemoryPressure = false
};
private static readonly TimeSpan SlidingExpirationDuration = TimeSpan.FromMinutes(1);
private readonly IFileProvider _fileProvider;
private readonly IMemoryCache _chunkTreeCache;
/// <summary>
/// Initializes a new instance of <see cref="DefaultChunkTreeCache"/>.
/// </summary>
/// <param name="fileProvider">The application's <see cref="IFileProvider"/>.</param>
public DefaultChunkTreeCache(IFileProvider fileProvider)
: this(fileProvider, MemoryCacheOptions)
{
}
// Internal for unit testing
internal DefaultChunkTreeCache(
IFileProvider fileProvider,
MemoryCacheOptions options)
{
_fileProvider = fileProvider;
_chunkTreeCache = new MemoryCache(options);
}
/// <inheritdoc />
public ChunkTree GetOrAdd(
string pagePath,
Func<IFileInfo, ChunkTree> getChunkTree)
{
if (pagePath == null)
{
throw new ArgumentNullException(nameof(pagePath));
}
if (getChunkTree == null)
{
throw new ArgumentNullException(nameof(getChunkTree));
}
ChunkTree chunkTree;
if (!_chunkTreeCache.TryGetValue(pagePath, out chunkTree))
{
// GetOrAdd is invoked for each _ViewImport that might potentially exist in the path.
// We can avoid performing file system lookups for files that do not exist by caching
// negative results and adding a Watch for that file.
var options = new MemoryCacheEntryOptions()
.AddExpirationToken(_fileProvider.Watch(pagePath))
.SetSlidingExpiration(SlidingExpirationDuration);
var file = _fileProvider.GetFileInfo(pagePath);
chunkTree = file.Exists ? getChunkTree(file) : null;
_chunkTreeCache.Set(pagePath, chunkTree, options);
}
return chunkTree;
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// 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.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// Defines the contract for merging <see cref="Chunk"/> instances from _ViewStart files.
/// </summary>
public interface IChunkMerger
{
/// <summary>
/// Visits a <see cref="Chunk"/> from the <see cref="ChunkTree"/> to merge into.
/// </summary>
/// <param name="chunk">A <see cref="Chunk"/> from the tree.</param>
void VisitChunk(Chunk chunk);
/// <summary>
/// Merges an inherited <see cref="Chunk"/> into the <see cref="ChunkTree"/>.
/// </summary>
/// <param name="ChunkTree">The <see cref="ChunkTree"/> to merge into.</param>
/// <param name="inheritedChunks">The <see cref="IReadOnlyList{Chunk}"/>s to merge.</param>
void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList<Chunk> inheritedChunks);
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// 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;
using Microsoft.AspNet.FileProviders.VSRC1;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// A cache for parsed <see cref="ChunkTree"/>s.
/// </summary>
public interface IChunkTreeCache
{
/// <summary>
/// Get an existing <see cref="ChunkTree"/>, or create and add a new one if it is
/// not available in the cache or is expired.
/// </summary>
/// <param name="pagePath">The application relative path of the Razor page.</param>
/// <param name="getChunkTree">A delegate that creates a new <see cref="ChunkTree"/>.</param>
/// <returns>The <see cref="ChunkTree"/> if a file exists at <paramref name="pagePath"/>,
/// <c>null</c> otherwise.</returns>
/// <remarks>The resulting <see cref="ChunkTree"/> does not contain inherited chunks from _ViewStart or
/// default inherited chunks.</remarks>
ChunkTree GetOrAdd(string pagePath, Func<IFileInfo, ChunkTree> getChunkTree);
}
}

Просмотреть файл

@ -0,0 +1,87 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// A <see cref="IChunkMerger"/> that merges <see cref="InjectChunk"/> instances.
/// </summary>
public class InjectChunkMerger : IChunkMerger
{
private readonly HashSet<string> _addedMemberNames = new HashSet<string>(StringComparer.Ordinal);
private string _modelType;
/// <summary>
/// Initializes a new instance of <see cref="InjectChunkMerger"/>.
/// </summary>
/// <param name="modelType">The model type to be used to replace &lt;TModel&gt; tokens.</param>
public InjectChunkMerger(string modelType)
{
if (modelType == null)
{
throw new ArgumentNullException(nameof(modelType));
}
_modelType = "<" + modelType + ">";
}
/// <inheritdoc />
public void VisitChunk(Chunk chunk)
{
if (chunk == null)
{
throw new ArgumentNullException(nameof(chunk));
}
var injectChunk = chunk as InjectChunk;
if (injectChunk != null)
{
injectChunk.TypeName = ChunkHelper.ReplaceTModel(injectChunk.TypeName, _modelType);
_addedMemberNames.Add(injectChunk.MemberName);
}
}
/// <inheritdoc />
public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList<Chunk> inheritedChunks)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (inheritedChunks == null)
{
throw new ArgumentNullException(nameof(inheritedChunks));
}
for (var i = inheritedChunks.Count - 1; i >= 0; i--)
{
var injectChunk = inheritedChunks[i] as InjectChunk;
if (injectChunk != null &&
_addedMemberNames.Add(injectChunk.MemberName))
{
chunkTree.Chunks.Add(TransformChunk(injectChunk));
}
}
}
private InjectChunk TransformChunk(InjectChunk injectChunk)
{
var typeName = ChunkHelper.ReplaceTModel(injectChunk.TypeName, _modelType);
if (typeName != injectChunk.TypeName)
{
return new InjectChunk(typeName, injectChunk.MemberName)
{
Start = injectChunk.Start,
Association = injectChunk.Association
};
}
return injectChunk;
}
}
}

Просмотреть файл

@ -0,0 +1,85 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// A <see cref="IChunkMerger"/> that merges <see cref="SetBaseTypeChunk"/> instances.
/// </summary>
public class SetBaseTypeChunkMerger : IChunkMerger
{
private readonly string _modelType;
private bool _isBaseTypeSet;
/// <summary>
/// Initializes a new instance of <see cref="SetBaseTypeChunkMerger"/>.
/// </summary>
/// <param name="modelType">The type name of the model used by default.</param>
public SetBaseTypeChunkMerger(string modelType)
{
_modelType = "<" + modelType + ">";
}
/// <inheritdoc />
public void VisitChunk(Chunk chunk)
{
if (chunk == null)
{
throw new ArgumentNullException(nameof(chunk));
}
var setBaseTypeChunk = chunk as SetBaseTypeChunk;
if (setBaseTypeChunk != null)
{
setBaseTypeChunk.TypeName = ChunkHelper.ReplaceTModel(setBaseTypeChunk.TypeName, _modelType);
_isBaseTypeSet = true;
}
}
/// <inheritdoc />
public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList<Chunk> inheritedChunks)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (inheritedChunks == null)
{
throw new ArgumentNullException(nameof(inheritedChunks));
}
if (!_isBaseTypeSet)
{
for (var i = inheritedChunks.Count - 1; i >= 0; i--)
{
var baseTypeChunk = inheritedChunks[i] as SetBaseTypeChunk;
if (baseTypeChunk != null)
{
chunkTree.Chunks.Add(TransformChunk(baseTypeChunk));
break;
}
}
}
}
private SetBaseTypeChunk TransformChunk(SetBaseTypeChunk setBaseTypeChunk)
{
var typeName = ChunkHelper.ReplaceTModel(setBaseTypeChunk.TypeName, _modelType);
if (typeName != setBaseTypeChunk.TypeName)
{
return new SetBaseTypeChunk
{
TypeName = typeName,
Start = setBaseTypeChunk.Start,
Association = setBaseTypeChunk.Association
};
}
return setBaseTypeChunk;
}
}
}

Просмотреть файл

@ -0,0 +1,56 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor.Directives
{
/// <summary>
/// A <see cref="IChunkMerger"/> that merges <see cref="UsingChunk"/> instances.
/// </summary>
public class UsingChunkMerger : IChunkMerger
{
private readonly HashSet<string> _currentUsings = new HashSet<string>(StringComparer.Ordinal);
/// <inheritdoc />
public void VisitChunk(Chunk chunk)
{
if (chunk == null)
{
throw new ArgumentNullException(nameof(chunk));
}
var namespaceChunk = chunk as UsingChunk;
if (namespaceChunk != null)
{
_currentUsings.Add(namespaceChunk.Namespace);
}
}
/// <inheritdoc />
public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList<Chunk> inheritedChunks)
{
if (chunkTree == null)
{
throw new ArgumentNullException(nameof(chunkTree));
}
if (inheritedChunks == null)
{
throw new ArgumentNullException(nameof(inheritedChunks));
}
var namespaceChunks = inheritedChunks.OfType<UsingChunk>();
foreach (var namespaceChunk in namespaceChunks)
{
if (_currentUsings.Add(namespaceChunk.Namespace))
{
chunkTree.Chunks.Add(namespaceChunk);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// 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.
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// Contains information for the <see cref="AspNet.Razor.TagHelpers.ITagHelper"/> attribute code
/// generation process.
/// </summary>
public class GeneratedTagHelperAttributeContext
{
/// <summary>
/// Name of the model expression type.
/// </summary>
public string ModelExpressionTypeName { get; set; }
/// <summary>
/// Name the method to create <c>ModelExpression</c>s.
/// </summary>
public string CreateModelExpressionMethodName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// 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.IO;
using Microsoft.AspNet.Razor.CodeGenerators;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// Specifies the contracts for a Razor host that parses Razor files and generates C# code.
/// </summary>
public interface IMvcRazorHost
{
/// <summary>
/// Parses and generates the contents of a Razor file represented by <paramref name="inputStream"/>.
/// </summary>
/// <param name="rootRelativePath">The path of the relative to the root of the application.
/// Used to generate line pragmas and calculate the class name of the generated type.</param>
/// <param name="inputStream">A <see cref="Stream"/> that represents the Razor contents.</param>
/// <returns>A <see cref="GeneratorResults"/> instance that represents the results of code generation.
/// </returns>
GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream);
/// <summary>
/// Represent the prefix off the main entry class in the view.
/// </summary>
string MainClassNamePrefix { get; }
/// <summary>
/// Represent the namespace the main entry class in the view.
/// </summary>
string DefaultNamespace { get; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// 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.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor
{
public class InjectChunk : Chunk
{
/// <summary>
/// Represents the chunk for an @inject statement.
/// </summary>
/// <param name="typeName">The type name of the property to be injected</param>
/// <param name="propertyName">The member name of the property to be injected.</param>
public InjectChunk(
string typeName,
string propertyName)
{
TypeName = typeName;
MemberName = propertyName;
}
/// <summary>
/// Gets or sets the type name of the property to be injected.
/// </summary>
public string TypeName { get; set; }
/// <summary>
/// Gets or sets the name of the property to be injected.
/// </summary>
public string MemberName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
namespace Microsoft.AspNet.Mvc.Razor
{
public class InjectChunkVisitor : MvcCSharpCodeVisitor
{
private readonly string _injectAttribute;
public InjectChunkVisitor(
CSharpCodeWriter writer,
CodeGeneratorContext context,
string injectAttributeName)
: base(writer, context)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (injectAttributeName == null)
{
throw new ArgumentNullException(nameof(injectAttributeName));
}
_injectAttribute = "[" + injectAttributeName + "]";
}
public IList<InjectChunk> InjectChunks { get; } = new List<InjectChunk>();
protected override void Visit(InjectChunk chunk)
{
if (chunk == null)
{
throw new ArgumentNullException(nameof(chunk));
}
Writer.WriteLine(_injectAttribute);
// Some of the chunks that we visit are either InjectDescriptors that are added by default or
// are chunks from _ViewStart files and are not associated with any Spans. Invoking
// CreateExpressionMapping to produce line mappings on these chunks would fail. We'll skip
// generating code mappings for these chunks. This makes sense since the chunks do not map
// to any code in the current view.
if (Context.Host.DesignTimeMode && chunk.Association != null)
{
Writer.WriteLine("public");
var code = string.IsNullOrEmpty(chunk.MemberName) ?
chunk.TypeName :
chunk.TypeName + " " + chunk.MemberName;
var csharpVisitor = new CSharpCodeVisitor(Writer, Context);
csharpVisitor.CreateExpressionCodeMapping(code, chunk);
Writer.WriteLine("{ get; private set; }");
}
else
{
Writer.Write("public ")
.Write(chunk.TypeName)
.Write(" ")
.Write(chunk.MemberName)
.WriteLine(" { get; private set; }");
}
InjectChunks.Add(chunk);
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
// 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;
using System.Globalization;
using Microsoft.AspNet.Razor.Chunks.Generators;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Mvc.Razor
{
public class InjectParameterGenerator : SpanChunkGenerator
{
public InjectParameterGenerator(string typeName, string propertyName)
{
TypeName = typeName;
PropertyName = propertyName;
}
public string TypeName { get; private set; }
public string PropertyName { get; private set; }
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
var injectChunk = new InjectChunk(TypeName, PropertyName);
context.ChunkTreeBuilder.AddChunk(injectChunk, target);
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "@inject {0} {1}", TypeName, PropertyName);
}
public override bool Equals(object obj)
{
var other = obj as InjectParameterGenerator;
return other != null &&
string.Equals(TypeName, other.TypeName, StringComparison.Ordinal) &&
string.Equals(PropertyName, other.PropertyName, StringComparison.Ordinal);
}
public override int GetHashCode()
{
return TypeName.GetHashCode() +
(PropertyName.GetHashCode() * 13);
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
// 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;
using System.IO;
namespace Microsoft.AspNet.Mvc.Razor.Internal
{
public class DesignTimeRazorPathNormalizer : RazorPathNormalizer
{
private readonly string _applicationRoot;
public DesignTimeRazorPathNormalizer(string applicationRoot)
{
if (applicationRoot == null)
{
throw new ArgumentNullException(nameof(applicationRoot));
}
_applicationRoot = applicationRoot;
}
public override string NormalizePath(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
// Need to convert path to application relative (rooted paths are passed in during design time).
if (Path.IsPathRooted(path) && path.StartsWith(_applicationRoot, StringComparison.Ordinal))
{
path = path.Substring(_applicationRoot.Length);
}
return path;
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// 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;
namespace Microsoft.AspNet.Mvc.Razor.Internal
{
public class RazorPathNormalizer
{
public virtual string NormalizePath(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
return path;
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>85c54a84-3e60-40e1-be39-c2f514dd922e</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

Просмотреть файл

@ -0,0 +1,27 @@
// 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.AspNet.Razor.Chunks;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// <see cref="Chunk"/> for an <c>@model</c> directive.
/// </summary>
public class ModelChunk : Chunk
{
/// <summary>
/// Initializes a new instance of <see cref="ModelChunk"/>.
/// </summary>
/// <param name="modelType">The type of the view's model.</param>
public ModelChunk(string modelType)
{
ModelType = modelType;
}
/// <summary>
/// Gets the type of the view's model.
/// </summary>
public string ModelType { get; }
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// 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;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Razor.Chunks.Generators;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class ModelChunkGenerator : SpanChunkGenerator
{
public ModelChunkGenerator(string modelType)
{
ModelType = modelType;
}
public string ModelType { get; }
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
var modelChunk = new ModelChunk(ModelType);
context.ChunkTreeBuilder.AddChunk(modelChunk, target, topLevel: true);
}
public override string ToString() => ModelType;
public override bool Equals(object obj)
{
var other = obj as ModelChunkGenerator;
return other != null &&
string.Equals(ModelType, other.ModelType, StringComparison.Ordinal);
}
public override int GetHashCode()
{
return StringComparer.Ordinal.GetHashCode(ModelType);
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
// 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;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
namespace Microsoft.AspNet.Mvc.Razor
{
public abstract class MvcCSharpChunkVisitor : CodeVisitor<CSharpCodeWriter>
{
public MvcCSharpChunkVisitor(
CSharpCodeWriter writer,
CodeGeneratorContext context)
: base(writer, context)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
}
public override void Accept(Chunk chunk)
{
if (chunk is InjectChunk)
{
Visit((InjectChunk)chunk);
}
else
{
base.Accept(chunk);
}
}
protected abstract void Visit(InjectChunk chunk);
}
}

Просмотреть файл

@ -0,0 +1,128 @@
// 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;
using System.IO;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcCSharpCodeGenerator : CSharpCodeGenerator
{
private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext;
private readonly string _defaultModel;
private readonly string _injectAttribute;
public MvcCSharpCodeGenerator(
CodeGeneratorContext context,
string defaultModel,
string injectAttribute,
GeneratedTagHelperAttributeContext tagHelperAttributeContext)
: base(context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (defaultModel == null)
{
throw new ArgumentNullException(nameof(defaultModel));
}
if (injectAttribute == null)
{
throw new ArgumentNullException(nameof(injectAttribute));
}
if (tagHelperAttributeContext == null)
{
throw new ArgumentNullException(nameof(tagHelperAttributeContext));
}
_tagHelperAttributeContext = tagHelperAttributeContext;
_defaultModel = defaultModel;
_injectAttribute = injectAttribute;
}
protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
{
if (Context.Host.DesignTimeMode &&
string.Equals(
Path.GetFileName(Context.SourceFile),
ViewHierarchyUtility.ViewImportsFileName,
StringComparison.OrdinalIgnoreCase))
{
// Write a using TModel = System.Object; token during design time to make intellisense work
writer.WriteLine($"using {ChunkHelper.TModelToken} = {typeof(object).FullName};");
}
return base.BuildClassDeclaration(writer);
}
protected override CSharpCodeVisitor CreateCSharpCodeVisitor(
CSharpCodeWriter writer,
CodeGeneratorContext context)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var csharpCodeVisitor = base.CreateCSharpCodeVisitor(writer, context);
csharpCodeVisitor.TagHelperRenderer.AttributeValueCodeRenderer =
new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext);
return csharpCodeVisitor;
}
protected override CSharpDesignTimeCodeVisitor CreateCSharpDesignTimeCodeVisitor(
CSharpCodeVisitor csharpCodeVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
{
if (csharpCodeVisitor == null)
{
throw new ArgumentNullException(nameof(csharpCodeVisitor));
}
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new MvcCSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, context);
}
protected override void BuildConstructor(CSharpCodeWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
base.BuildConstructor(writer);
writer.WriteLineHiddenDirective();
var injectVisitor = new InjectChunkVisitor(writer, Context, _injectAttribute);
injectVisitor.Accept(Context.ChunkTreeBuilder.ChunkTree.Chunks);
writer.WriteLine();
writer.WriteLineHiddenDirective();
}
}
}

Просмотреть файл

@ -0,0 +1,31 @@
// 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;
using Microsoft.AspNet.Razor.CodeGenerators;
namespace Microsoft.AspNet.Mvc.Razor
{
public abstract class MvcCSharpCodeVisitor : MvcCSharpChunkVisitor
{
public MvcCSharpCodeVisitor(
CSharpCodeWriter writer,
CodeGeneratorContext context)
: base(writer, context)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
}
protected override void Visit(InjectChunk chunk)
{
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// 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.Diagnostics;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcCSharpDesignTimeCodeVisitor : CSharpDesignTimeCodeVisitor
{
private const string ModelVariable = "__modelHelper";
private ModelChunk _modelChunk;
public MvcCSharpDesignTimeCodeVisitor(
CSharpCodeVisitor csharpCodeVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
: base(csharpCodeVisitor, writer, context)
{
}
protected override void AcceptTreeCore(ChunkTree tree)
{
base.AcceptTreeCore(tree);
if (_modelChunk != null)
{
WriteModelChunkLineMapping();
}
}
public override void Accept(Chunk chunk)
{
if (chunk is ModelChunk)
{
Visit((ModelChunk)chunk);
}
base.Accept(chunk);
}
private void Visit(ModelChunk chunk)
{
Debug.Assert(chunk != null);
_modelChunk = chunk;
}
private void WriteModelChunkLineMapping()
{
Debug.Assert(Context.Host.DesignTimeMode);
using (var lineMappingWriter =
Writer.BuildLineMapping(_modelChunk.Start, _modelChunk.ModelType.Length, Context.SourceFile))
{
// var __modelHelper = default(MyModel);
Writer.Write("var ")
.Write(ModelVariable)
.Write(" = default(");
lineMappingWriter.MarkLineMappingStart();
Writer.Write(_modelChunk.ModelType);
lineMappingWriter.MarkLineMappingEnd();
Writer.WriteLine(");");
}
}
}
}

Просмотреть файл

@ -0,0 +1,172 @@
// 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.Diagnostics;
using Microsoft.AspNet.Mvc.Razor.Host;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Chunks.Generators;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcRazorCodeParser : CSharpCodeParser
{
private const string ModelKeyword = "model";
private const string InjectKeyword = "inject";
private SourceLocation? _endInheritsLocation;
private bool _modelStatementFound;
public MvcRazorCodeParser()
{
MapDirectives(ModelDirective, ModelKeyword);
MapDirectives(InjectDirective, InjectKeyword);
}
protected override void InheritsDirective()
{
// Verify we're on the right keyword and accept
AssertDirective(SyntaxConstants.CSharp.InheritsKeyword);
AcceptAndMoveNext();
_endInheritsLocation = CurrentLocation;
InheritsDirectiveCore();
CheckForInheritsAndModelStatements();
}
private void CheckForInheritsAndModelStatements()
{
if (_modelStatementFound && _endInheritsLocation.HasValue)
{
Context.OnError(
_endInheritsLocation.Value,
Resources.FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(ModelKeyword),
SyntaxConstants.CSharp.InheritsKeyword.Length);
}
}
protected virtual void ModelDirective()
{
// Verify we're on the right keyword and accept
AssertDirective(ModelKeyword);
var startModelLocation = CurrentLocation;
AcceptAndMoveNext();
BaseTypeDirective(Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(ModelKeyword),
CreateModelChunkGenerator);
if (_modelStatementFound)
{
Context.OnError(
startModelLocation,
Resources.FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(ModelKeyword),
ModelKeyword.Length);
}
_modelStatementFound = true;
CheckForInheritsAndModelStatements();
}
protected virtual void InjectDirective()
{
// @inject MyApp.MyService MyServicePropertyName
AssertDirective(InjectKeyword);
var startLocation = CurrentLocation;
AcceptAndMoveNext();
Context.CurrentBlock.Type = BlockType.Directive;
// Accept whitespace
var remainingWhitespace = AcceptSingleWhiteSpaceCharacter();
var keywordwithSingleWhitespaceLength = Span.GetContent().Value.Length;
if (Span.Symbols.Count > 1)
{
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
}
Output(SpanKind.MetaCode);
if (remainingWhitespace != null)
{
Accept(remainingWhitespace);
}
var remainingWhitespaceLength = Span.GetContent().Value.Length;
// Consume any other whitespace tokens.
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
var hasTypeError = !At(CSharpSymbolType.Identifier);
if (hasTypeError)
{
Context.OnError(
startLocation,
Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(InjectKeyword),
InjectKeyword.Length);
}
// Accept 'MyApp.MyService'
NamespaceOrTypeName();
// typeName now contains the token 'MyApp.MyService'
var typeName = Span.GetContent().Value;
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
if (!hasTypeError && (EndOfFile || At(CSharpSymbolType.NewLine)))
{
// Add an error for the property name only if we successfully read the type name
Context.OnError(
startLocation,
Resources.FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(InjectKeyword),
keywordwithSingleWhitespaceLength + remainingWhitespaceLength + typeName.Length);
}
// Read until end of line. Span now contains 'MyApp.MyService MyServiceName'.
AcceptUntil(CSharpSymbolType.NewLine);
if (!Context.DesignTimeMode)
{
// We want the newline to be treated as code, but it causes issues at design-time.
Optional(CSharpSymbolType.NewLine);
}
// Parse out 'MyServicePropertyName' from the Span.
var propertyName = Span.GetContent()
.Value
.Substring(typeName.Length);
// ';' is optional
propertyName = RemoveWhitespaceAndTrailingSemicolons(propertyName);
Span.ChunkGenerator = new InjectParameterGenerator(typeName.Trim(), propertyName);
// Output the span and finish the block
CompleteBlock();
Output(SpanKind.Code, AcceptedCharacters.AnyExceptNewline);
}
private SpanChunkGenerator CreateModelChunkGenerator(string model)
{
return new ModelChunkGenerator(model);
}
// Internal for unit testing
internal static string RemoveWhitespaceAndTrailingSemicolons(string value)
{
Debug.Assert(value != null);
value = value.TrimStart();
for (var index = value.Length - 1; index >= 0; index--)
{
var currentChar = value[index];
if (!char.IsWhiteSpace(currentChar) && currentChar != ';')
{
return value.Substring(0, index + 1);
}
}
return string.Empty;
}
}
}

Просмотреть файл

@ -0,0 +1,335 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNet.FileProviders.VSRC1;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcRazorHost : RazorEngineHost, IMvcRazorHost
{
private const string BaseType = "Microsoft.AspNet.Mvc.Razor.RazorPage";
private const string HtmlHelperPropertyName = "Html";
private static readonly string[] _defaultNamespaces = new[]
{
"System",
"System.Linq",
"System.Collections.Generic",
"Microsoft.AspNet.Mvc",
"Microsoft.AspNet.Mvc.Rendering",
};
private static readonly Chunk[] _defaultInheritedChunks = new Chunk[]
{
new InjectChunk("Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<TModel>", HtmlHelperPropertyName),
new InjectChunk("Microsoft.AspNet.Mvc.Rendering.IJsonHelper", "Json"),
new InjectChunk("Microsoft.AspNet.Mvc.IViewComponentHelper", "Component"),
new InjectChunk("Microsoft.AspNet.Mvc.IUrlHelper", "Url"),
new AddTagHelperChunk
{
LookupText = "Microsoft.AspNet.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNet.Mvc.Razor"
},
new SetBaseTypeChunk
{
// Microsoft.Aspnet.Mvc.Razor.RazorPage<TModel>
TypeName = $"{BaseType}<{ChunkHelper.TModelToken}>",
// Set the Start to Undefined to prevent Razor design time code generation from rendering a line mapping
// for this chunk.
Start = SourceLocation.Undefined
}
};
// CodeGenerationContext.DefaultBaseClass is set to MyBaseType<dynamic>.
private readonly IChunkTreeCache _chunkTreeCache;
private readonly RazorPathNormalizer _pathNormalizer;
private ChunkInheritanceUtility _chunkInheritanceUtility;
private ITagHelperDescriptorResolver _tagHelperDescriptorResolver;
internal MvcRazorHost(IChunkTreeCache chunkTreeCache, RazorPathNormalizer pathNormalizer)
: base(new CSharpRazorCodeLanguage())
{
_pathNormalizer = pathNormalizer;
_chunkTreeCache = chunkTreeCache;
DefaultBaseClass = $"{BaseType}<{ChunkHelper.TModelToken}>";
DefaultNamespace = "Asp";
// Enable instrumentation by default to allow precompiled views to work with BrowserLink.
EnableInstrumentation = true;
GeneratedClassContext = new GeneratedClassContext(
executeMethodName: "ExecuteAsync",
writeMethodName: "Write",
writeLiteralMethodName: "WriteLiteral",
writeToMethodName: "WriteTo",
writeLiteralToMethodName: "WriteLiteralTo",
templateTypeName: "Microsoft.AspNet.Mvc.Razor.HelperResult",
defineSectionMethodName: "DefineSection",
generatedTagHelperContext: new GeneratedTagHelperContext
{
ExecutionContextTypeName = typeof(TagHelperExecutionContext).FullName,
ExecutionContextAddMethodName = nameof(TagHelperExecutionContext.Add),
ExecutionContextAddTagHelperAttributeMethodName =
nameof(TagHelperExecutionContext.AddTagHelperAttribute),
ExecutionContextAddHtmlAttributeMethodName = nameof(TagHelperExecutionContext.AddHtmlAttribute),
ExecutionContextAddMinimizedHtmlAttributeMethodName =
nameof(TagHelperExecutionContext.AddMinimizedHtmlAttribute),
ExecutionContextOutputPropertyName = nameof(TagHelperExecutionContext.Output),
RunnerTypeName = typeof(TagHelperRunner).FullName,
RunnerRunAsyncMethodName = nameof(TagHelperRunner.RunAsync),
ScopeManagerTypeName = typeof(TagHelperScopeManager).FullName,
ScopeManagerBeginMethodName = nameof(TagHelperScopeManager.Begin),
ScopeManagerEndMethodName = nameof(TagHelperScopeManager.End),
TagHelperContentTypeName = nameof(TagHelperContent),
// Can't use nameof because RazorPage is not accessible here.
CreateTagHelperMethodName = "CreateTagHelper",
FormatInvalidIndexerAssignmentMethodName = "InvalidTagHelperIndexerAssignment",
StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope",
EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope",
WriteTagHelperAsyncMethodName = "WriteTagHelperAsync",
WriteTagHelperToAsyncMethodName = "WriteTagHelperToAsync",
// Can't use nameof because IHtmlHelper is (also) not accessible here.
MarkAsHtmlEncodedMethodName = HtmlHelperPropertyName + ".Raw",
BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues",
EndAddHtmlAttributeValuesMethodName = "EndAddHtmlAttributeValues",
AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue",
HtmlEncoderPropertyName = "HtmlEncoder",
TagHelperContentGetContentMethodName = nameof(TagHelperContent.GetContent),
})
{
BeginContextMethodName = "BeginContext",
EndContextMethodName = "EndContext"
};
foreach (var ns in _defaultNamespaces)
{
NamespaceImports.Add(ns);
}
}
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorHost"/> with the specified <paramref name="root"/>.
/// </summary>
/// <param name="root">The path to the application base.</param>
// Note: This constructor is used by tooling and is created once for each
// Razor page that is loaded. Consequently, each loaded page has its own copy of
// the ChunkTreeCache, but this ok - having a shared ChunkTreeCache per application in tooling
// is problematic to manage.
public MvcRazorHost(string root)
: this(new DefaultChunkTreeCache(new PhysicalFileProvider(root)), new DesignTimeRazorPathNormalizer(root))
{
}
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorHost"/> using the specified <paramref name="chunkTreeCache"/>.
/// </summary>
/// <param name="chunkTreeCache">An <see cref="IChunkTreeCache"/> rooted at the application base path.</param>
public MvcRazorHost(IChunkTreeCache chunkTreeCache)
: this(chunkTreeCache, new RazorPathNormalizer())
{
}
/// <inheritdoc />
public override ITagHelperDescriptorResolver TagHelperDescriptorResolver
{
get
{
// The initialization of the _tagHelperDescriptorResolver needs to be lazy to allow for the setting
// of DesignTimeMode.
if (_tagHelperDescriptorResolver == null)
{
_tagHelperDescriptorResolver = new TagHelperDescriptorResolver(DesignTimeMode);
}
return _tagHelperDescriptorResolver;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_tagHelperDescriptorResolver = value;
}
}
/// <summary>
/// Gets the model type used by default when no model is specified.
/// </summary>
/// <remarks>This value is used as the generic type argument for the base type </remarks>
public virtual string DefaultModel
{
get { return "dynamic"; }
}
/// <inheritdoc />
public string MainClassNamePrefix
{
get { return "ASPV_"; }
}
/// <summary>
/// Gets the list of chunks that are injected by default by this host.
/// </summary>
public virtual IReadOnlyList<Chunk> DefaultInheritedChunks
{
get { return _defaultInheritedChunks; }
}
/// <summary>
/// Gets or sets the name attribute that is used to decorate properties that are injected and need to be
/// activated.
/// </summary>
public virtual string InjectAttribute
{
get { return "Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute"; }
}
/// <summary>
/// Gets the type name used to represent <see cref="ITagHelper"/> model expression properties.
/// </summary>
public virtual string ModelExpressionType
{
get { return "Microsoft.AspNet.Mvc.Rendering.ModelExpression"; }
}
/// <summary>
/// Gets the method name used to create model expressions.
/// </summary>
public virtual string CreateModelExpressionMethod
{
get { return "CreateModelExpression"; }
}
// Internal for testing
internal ChunkInheritanceUtility ChunkInheritanceUtility
{
get
{
if (_chunkInheritanceUtility == null)
{
// This needs to be lazily evaluated to support DefaultInheritedChunks being virtual.
_chunkInheritanceUtility = new ChunkInheritanceUtility(this, _chunkTreeCache, DefaultInheritedChunks);
}
return _chunkInheritanceUtility;
}
set
{
_chunkInheritanceUtility = value;
}
}
/// <summary>
/// Locates and parses _ViewImports.cshtml files applying to the given <paramref name="sourceFileName"/> to
/// create <see cref="ChunkTreeResult"/>s.
/// </summary>
/// <param name="sourceFileName">The path to a Razor file to locate _ViewImports.cshtml for.</param>
/// <returns>Inherited <see cref="ChunkTreeResult"/>s.</returns>
public IReadOnlyList<ChunkTreeResult> GetInheritedChunkTreeResults(string sourceFileName)
{
if (sourceFileName == null)
{
throw new ArgumentNullException(nameof(sourceFileName));
}
// Need the normalized path to resolve inherited chunks only. Full paths are needed for generated Razor
// files checksum and line pragmas to enable DesignTime debugging.
var normalizedPath = _pathNormalizer.NormalizePath(sourceFileName);
return ChunkInheritanceUtility.GetInheritedChunkTreeResults(normalizedPath);
}
/// <inheritdoc />
public GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream)
{
// Adding a prefix so that the main view class can be easily identified.
var className = MainClassNamePrefix + ParserHelpers.SanitizeClassName(rootRelativePath);
var engine = new RazorTemplateEngine(this);
return engine.GenerateCode(inputStream, className, DefaultNamespace, rootRelativePath);
}
/// <inheritdoc />
public override RazorParser DecorateRazorParser(RazorParser razorParser, string sourceFileName)
{
if (razorParser == null)
{
throw new ArgumentNullException(nameof(razorParser));
}
var inheritedChunkTrees = GetInheritedChunkTrees(sourceFileName);
return new MvcRazorParser(razorParser, inheritedChunkTrees, DefaultInheritedChunks, ModelExpressionType);
}
/// <inheritdoc />
public override ParserBase DecorateCodeParser(ParserBase incomingCodeParser)
{
if (incomingCodeParser == null)
{
throw new ArgumentNullException(nameof(incomingCodeParser));
}
return new MvcRazorCodeParser();
}
/// <inheritdoc />
public override CodeGenerator DecorateCodeGenerator(
CodeGenerator incomingGenerator,
CodeGeneratorContext context)
{
if (incomingGenerator == null)
{
throw new ArgumentNullException(nameof(incomingGenerator));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var inheritedChunkTrees = GetInheritedChunkTrees(context.SourceFile);
ChunkInheritanceUtility.MergeInheritedChunkTrees(
context.ChunkTreeBuilder.ChunkTree,
inheritedChunkTrees,
DefaultModel);
return new MvcCSharpCodeGenerator(
context,
DefaultModel,
InjectAttribute,
new GeneratedTagHelperAttributeContext
{
ModelExpressionTypeName = ModelExpressionType,
CreateModelExpressionMethodName = CreateModelExpressionMethod
});
}
private IReadOnlyList<ChunkTree> GetInheritedChunkTrees(string sourceFileName)
{
var inheritedChunkTrees = GetInheritedChunkTreeResults(sourceFileName)
.Select(result => result.ChunkTree)
.ToList();
return inheritedChunkTrees;
}
}
}

Просмотреть файл

@ -0,0 +1,229 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.Razor.Host;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Parser.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// A subtype of <see cref="RazorParser"/> that <see cref="MvcRazorHost"/> uses to support inheritance of tag
/// helpers from <c>_ViewImports</c> files.
/// </summary>
public class MvcRazorParser : RazorParser
{
private readonly IEnumerable<TagHelperDirectiveDescriptor> _viewImportsDirectiveDescriptors;
private readonly string _modelExpressionTypeName;
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorParser"/>.
/// </summary>
/// <param name="parser">The <see cref="RazorParser"/> to copy properties from.</param>
/// <param name="inheritedChunkTrees">The <see cref="IReadOnlyList{ChunkTree}"/>s that are inherited
/// from parsed pages from _ViewImports files.</param>
/// <param name="defaultInheritedChunks">The <see cref="IReadOnlyList{Chunk}"/> inherited by
/// default by all Razor pages in the application.</param>
public MvcRazorParser(
RazorParser parser,
IReadOnlyList<ChunkTree> inheritedChunkTrees,
IReadOnlyList<Chunk> defaultInheritedChunks,
string modelExpressionTypeName)
: base(parser)
{
if (parser == null)
{
throw new ArgumentNullException(nameof(parser));
}
if (inheritedChunkTrees == null)
{
throw new ArgumentNullException(nameof(inheritedChunkTrees));
}
if (defaultInheritedChunks == null)
{
throw new ArgumentNullException(nameof(defaultInheritedChunks));
}
if (modelExpressionTypeName == null)
{
throw new ArgumentNullException(nameof(modelExpressionTypeName));
}
// Construct tag helper descriptors from @addTagHelper, @removeTagHelper and @tagHelperPrefix chunks
_viewImportsDirectiveDescriptors = GetTagHelperDirectiveDescriptors(
inheritedChunkTrees,
defaultInheritedChunks);
_modelExpressionTypeName = modelExpressionTypeName;
}
/// <inheritdoc />
protected override IEnumerable<TagHelperDescriptor> GetTagHelperDescriptors(
Block documentRoot,
ErrorSink errorSink)
{
if (documentRoot == null)
{
throw new ArgumentNullException(nameof(documentRoot));
}
if (errorSink == null)
{
throw new ArgumentNullException(nameof(errorSink));
}
var visitor = new ViewImportsTagHelperDirectiveSpanVisitor(
TagHelperDescriptorResolver,
_viewImportsDirectiveDescriptors,
errorSink);
var descriptors = visitor.GetDescriptors(documentRoot);
foreach (var descriptor in descriptors)
{
foreach (var attributeDescriptor in descriptor.Attributes)
{
if (attributeDescriptor.IsIndexer &&
string.Equals(
attributeDescriptor.TypeName,
_modelExpressionTypeName,
StringComparison.Ordinal))
{
errorSink.OnError(
SourceLocation.Undefined,
Resources.FormatMvcRazorParser_InvalidPropertyType(
descriptor.TypeName,
attributeDescriptor.Name,
_modelExpressionTypeName),
length: 0);
}
}
}
return descriptors;
}
private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDescriptors(
IReadOnlyList<ChunkTree> inheritedChunkTrees,
IReadOnlyList<Chunk> defaultInheritedChunks)
{
var descriptors = new List<TagHelperDirectiveDescriptor>();
var inheritedChunks = defaultInheritedChunks.Concat(inheritedChunkTrees.SelectMany(tree => tree.Chunks));
foreach (var chunk in inheritedChunks)
{
// All TagHelperDirectiveDescriptors created here have undefined source locations because the source
// that created them is not in the same file.
var addTagHelperChunk = chunk as AddTagHelperChunk;
if (addTagHelperChunk != null)
{
var descriptor = new TagHelperDirectiveDescriptor
{
DirectiveText = addTagHelperChunk.LookupText,
Location = chunk.Start,
DirectiveType = TagHelperDirectiveType.AddTagHelper
};
descriptors.Add(descriptor);
continue;
}
var removeTagHelperChunk = chunk as RemoveTagHelperChunk;
if (removeTagHelperChunk != null)
{
var descriptor = new TagHelperDirectiveDescriptor
{
DirectiveText = removeTagHelperChunk.LookupText,
Location = chunk.Start,
DirectiveType = TagHelperDirectiveType.RemoveTagHelper
};
descriptors.Add(descriptor);
continue;
}
var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk;
if (tagHelperPrefixDirectiveChunk != null)
{
var descriptor = new TagHelperDirectiveDescriptor
{
DirectiveText = tagHelperPrefixDirectiveChunk.Prefix,
Location = chunk.Start,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix
};
descriptors.Add(descriptor);
}
}
return descriptors;
}
private class ViewImportsTagHelperDirectiveSpanVisitor : TagHelperDirectiveSpanVisitor
{
private readonly IEnumerable<TagHelperDirectiveDescriptor> _viewImportsDirectiveDescriptors;
public ViewImportsTagHelperDirectiveSpanVisitor(
ITagHelperDescriptorResolver descriptorResolver,
IEnumerable<TagHelperDirectiveDescriptor> viewImportsDirectiveDescriptors,
ErrorSink errorSink)
: base(descriptorResolver, errorSink)
{
_viewImportsDirectiveDescriptors = viewImportsDirectiveDescriptors;
}
protected override TagHelperDescriptorResolutionContext GetTagHelperDescriptorResolutionContext(
IEnumerable<TagHelperDirectiveDescriptor> descriptors,
ErrorSink errorSink)
{
var directivesToImport = MergeDirectiveDescriptors(descriptors, _viewImportsDirectiveDescriptors);
return base.GetTagHelperDescriptorResolutionContext(directivesToImport, errorSink);
}
private static IEnumerable<TagHelperDirectiveDescriptor> MergeDirectiveDescriptors(
IEnumerable<TagHelperDirectiveDescriptor> descriptors,
IEnumerable<TagHelperDirectiveDescriptor> inheritedDescriptors)
{
var mergedDescriptors = new List<TagHelperDirectiveDescriptor>();
TagHelperDirectiveDescriptor prefixDirectiveDescriptor = null;
foreach (var descriptor in inheritedDescriptors)
{
if (descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix)
{
// Always take the latest @tagHelperPrefix descriptor. Can only have 1 per page.
prefixDirectiveDescriptor = descriptor;
}
else
{
mergedDescriptors.Add(descriptor);
}
}
// We need to see if the provided descriptors contain a @tagHelperPrefix directive. If so, it
// takes precedence and overrides any provided by the inheritedDescriptors. If not we need to add the
// inherited @tagHelperPrefix directive back into the merged list.
if (prefixDirectiveDescriptor != null &&
!descriptors.Any(descriptor => descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix))
{
mergedDescriptors.Add(prefixDirectiveDescriptor);
}
mergedDescriptors.AddRange(descriptors);
return mergedDescriptors;
}
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
// 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;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <inheritdoc />
public class MvcTagHelperAttributeValueCodeRenderer : TagHelperAttributeValueCodeRenderer
{
private const string ModelLambdaVariableName = "__model";
private readonly GeneratedTagHelperAttributeContext _context;
/// <summary>
/// Instantiates a new instance of <see cref="MvcTagHelperAttributeValueCodeRenderer"/>.
/// </summary>
/// <param name="context">Contains code generation information for rendering attribute values.</param>
public MvcTagHelperAttributeValueCodeRenderer(GeneratedTagHelperAttributeContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
_context = context;
}
/// <inheritdoc />
/// <remarks>If the attribute being rendered is of the type
/// <see cref="GeneratedTagHelperAttributeContext.ModelExpressionTypeName"/>, then a model expression will be
/// created by calling into <see cref="GeneratedTagHelperAttributeContext.CreateModelExpressionMethodName"/>.
/// </remarks>
public override void RenderAttributeValue(
TagHelperAttributeDescriptor attributeDescriptor,
CSharpCodeWriter writer,
CodeGeneratorContext codeGeneratorContext,
Action<CSharpCodeWriter> renderAttributeValue,
bool complexValue)
{
if (attributeDescriptor == null)
{
throw new ArgumentNullException(nameof(attributeDescriptor));
}
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (codeGeneratorContext == null)
{
throw new ArgumentNullException(nameof(codeGeneratorContext));
}
if (renderAttributeValue == null)
{
throw new ArgumentNullException(nameof(renderAttributeValue));
}
if (attributeDescriptor.TypeName.Equals(_context.ModelExpressionTypeName, StringComparison.Ordinal))
{
writer
.WriteStartMethodInvocation(_context.CreateModelExpressionMethodName)
.Write(ModelLambdaVariableName)
.Write(" => ");
if (!complexValue)
{
writer
.Write(ModelLambdaVariableName)
.Write(".");
}
renderAttributeValue(writer);
writer.WriteEndMethodInvocation(endLine: false);
}
else
{
base.RenderAttributeValue(
attributeDescriptor,
writer,
codeGeneratorContext,
renderAttributeValue,
complexValue);
}
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
// 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.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: NeutralResourcesLanguage("en-us")]

Просмотреть файл

@ -0,0 +1,126 @@
// <auto-generated />
namespace Microsoft.AspNet.Mvc.Razor.Host
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Mvc.Razor.Host.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpy
{
get { return GetString("ArgumentCannotBeNullOrEmpy"); }
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpy()
{
return GetString("ArgumentCannotBeNullOrEmpy");
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword
{
get { return GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"); }
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"), p0);
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string MvcRazorCodeParser_InjectDirectivePropertyNameRequired
{
get { return GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"); }
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"), p0);
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string MvcRazorCodeParser_KeywordMustBeFollowedByTypeName
{
get { return GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"); }
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"), p0);
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string MvcRazorCodeParser_OnlyOneModelStatementIsAllowed
{
get { return GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"); }
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"), p0);
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string MvcRazorParser_InvalidPropertyType
{
get { return GetString("MvcRazorParser_InvalidPropertyType"); }
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string FormatMvcRazorParser_InvalidPropertyType(object p0, object p1, object p2)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorParser_InvalidPropertyType"), p0, p1, p2);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,513 @@
// 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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace Microsoft.Extensions.Internal
{
internal class PropertyHelper
{
// Delegate type for a by-ref property getter
private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);
private static readonly MethodInfo CallPropertyGetterOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter));
private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference));
private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter));
private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference));
private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter));
// Using an array rather than IEnumerable, as target will be called on the hot path numerous times.
private static readonly ConcurrentDictionary<Type, PropertyHelper[]> PropertiesCache =
new ConcurrentDictionary<Type, PropertyHelper[]>();
private static readonly ConcurrentDictionary<Type, PropertyHelper[]> VisiblePropertiesCache =
new ConcurrentDictionary<Type, PropertyHelper[]>();
private Action<object, object> _valueSetter;
/// <summary>
/// Initializes a fast <see cref="PropertyHelper"/>.
/// This constructor does not cache the helper. For caching, use <see cref="GetProperties(object)"/>.
/// </summary>
public PropertyHelper(PropertyInfo property)
{
if (property == null)
{
throw new ArgumentNullException(nameof(property));
}
Property = property;
Name = property.Name;
ValueGetter = MakeFastPropertyGetter(property);
}
/// <summary>
/// Gets the backing <see cref="PropertyInfo"/>.
/// </summary>
public PropertyInfo Property { get; }
/// <summary>
/// Gets (or sets in derived types) the property name.
/// </summary>
public virtual string Name { get; protected set; }
/// <summary>
/// Gets the property value getter.
/// </summary>
public Func<object, object> ValueGetter { get; }
/// <summary>
/// Gets the property value setter.
/// </summary>
public Action<object, object> ValueSetter
{
get
{
if (_valueSetter == null)
{
// We'll allow safe races here.
_valueSetter = MakeFastPropertySetter(Property);
}
return _valueSetter;
}
}
/// <summary>
/// Returns the property value for the specified <paramref name="instance"/>.
/// </summary>
/// <param name="instance">The object whose property value will be returned.</param>
/// <returns>The property value.</returns>
public object GetValue(object instance)
{
return ValueGetter(instance);
}
/// <summary>
/// Sets the property value for the specified <paramref name="instance" />.
/// </summary>
/// <param name="instance">The object whose property value will be set.</param>
/// <param name="value">The property value.</param>
public void SetValue(object instance, object value)
{
ValueSetter(instance, value);
}
/// <summary>
/// Creates and caches fast property helpers that expose getters for every public get property on the
/// underlying type.
/// </summary>
/// <param name="instance">the instance to extract property accessors for.</param>
/// <returns>a cached array of all public property getters from the underlying type of target instance.
/// </returns>
public static PropertyHelper[] GetProperties(object instance)
{
return GetProperties(instance.GetType());
}
/// <summary>
/// Creates and caches fast property helpers that expose getters for every public get property on the
/// specified type.
/// </summary>
/// <param name="type">the type to extract property accessors for.</param>
/// <returns>a cached array of all public property getters from the type of target instance.
/// </returns>
public static PropertyHelper[] GetProperties(Type type)
{
return GetProperties(type, CreateInstance, PropertiesCache);
}
/// <summary>
/// <para>
/// Creates and caches fast property helpers that expose getters for every non-hidden get property
/// on the specified type.
/// </para>
/// <para>
/// <see cref="GetVisibleProperties"/> excludes properties defined on base types that have been
/// hidden by definitions using the <c>new</c> keyword.
/// </para>
/// </summary>
/// <param name="instance">The instance to extract property accessors for.</param>
/// <returns>
/// A cached array of all public property getters from the instance's type.
/// </returns>
public static PropertyHelper[] GetVisibleProperties(object instance)
{
return GetVisibleProperties(instance.GetType(), CreateInstance, PropertiesCache, VisiblePropertiesCache);
}
/// <summary>
/// <para>
/// Creates a caches fast property helpers that expose getters for every non-hidden get property
/// on the specified type.
/// </para>
/// <para>
/// <see cref="GetVisibleProperties"/> excludes properties defined on base types that have been
/// hidden by definitions using the <c>new</c> keyword.
/// </para>
/// </summary>
/// <param name="type">The type to extract property accessors for.</param>
/// <returns>
/// A cached array of all public property getters from the type.
/// </returns>
public static PropertyHelper[] GetVisibleProperties(Type type)
{
return GetVisibleProperties(type, CreateInstance, PropertiesCache, VisiblePropertiesCache);
}
/// <summary>
/// Creates a single fast property getter. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>
/// This method is more memory efficient than a dynamically compiled lambda, and about the
/// same speed.
/// </remarks>
public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo != null);
return MakeFastPropertyGetter(
propertyInfo,
CallPropertyGetterOpenGenericMethod,
CallPropertyGetterByReferenceOpenGenericMethod);
}
/// <summary>
/// Creates a single fast property getter which is safe for a null input object. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>
/// This method is more memory efficient than a dynamically compiled lambda, and about the
/// same speed.
/// </remarks>
public static Func<object, object> MakeNullSafeFastPropertyGetter(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo != null);
return MakeFastPropertyGetter(
propertyInfo,
CallNullSafePropertyGetterOpenGenericMethod,
CallNullSafePropertyGetterByReferenceOpenGenericMethod);
}
private static Func<object, object> MakeFastPropertyGetter(
PropertyInfo propertyInfo,
MethodInfo propertyGetterWrapperMethod,
MethodInfo propertyGetterByRefWrapperMethod)
{
Debug.Assert(propertyInfo != null);
// Must be a generic method with a Func<,> parameter
Debug.Assert(propertyGetterWrapperMethod != null);
Debug.Assert(propertyGetterWrapperMethod.IsGenericMethodDefinition);
Debug.Assert(propertyGetterWrapperMethod.GetParameters().Length == 2);
// Must be a generic method with a ByRefFunc<,> parameter
Debug.Assert(propertyGetterByRefWrapperMethod != null);
Debug.Assert(propertyGetterByRefWrapperMethod.IsGenericMethodDefinition);
Debug.Assert(propertyGetterByRefWrapperMethod.GetParameters().Length == 2);
var getMethod = propertyInfo.GetMethod;
Debug.Assert(getMethod != null);
Debug.Assert(!getMethod.IsStatic);
Debug.Assert(getMethod.GetParameters().Length == 0);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "target". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
if (getMethod.DeclaringType.GetTypeInfo().IsValueType)
{
// Create a delegate (ref TDeclaringType) -> TValue
return MakeFastPropertyGetter(
typeof(ByRefFunc<,>),
getMethod,
propertyGetterByRefWrapperMethod);
}
else
{
// Create a delegate TDeclaringType -> TValue
return MakeFastPropertyGetter(
typeof(Func<,>),
getMethod,
propertyGetterWrapperMethod);
}
}
private static Func<object, object> MakeFastPropertyGetter(
Type openGenericDelegateType,
MethodInfo propertyGetMethod,
MethodInfo openGenericWrapperMethod)
{
var typeInput = propertyGetMethod.DeclaringType;
var typeOutput = propertyGetMethod.ReturnType;
var delegateType = openGenericDelegateType.MakeGenericType(typeInput, typeOutput);
var propertyGetterDelegate = propertyGetMethod.CreateDelegate(delegateType);
var wrapperDelegateMethod = openGenericWrapperMethod.MakeGenericMethod(typeInput, typeOutput);
var accessorDelegate = wrapperDelegateMethod.CreateDelegate(
typeof(Func<object, object>),
propertyGetterDelegate);
return (Func<object, object>)accessorDelegate;
}
/// <summary>
/// Creates a single fast property setter for reference types. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the setter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>
/// This method is more memory efficient than a dynamically compiled lambda, and about the
/// same speed. This only works for reference types.
/// </remarks>
public static Action<object, object> MakeFastPropertySetter(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo != null);
Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType);
var setMethod = propertyInfo.SetMethod;
Debug.Assert(setMethod != null);
Debug.Assert(!setMethod.IsStatic);
Debug.Assert(setMethod.ReturnType == typeof(void));
var parameters = setMethod.GetParameters();
Debug.Assert(parameters.Length == 1);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "target". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
var typeInput = setMethod.DeclaringType;
var parameterType = parameters[0].ParameterType;
// Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; }
var propertySetterAsAction =
setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType));
var callPropertySetterClosedGenericMethod =
CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType);
var callPropertySetterDelegate =
callPropertySetterClosedGenericMethod.CreateDelegate(
typeof(Action<object, object>), propertySetterAsAction);
return (Action<object, object>)callPropertySetterDelegate;
}
/// <summary>
/// Given an object, adds each instance property with a public get method as a key and its
/// associated value to a dictionary.
///
/// If the object is already an <see cref="IDictionary{string, object}"/> instance, then a copy
/// is returned.
/// </summary>
/// <remarks>
/// The implementation of PropertyHelper will cache the property accessors per-type. This is
/// faster when the the same type is used multiple times with ObjectToDictionary.
/// </remarks>
public static IDictionary<string, object> ObjectToDictionary(object value)
{
var dictionary = value as IDictionary<string, object>;
if (dictionary != null)
{
return new Dictionary<string, object>(dictionary, StringComparer.OrdinalIgnoreCase);
}
dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
if (value != null)
{
foreach (var helper in GetProperties(value))
{
dictionary[helper.Name] = helper.GetValue(value);
}
}
return dictionary;
}
private static PropertyHelper CreateInstance(PropertyInfo property)
{
return new PropertyHelper(property);
}
// Called via reflection
private static object CallPropertyGetter<TDeclaringType, TValue>(
Func<TDeclaringType, TValue> getter,
object target)
{
return getter((TDeclaringType)target);
}
// Called via reflection
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(
ByRefFunc<TDeclaringType, TValue> getter,
object target)
{
var unboxed = (TDeclaringType)target;
return getter(ref unboxed);
}
// Called via reflection
private static object CallNullSafePropertyGetter<TDeclaringType, TValue>(
Func<TDeclaringType, TValue> getter,
object target)
{
if (target == null)
{
return null;
}
return getter((TDeclaringType)target);
}
// Called via reflection
private static object CallNullSafePropertyGetterByReference<TDeclaringType, TValue>(
ByRefFunc<TDeclaringType, TValue> getter,
object target)
{
if (target == null)
{
return null;
}
var unboxed = (TDeclaringType)target;
return getter(ref unboxed);
}
private static void CallPropertySetter<TDeclaringType, TValue>(
Action<TDeclaringType, TValue> setter,
object target,
object value)
{
setter((TDeclaringType)target, (TValue)value);
}
protected static PropertyHelper[] GetVisibleProperties(
Type type,
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
ConcurrentDictionary<Type, PropertyHelper[]> allPropertiesCache,
ConcurrentDictionary<Type, PropertyHelper[]> visiblePropertiesCache)
{
PropertyHelper[] result;
if (visiblePropertiesCache.TryGetValue(type, out result))
{
return result;
}
// The simple and common case, this is normal POCO object - no need to allocate.
var allPropertiesDefinedOnType = true;
var allProperties = GetProperties(type, createPropertyHelper, allPropertiesCache);
foreach (var propertyHelper in allProperties)
{
if (propertyHelper.Property.DeclaringType != type)
{
allPropertiesDefinedOnType = false;
break;
}
}
if (allPropertiesDefinedOnType)
{
result = allProperties;
visiblePropertiesCache.TryAdd(type, result);
return result;
}
// There's some inherited properties here, so we need to check for hiding via 'new'.
var filteredProperties = new List<PropertyHelper>(allProperties.Length);
foreach (var propertyHelper in allProperties)
{
var declaringType = propertyHelper.Property.DeclaringType;
if (declaringType == type)
{
filteredProperties.Add(propertyHelper);
continue;
}
// If this property was declared on a base type then look for the definition closest to the
// the type to see if we should include it.
var ignoreProperty = false;
// Walk up the hierarchy until we find the type that actally declares this
// PropertyInfo.
var currentTypeInfo = type.GetTypeInfo();
var declaringTypeInfo = declaringType.GetTypeInfo();
while (currentTypeInfo != null && currentTypeInfo != declaringTypeInfo)
{
// We've found a 'more proximal' public definition
var declaredProperty = currentTypeInfo.GetDeclaredProperty(propertyHelper.Name);
if (declaredProperty != null)
{
ignoreProperty = true;
break;
}
currentTypeInfo = currentTypeInfo.BaseType?.GetTypeInfo();
}
if (!ignoreProperty)
{
filteredProperties.Add(propertyHelper);
}
}
result = filteredProperties.ToArray();
visiblePropertiesCache.TryAdd(type, result);
return result;
}
protected static PropertyHelper[] GetProperties(
Type type,
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
ConcurrentDictionary<Type, PropertyHelper[]> cache)
{
// Unwrap nullable types. This means Nullable<T>.Value and Nullable<T>.HasValue will not be
// part of the sequence of properties returned by this method.
type = Nullable.GetUnderlyingType(type) ?? type;
PropertyHelper[] helpers;
if (!cache.TryGetValue(type, out helpers))
{
// We avoid loading indexed properties using the Where statement.
var properties = type.GetRuntimeProperties().Where(IsInterestingProperty);
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsInterface)
{
// Reflection does not return information about inherited properties on the interface itself.
properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany(
interfaceType => interfaceType.GetRuntimeProperties().Where(IsInterestingProperty)));
}
helpers = properties.Select(p => createPropertyHelper(p)).ToArray();
cache.TryAdd(type, helpers);
}
return helpers;
}
// Indexed properties are not useful (or valid) for grabbing properties off an object.
private static bool IsInterestingProperty(PropertyInfo property)
{
return property.GetIndexParameters().Length == 0 &&
property.GetMethod != null &&
property.GetMethod.IsPublic &&
!property.GetMethod.IsStatic;
}
}
}

Просмотреть файл

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentCannotBeNullOrEmpy" xml:space="preserve">
<value>Value cannot be null or empty.</value>
</data>
<data name="MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword" xml:space="preserve">
<value>The 'inherits' keyword is not allowed when a '{0}' keyword is used.</value>
</data>
<data name="MvcRazorCodeParser_InjectDirectivePropertyNameRequired" xml:space="preserve">
<value>A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.</value>
</data>
<data name="MvcRazorCodeParser_KeywordMustBeFollowedByTypeName" xml:space="preserve">
<value>The '{0}' keyword must be followed by a type name on the same line.</value>
</data>
<data name="MvcRazorCodeParser_OnlyOneModelStatementIsAllowed" xml:space="preserve">
<value>Only one '{0}' statement is allowed in a file.</value>
</data>
<data name="MvcRazorParser_InvalidPropertyType" xml:space="preserve">
<value>Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,111 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// Contains methods to locate <c>_ViewStart.cshtml</c> and <c>_ViewImports.cshtml</c>
/// </summary>
public static class ViewHierarchyUtility
{
private const string ViewStartFileName = "_ViewStart.cshtml";
/// <summary>
/// File name of <c>_ViewImports.cshtml</c> file
/// </summary>
public static readonly string ViewImportsFileName = "_ViewImports.cshtml";
/// <summary>
/// Gets the view start locations that are applicable to the specified path.
/// </summary>
/// <param name="applicationRelativePath">The application relative path of the file to locate
/// <c>_ViewStart</c>s for.</param>
/// <returns>A sequence of paths that represent potential view start locations.</returns>
/// <remarks>
/// This method returns paths starting from the directory of <paramref name="applicationRelativePath"/> and
/// moves upwards until it hits the application root.
/// e.g.
/// /Views/Home/View.cshtml -> [ /Views/Home/_ViewStart.cshtml, /Views/_ViewStart.cshtml, /_ViewStart.cshtml ]
/// </remarks>
public static IEnumerable<string> GetViewStartLocations(string applicationRelativePath)
{
return GetHierarchicalPath(applicationRelativePath, ViewStartFileName);
}
/// <summary>
/// Gets the locations for <c>_ViewImports</c>s that are applicable to the specified path.
/// </summary>
/// <param name="applicationRelativePath">The application relative path of the file to locate
/// <c>_ViewImports</c>s for.</param>
/// <returns>A sequence of paths that represent potential <c>_ViewImports</c> locations.</returns>
/// <remarks>
/// This method returns paths starting from the directory of <paramref name="applicationRelativePath"/> and
/// moves upwards until it hits the application root.
/// e.g.
/// /Views/Home/View.cshtml -> [ /Views/Home/_ViewImports.cshtml, /Views/_ViewImports.cshtml,
/// /_ViewImports.cshtml ]
/// </remarks>
public static IEnumerable<string> GetViewImportsLocations(string applicationRelativePath)
{
return GetHierarchicalPath(applicationRelativePath, ViewImportsFileName);
}
private static IEnumerable<string> GetHierarchicalPath(string relativePath, string fileName)
{
if (string.IsNullOrEmpty(relativePath))
{
return Enumerable.Empty<string>();
}
if (relativePath.StartsWith("~/", StringComparison.Ordinal))
{
relativePath = relativePath.Substring(2);
}
if (relativePath.StartsWith("/", StringComparison.Ordinal))
{
relativePath = relativePath.Substring(1);
}
if (string.Equals(Path.GetFileName(relativePath), fileName, StringComparison.OrdinalIgnoreCase))
{
// If the specified path is for the file hierarchy being constructed, then the first file that applies
// to it is in a parent directory.
relativePath = Path.GetDirectoryName(relativePath);
if (string.IsNullOrEmpty(relativePath))
{
return Enumerable.Empty<string>();
}
}
var builder = new StringBuilder(relativePath);
builder.Replace('\\', '/');
if (builder.Length > 0 && builder[0] != '/')
{
builder.Insert(0, '/');
}
var locations = new List<string>();
for (var index = builder.Length - 1; index >= 0; index--)
{
if (builder[index] == '/')
{
builder.Length = index + 1;
builder.Append(fileName);
locations.Add(builder.ToString());
}
}
return locations;
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
{
"description": "Design time hosting infrastructure for the ASP.NET MVC Razor view engine.",
"version": "6.0.0-rc1-final",
"repository": {
"type": "git",
"url": "git://github.com/aspnet/mvc"
},
"compilationOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.AspNet.FileProviders.Physical.VSRC1": "1.0.0-rc1-final",
"Microsoft.AspNet.Razor.Runtime.VSRC1": "4.0.0-rc1-final",
"Microsoft.Extensions.Caching.Memory.VSRC1": "1.0.0-rc1-final"
},
"frameworks": {
"net451": {
"dependencies": {
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc1-final"
}
}
},
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
]
}