Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into features/cohost
Browse files Browse the repository at this point in the history
  • Loading branch information
davidwengier committed Jan 26, 2024
2 parents 5335952 + 8e5fbd4 commit 5c5b3e6
Show file tree
Hide file tree
Showing 84 changed files with 1,363 additions and 1,240 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ csharp_style_unused_value_expression_statement_preference = discard_variable:non
# IDE0065
csharp_using_directive_placement = outside_namespace:suggestion

# Roslyn analyzers
dotnet_diagnostic.RS0006.severity = error
dotnet_diagnostic.RS0023.severity = error

# xUnit1004: Test methods should not be skipped
dotnet_diagnostic.xUnit1004.severity = refactoring

Expand Down
50 changes: 50 additions & 0 deletions docs/Onboarding Docs/01_Razor_Basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Razor Basics

Razor is a templating language used in ASP.NET for creating dynamic web pages. It's not a programming language itself, but a markup syntax for embedding code (C# or VB.NET) into HTML.

In a Razor file, you can use a combination of several languages:

| Language | Usage | Supported in .NET Core and .NET 5+ |
| --- | --- | --- |
| **Razor syntax** | Used to embed and execute server-side code within HTML. | Yes |
| **C#** | The server-side language used within Razor templates. Most commonly used with Razor. | Yes |
| **HTML** | Used to structure the content on web pages. | Yes |
| **JavaScript** | Used for client-side scripting in Razor templates. | Yes |
| **CSS** | Used for styling web pages. | Yes |
| **VB.NET** | Can be used in Razor syntax in the older .NET Framework. | No |

Please note that while Razor syntax does support VB.NET in the older .NET Framework, VB.NET is not supported in .NET Core or .NET 5 and onwards. In these newer frameworks, only C# is supported.

## Razor File Types

Razor files typically come in three extensions: `.cshtml`, `.vbhtml`, and `.razor`. Each extension corresponds to a specific type of Razor file and determines its usage within an application:

| File Extension | Type | Description | Usage |
| --- | --- | --- | --- |
| `.cshtml` | Razor View | Part of the MVC (Model-View-Controller) pattern, where the View is responsible for the presentation logic. Located within the Views folder of an MVC application and associated with a Controller. | Used in MVC applications for complex scenarios where separation of concerns is important. |
| `.cshtml` | Razor Page | A page-based programming model that makes building web UI easier and more productive. Located within the Pages folder of a Razor Pages application and includes a `@page` directive at the top. | Used in Razor Pages applications for simpler scenarios where a full MVC model might be overkill. |
| `.razor` | Razor Component (Blazor) | Used in Blazor, a framework for building interactive client-side web UI with .NET. Each `.razor` file is a self-contained component that can include both the markup and the processing logic. | Used in Blazor applications for building interactive client-side web UIs. |
| `.vbhtml` | Razor View (VB.NET) | Part of the MVC (Model-View-Controller) pattern, where the View is responsible for the presentation logic. Located within the Views folder of an MVC application and associated with a Controller. | Used in older MVC applications written in VB.NET. |

## Razor Editors: Legacy vs New

| Aspect | Razor Legacy | Legacy .NET Core Razor Editor | New .NET Core Razor Editor |
| --- | --- | --- | --- |
| **Introduction** | Introduced with ASP.NET MVC 3. | Older Razor editor for ASP.NET Core projects. | Updated Razor editor introduced in Visual Studio 2019 version 16.8. |
| **Usage** | Used in ASP.NET MVC and ASP.NET Web Pages applications. | Used for editing Razor views and pages in ASP.NET Core projects. | Used for editing Razor views and pages in ASP.NET Core projects. |
| **Source code** | Closed source. | Closed source. | [Open source on GitHub](https://github.com/dotnet/razor/) |
| **File Extensions** | `.cshtml` for C#, `.vbhtml` for VB.NET. | `.cshtml` and `.razor` | `.cshtml` and `.razor` |
| **Functionality** | Creates dynamic web pages that combine HTML and server-side code. | Provides basic features like syntax highlighting and IntelliSense for Razor syntax. | Provides improved functionality and performance, including better IntelliSense, improved syntax highlighting, support for Razor formatting, better diagnostics, and features like "Go to Definition" and "Find All References" for Razor components and their parameters. |
| **Support** | Supported for maintaining existing applications. | Phased out, not recommended for new projects. | Actively supported and recommended for new projects. |
| **Configuration** | Used by default for .NET Framework applications. | The legacy .NET Core editor is off by default. | The new .NET Core editor is used by default. |
| **Implementation** | Monolithic design, language services implemented by the editor, no LSP or TextMate grammars, limited VS integration. | Same as Razor Legacy | Uses LSP for language services, TextMate grammars for syntax highlighting, integrated with VS editor API, includes Blazor support. |

## Razor Support Across ASP.NET Versions

Different versions of ASP.NET support different features of Razor. Here's a summary:

| TFM | Razor Support |
| --- | --- |
| **.NET Framework (<= 4.8)** | Supports Razor syntax with C# and VB.NET. Used in ASP.NET MVC and ASP.NET Web Pages applications. |
| **.NET Core 1.x - 3.1** | Supports Razor syntax with C# only. Used in ASP.NET Core MVC, Razor Pages applications, and had preview support for Blazor. |
| **.NET 5+** | Supports Razor syntax with C# only. Used in ASP.NET Core MVC, Razor Pages, and Blazor applications. |
4 changes: 2 additions & 2 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>3a25a7f1cc446b60678ed25c9d829420d6321eba</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24060.4">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24074.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>888985fb9a9ae4cb30bca75f98af9126c839e660</Sha>
<Sha>96c2cee493aa1542c0b06a6498e0379eb11e005f</Sha>
<SourceBuild RepoName="arcade" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.DotNet.XliffTasks" Version="1.0.0-beta.23475.1" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
"rollForward": "latestPatch"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24060.4"
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24074.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Components;

internal class ComponentMarkupEncodingPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass
{
private readonly RazorLanguageVersion _version;

public ComponentMarkupEncodingPass(RazorLanguageVersion version)
{
_version = version;
}

// Runs after ComponentMarkupBlockPass
public override int Order => ComponentMarkupDiagnosticPass.DefaultOrder + 20;

Expand All @@ -29,7 +36,7 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentInte
return;
}

var rewriter = new Rewriter();
var rewriter = new Rewriter(_version);
rewriter.Visit(documentNode);
}

