diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkHelper.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkHelper.cs
index c769c7f1ad..8f39c3596a 100644
--- a/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkHelper.cs
@@ -16,7 +16,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
/// Token that is replaced by the model name in @inherits and @inject
/// chunks as part of .
///
- public static readonly string TModelToken = "";
+ public static readonly string TModelToken = "TModel";
+ private static readonly string TModelReplaceToken = $"<{TModelToken}>";
///
/// Returns the used to determine the model name for the page generated
@@ -86,7 +87,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
throw new ArgumentNullException(nameof(modelName));
}
- return value.Replace(TModelToken, modelName);
+ return value.Replace(TModelReplaceToken, modelName);
}
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs
index 146a3c53cb..7c434d54fe 100644
--- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs
@@ -2,6 +2,8 @@
// 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;
@@ -45,6 +47,21 @@ namespace Microsoft.AspNet.Mvc.Razor
_injectAttribute = injectAttribute;
}
+ protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
+ {
+ if (Context.Host.DesignTimeMode &&
+ string.Equals(
+ Path.GetFileName(Context.SourceFile),
+ ViewHierarchyUtility.ViewImportsFileName,
+ StringComparison.Ordinal))
+ {
+ // 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)
diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs
index 7a3a6db05c..5b31b4accf 100644
--- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs
@@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.Razor
new SetBaseTypeChunk
{
// Microsoft.Aspnet.Mvc.Razor.RazorPage
- TypeName = BaseType + ChunkHelper.TModelToken,
+ 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
@@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.Razor
_pathNormalizer = pathNormalizer;
_chunkTreeCache = chunkTreeCache;
- DefaultBaseClass = BaseType + ChunkHelper.TModelToken;
+ DefaultBaseClass = $"{BaseType}<{ChunkHelper.TModelToken}>";
DefaultNamespace = "Asp";
// Enable instrumentation by default to allow precompiled views to work with BrowserLink.
EnableInstrumentation = true;
diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/ViewHierarchyUtility.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/ViewHierarchyUtility.cs
index aea88d7e8a..676fa65e06 100644
--- a/src/Microsoft.AspNet.Mvc.Razor.Host/ViewHierarchyUtility.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor.Host/ViewHierarchyUtility.cs
@@ -14,7 +14,11 @@ namespace Microsoft.AspNet.Mvc.Razor
public static class ViewHierarchyUtility
{
private const string ViewStartFileName = "_ViewStart.cshtml";
- private const string ViewImportsFileName = "_ViewImports.cshtml";
+
+ ///
+ /// File name of _ViewImports.cshtml file
+ ///
+ public static readonly string ViewImportsFileName = "_ViewImports.cshtml";
///
/// Gets the view start locations that are applicable to the specified path.
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs
index fb741a2220..4c987624d2 100644
--- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorHostTest.cs
@@ -171,6 +171,7 @@ namespace Microsoft.AspNet.Mvc.Razor
[Theory]
[InlineData("Basic")]
+ [InlineData("_ViewImports")]
[InlineData("Inject")]
[InlineData("InjectWithModel")]
[InlineData("InjectWithSemicolon")]
@@ -220,6 +221,32 @@ namespace Microsoft.AspNet.Mvc.Razor
RunDesignTimeTest(host, "Basic", expectedLineMappings);
}
+ [Fact]
+ public void MvcRazorHost_GeneratesCorrectLineMappingsAndUsingStatementsForViewImports()
+ {
+ // Arrange
+ var fileProvider = new TestFileProvider();
+ var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider))
+ {
+ DesignTimeMode = true
+ };
+ host.NamespaceImports.Clear();
+ var expectedLineMappings = new[]
+ {
+ BuildLineMapping(
+ documentAbsoluteIndex: 8,
+ documentLineIndex: 0,
+ documentCharacterIndex: 8,
+ generatedAbsoluteIndex: 661,
+ generatedLineIndex: 21,
+ generatedCharacterIndex: 8,
+ contentLength: 26),
+ };
+
+ // Act and Assert
+ RunDesignTimeTest(host, "_ViewImports", expectedLineMappings);
+ }
+
[Fact]
public void InjectVisitor_GeneratesCorrectLineMappings()
{
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Input/_ViewImports.cshtml b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Input/_ViewImports.cshtml
new file mode 100644
index 0000000000..fea9533d09
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Input/_ViewImports.cshtml
@@ -0,0 +1 @@
+@inject IHtmlHelper Model
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs
new file mode 100644
index 0000000000..7dc8c0a827
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs
@@ -0,0 +1,44 @@
+namespace Asp
+{
+ using System.Threading.Tasks;
+
+ using TModel = System.Object;
+ public class ASPV_TestFiles_Input__ViewImports_cshtml : Microsoft.AspNet.Mvc.Razor.RazorPage
+ {
+ private static object @__o;
+ private void @__RazorDesignTimeHelpers__()
+ {
+ #pragma warning disable 219
+ #pragma warning restore 219
+ }
+ #line hidden
+ public ASPV_TestFiles_Input__ViewImports_cshtml()
+ {
+ }
+ #line hidden
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public
+#line 1 "TestFiles/Input/_ViewImports.cshtml"
+ IHtmlHelper Model
+
+#line default
+#line hidden
+ { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.IUrlHelper Url { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.Rendering.IJsonHelper Json { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.Rendering.IHtmlHelper Html { get; private set; }
+
+ #line hidden
+
+ #pragma warning disable 1998
+ public override async Task ExecuteAsync()
+ {
+ }
+ #pragma warning restore 1998
+ }
+}
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/_ViewImports.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/_ViewImports.cs
new file mode 100644
index 0000000000..704c235968
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/_ViewImports.cs
@@ -0,0 +1,37 @@
+#pragma checksum "TestFiles/Input/_ViewImports.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "778b41f9406fcda776cc3f1bf093f3b21956e582"
+namespace Asp
+{
+ using System;
+ using System.Linq;
+ using System.Collections.Generic;
+ using Microsoft.AspNet.Mvc;
+ using Microsoft.AspNet.Mvc.Rendering;
+ using System.Threading.Tasks;
+
+ public class ASPV_TestFiles_Input__ViewImports_cshtml : Microsoft.AspNet.Mvc.Razor.RazorPage
+ {
+ #line hidden
+ public ASPV_TestFiles_Input__ViewImports_cshtml()
+ {
+ }
+ #line hidden
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public IHtmlHelper Model { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.IUrlHelper Url { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.Rendering.IJsonHelper Json { get; private set; }
+ [Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
+ public Microsoft.AspNet.Mvc.Rendering.IHtmlHelper Html { get; private set; }
+
+ #line hidden
+
+ #pragma warning disable 1998
+ public override async Task ExecuteAsync()
+ {
+ }
+ #pragma warning restore 1998
+ }
+}