TModel substitution in Razor pages has broken intellisense

Fixes #3185
This commit is contained in:
Pranav K 2015-09-23 16:11:41 -07:00
parent ff4100e292
commit 1833e06984
8 changed files with 136 additions and 5 deletions

View File

@ -16,7 +16,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
/// 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>";
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
@ -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);
}
}
}

View File

@ -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)

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.Razor
new SetBaseTypeChunk
{
// Microsoft.Aspnet.Mvc.Razor.RazorPage<TModel>
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;

View File

@ -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";
/// <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.

View File

@ -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()
{

View File

@ -0,0 +1 @@
@inject IHtmlHelper<TModel> Model

View File

@ -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<dynamic>
{
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<dynamic> 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<dynamic> Html { get; private set; }
#line hidden
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
}
#pragma warning restore 1998
}
}

View File

@ -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<dynamic>
{
#line hidden
public ASPV_TestFiles_Input__ViewImports_cshtml()
{
}
#line hidden
[Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
public IHtmlHelper<dynamic> 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<dynamic> Html { get; private set; }
#line hidden
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
}
#pragma warning restore 1998
}
}