Expand All @@ -47,10 +54,37 @@ private class Rewriter : IntermediateNodeWalker

private static readonly char[] EncodedCharacters = new[] { '\r', '\n', '\t', '<', '>' };

private readonly bool _avoidEncodingScripts;
private readonly Dictionary<string, string> _seenEntities = new Dictionary<string, string>(StringComparer.Ordinal);

private bool _avoidEncodingContent;

public Rewriter(RazorLanguageVersion version)
{
_avoidEncodingScripts = version.CompareTo(RazorLanguageVersion.Version_8_0) >= 0;
}

public override void VisitMarkupElement(MarkupElementIntermediateNode node)
{
// We don't want to HTML-encode literal content inside <script> tags.
var oldAvoidEncodingContent = _avoidEncodingContent;
_avoidEncodingContent = _avoidEncodingContent || (
_avoidEncodingScripts &&
string.Equals("script", node.TagName, StringComparison.OrdinalIgnoreCase));

base.VisitMarkupElement(node);

_avoidEncodingContent = oldAvoidEncodingContent;
}

public override void VisitHtml(HtmlContentIntermediateNode node)
{
if (_avoidEncodingContent)
{
node.SetEncoded();
return;
}

for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ private static void AddComponentFeatures(RazorProjectEngineBuilder builder, Razo
builder.Features.Add(new ComponentChildContentDiagnosticPass());
builder.Features.Add(new ComponentMarkupDiagnosticPass());
builder.Features.Add(new ComponentMarkupBlockPass(razorLanguageVersion));
builder.Features.Add(new ComponentMarkupEncodingPass());
builder.Features.Add(new ComponentMarkupEncodingPass(razorLanguageVersion));
}

private static void LoadExtensions(RazorProjectEngineBuilder builder, IReadOnlyList<RazorExtension> extensions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ComponentMarkupEncodingPassTest
{
public ComponentMarkupEncodingPassTest()
{
Pass = new ComponentMarkupEncodingPass();
Pass = new ComponentMarkupEncodingPass(RazorLanguageVersion.Latest);
ProjectEngine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create(Environment.CurrentDirectory),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,57 @@ public async Task ScriptTag()
await VerifyRazorPageMatchesBaselineAsync(compilation, "Views_Home_Index");
}

[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/aspnetcore/issues/52547")]
public async Task ScriptTag_WithVariable([CombinatorialValues("7.0", "8.0", "Latest")] string razorLangVersion)
{
// Arrange
var code = """
@{ var msg = "What's up"; }
<script>console.log('@msg');</script>
<div>console.log('@msg');</div>
<script>console.log('No variable');</script>
<div>console.log('No variable');</div>
<script>
console.log('@msg');
</script>
<div>
console.log('@msg');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>
""";
var project = CreateTestProject(new()
{
["Views/Home/Index.cshtml"] = $"""
{code}
@(await Html.RenderComponentAsync<MyApp.Shared.Component1>(RenderMode.Static))
""",
["Shared/Component1.razor"] = $"""
Component:
{code}
""",
});
var compilation = await project.GetCompilationAsync();
var driver = await GetDriverAsync(project, options =>
{
options.TestGlobalOptions["build_property.RazorLangVersion"] = razorLangVersion;
});

// Act
var result = RunGenerator(compilation!, ref driver, out compilation);

// Assert
result.Diagnostics.Verify();
Assert.Equal(2, result.GeneratedSources.Length);
var suffix = razorLangVersion == "7.0" ? "7" : "8";
result.VerifyOutputsMatchBaseline(suffix: suffix);
await VerifyRazorPageMatchesBaselineAsync(compilation, "Views_Home_Index", suffix: suffix);
}

[Fact, WorkItem("https://github.com/dotnet/razor/issues/9051")]
public async Task LineMapping()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,16 @@ static IEnumerable<string> GetViewStartNames(string name)
}

protected static async Task VerifyRazorPageMatchesBaselineAsync(Compilation compilation, string name,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
var html = await RenderRazorPageAsync(compilation, name);
Extensions.VerifyTextMatchesBaseline(
actualText: html,
fileName: name,
extension: "html",
testPath: testPath,
testName: testName);
testName: testName,
suffix: suffix);
}

protected static Project CreateTestProject(
Expand Down Expand Up @@ -420,21 +421,22 @@ public static GeneratorRunResult VerifyPageOutput(this GeneratorRunResult result
return result;
}

private static string CreateBaselineDirectory(string testPath, string testName)
private static string CreateBaselineDirectory(string testPath, string testName, string suffix)
{
var baselineDirectory = Path.Join(
_testProjectRoot,
"TestFiles",
Path.GetFileNameWithoutExtension(testPath)!,
testName);
testName,
suffix);
Directory.CreateDirectory(baselineDirectory);
return baselineDirectory;
}

public static GeneratorRunResult VerifyOutputsMatchBaseline(this GeneratorRunResult result,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
var baselineDirectory = CreateBaselineDirectory(testPath, testName);
var baselineDirectory = CreateBaselineDirectory(testPath, testName, suffix);
var touchedFiles = new HashSet<string>();

foreach (var source in result.GeneratedSources)
Expand All @@ -453,10 +455,10 @@ public static GeneratorRunResult VerifyOutputsMatchBaseline(this GeneratorRunRes
}

public static void VerifyTextMatchesBaseline(string actualText, string fileName, string extension,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
// Create output directory.
var baselineDirectory = CreateBaselineDirectory(testPath, testName);
var baselineDirectory = CreateBaselineDirectory(testPath, testName, suffix);

// Generate baseline if enabled.
var baselinePath = Path.Join(baselineDirectory, $"{fileName}.{extension}");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#pragma checksum "Shared/Component1.razor" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b72b3eb93cc4a906714929a4849d9f7aac2ef62a"
// <auto-generated/>
#pragma warning disable 1591
namespace MyApp.Shared
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class Component1 : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.AddMarkupContent(0, "Component:\r\n");
#nullable restore
#line 2 "Shared/Component1.razor"
var msg = "What's up";

#line default
#line hidden
#nullable disable
__builder.OpenElement(1, "script");
__builder.AddContent(2, "console.log(\'");
#nullable restore
#line (3,23)-(3,26) 24 "Shared/Component1.razor"
__builder.AddContent(3, msg);

#line default
#line hidden
#nullable disable
__builder.AddContent(4, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(5, "\r\n");
__builder.OpenElement(6, "div");
__builder.AddContent(7, "console.log(\'");
#nullable restore
#line (4,20)-(4,23) 24 "Shared/Component1.razor"
__builder.AddContent(8, msg);

#line default
#line hidden
#nullable disable
__builder.AddContent(9, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(10, "\r\n");
__builder.OpenElement(11, "script");
__builder.AddContent(12, "console.log(\'No variable\');");
__builder.CloseElement();
__builder.AddMarkupContent(13, "\r\n");
__builder.AddMarkupContent(14, "<div>console.log(\'No variable\');</div>\r\n");
__builder.OpenElement(15, "script");
__builder.AddMarkupContent(16, "\r\n console.log(\'");
#nullable restore
#line (8,19)-(8,22) 25 "Shared/Component1.razor"
__builder.AddContent(17, msg);

#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(18, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(19, "\r\n");
__builder.OpenElement(20, "div");
__builder.AddMarkupContent(21, "\r\n console.log(\'");
#nullable restore
#line (11,19)-(11,22) 25 "Shared/Component1.razor"
__builder.AddContent(22, msg);

#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(23, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(24, "\r\n");
__builder.OpenElement(25, "script");
__builder.AddMarkupContent(26, "\r\n console.log(\'No variable\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(27, "\r\n");
__builder.AddMarkupContent(28, "<div>\r\n console.log(\'No variable\');\r\n</div>");
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591
Loading

0 comments on commit 5c5b3e6

Please sign in to comment.