Skip to content

@functions block emitted inside ExecuteAsync (instead of as class members) when .cshtml contains UTF-8 string literals #12777

@DamianEdwards

Description

@DamianEdwards

Description

When a .cshtml file contains supplementary Unicode characters (codepoints above U+FFFF, encoded as 4-byte UTF-8 sequences) in its HTML literal content — such as emoji or variation selectors — the .NET 10 Razor compiler incorrectly emits the @functions block content inside the ExecuteAsync method body instead of as class-level members.

This is a regression from .NET 8/9 where the same file compiles correctly with @functions content placed as class members.

Steps to Reproduce

  1. Create a .cshtml file with emoji characters in HTML literals and a @functions block:
<p>
    <span>😁</span>
    <span>💩</span>
    <span>🐻</span>
    <span>🐳</span>
    <span>❤️</span>
    <span>🌶️</span>
    <span>😶‍🌫️</span>
    <span>👾</span>
    <span>🫨</span>
</p>

@functions {
    static string Title = "Unicode";
    public string SomeProperty => Title;
}
  1. Build targeting net10.0

Expected Behavior

The @functions block should be emitted as class-level members, just as it is in .NET 8 and .NET 9.

.NET 8/9 generated code (correct — @functions content after ExecuteAsync closes):

        }
        #pragma warning restore 1998
#nullable restore
#line (60,13)-(71,1) "Unicode.cshtml"

    static string Title = "Unicode";
    public string SomeProperty => Title;

#line default
#line hidden
#nullable disable

Actual Behavior

The @functions block content is emitted inside the ExecuteAsync method body, causing compilation errors (static not valid, properties not valid inside method, etc.):

.NET 10 generated code (broken — @functions content before ExecuteAsync closes):

            WriteLiteral("</span>\r\n</p>\r\n\r\n");
#nullable restore
#line (60,13)-(71,1) "Unicode.cshtml"

    static string Title = "Unicode";
    public string SomeProperty => Title;

#line default
#line hidden
#nullable disable

        }
        #pragma warning restore 1998

This produces errors like:

  • CS0106: The modifier 'static' is not valid for this item
  • CS0841: Cannot use local variable before it is declared
  • CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

Key Observations

  • Only affects files with supplementary Unicode characters (codepoints > U+FFFF, i.e., 4-byte UTF-8 sequences like emoji F0 9F xx xx or variation selectors F3 A0 xx xx)
  • Other .cshtml files in the same project with @functions blocks but without supplementary Unicode characters compile correctly in .NET 10
  • The same file compiles correctly in .NET 8 and .NET 9
  • The Razor compiler appears to recognize @functions (the line mapping (60,13)-(71,1) is identical across versions) but places the content in the wrong location

Workaround

Move code from @functions into a separate .cs helper class and reference it from the .cshtml file. Replace supplementary Unicode character literals in HTML with HTML character references (e.g., &#xE0100; instead of the raw U+E0100 character).

Environment

  • .NET SDK: 10.0.200-preview.0.26103.119
  • Runtime: 10.0.3
  • OS: Windows 11 (10.0.26200)
  • Works correctly on: .NET SDK 8.0.418 and 9.0.x

Related

Discovered and worked around in DamianEdwards/RazorSlices@28fecc0

Metadata

Metadata

Assignees

Labels

area-compilerUmbrella for all compiler issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions