Skip to content

Commit b121a2f

Browse files
Influence HTML head from Blazor (#23833)
* Started on head manager * Working prototype. * Started on improved meta tag support. * Improved meta support and better thread safety. * Improved synchronization. * Added support for meta "property" attribute. * Updated exception message. * Added link element support. * Started on functional tests. * Added more functional tests. * Added E2E tests. * Simplified implementation. * Prerendering support. * Small documentation updates. * Made TagElement and TitleElement readonly. * Removed M.A.Components.Server dependency. * Minor fixes and updates. * Update PrerenderedHeadComponent.razor * Removed AddWebExtensions. * Applied CR feedback
1 parent 4813a15 commit b121a2f

23 files changed

+784
-8
lines changed

AspNetCore.sln

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon
14271427
EndProject
14281428
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Web.Extensions.Tests", "src\Components\Web.Extensions\test\Microsoft.AspNetCore.Components.Web.Extensions.Tests.csproj", "{157605CB-5170-4C1A-980F-4BAE42DB60DE}"
14291429
EndProject
1430+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{2531F00A-54EB-4074-9C0B-9AF9FB3679DC}"
1431+
EndProject
1432+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTestApp", "src\Components\test\testassets\BasicTestApp\BasicTestApp.csproj", "{85D67E40-4B11-48ED-8C43-34590A1FB9ED}"
1433+
EndProject
1434+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazyTestContentPackage", "src\Components\test\testassets\LazyTestContentPackage\LazyTestContentPackage.csproj", "{C0EF53A5-5A94-4849-86B0-2297EA08D649}"
1435+
EndProject
1436+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentsApp.App", "src\Components\test\testassets\ComponentsApp.App\ComponentsApp.App.csproj", "{4FDD820F-8397-41B7-956E-F257DD044BD8}"
1437+
EndProject
1438+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComponentsApp.Server", "src\Components\test\testassets\ComponentsApp.Server\ComponentsApp.Server.csproj", "{CA7C7A53-446F-453A-A57B-78BB1443B8A8}"
1439+
EndProject
1440+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestContentPackage", "src\Components\test\testassets\TestContentPackage\TestContentPackage.csproj", "{B32C5882-2313-40D0-A003-2FF33724CFE6}"
1441+
EndProject
1442+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.TestServer", "src\Components\test\testassets\TestServer\Components.TestServer.csproj", "{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}"
1443+
EndProject
14301444
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}"
14311445
EndProject
14321446
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}"
@@ -6739,6 +6753,78 @@ Global
67396753
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x64.Build.0 = Release|Any CPU
67406754
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.ActiveCfg = Release|Any CPU
67416755
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.Build.0 = Release|Any CPU
6756+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6757+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
6758+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|x64.ActiveCfg = Debug|Any CPU
6759+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|x64.Build.0 = Debug|Any CPU
6760+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|x86.ActiveCfg = Debug|Any CPU
6761+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Debug|x86.Build.0 = Debug|Any CPU
6762+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
6763+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|Any CPU.Build.0 = Release|Any CPU
6764+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|x64.ActiveCfg = Release|Any CPU
6765+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|x64.Build.0 = Release|Any CPU
6766+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|x86.ActiveCfg = Release|Any CPU
6767+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED}.Release|x86.Build.0 = Release|Any CPU
6768+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6769+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|Any CPU.Build.0 = Debug|Any CPU
6770+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|x64.ActiveCfg = Debug|Any CPU
6771+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|x64.Build.0 = Debug|Any CPU
6772+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|x86.ActiveCfg = Debug|Any CPU
6773+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Debug|x86.Build.0 = Debug|Any CPU
6774+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|Any CPU.ActiveCfg = Release|Any CPU
6775+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|Any CPU.Build.0 = Release|Any CPU
6776+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|x64.ActiveCfg = Release|Any CPU
6777+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|x64.Build.0 = Release|Any CPU
6778+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|x86.ActiveCfg = Release|Any CPU
6779+
{C0EF53A5-5A94-4849-86B0-2297EA08D649}.Release|x86.Build.0 = Release|Any CPU
6780+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6781+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
6782+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|x64.ActiveCfg = Debug|Any CPU
6783+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|x64.Build.0 = Debug|Any CPU
6784+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|x86.ActiveCfg = Debug|Any CPU
6785+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Debug|x86.Build.0 = Debug|Any CPU
6786+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
6787+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|Any CPU.Build.0 = Release|Any CPU
6788+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|x64.ActiveCfg = Release|Any CPU
6789+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|x64.Build.0 = Release|Any CPU
6790+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|x86.ActiveCfg = Release|Any CPU
6791+
{4FDD820F-8397-41B7-956E-F257DD044BD8}.Release|x86.Build.0 = Release|Any CPU
6792+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6793+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
6794+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|x64.ActiveCfg = Debug|Any CPU
6795+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|x64.Build.0 = Debug|Any CPU
6796+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|x86.ActiveCfg = Debug|Any CPU
6797+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Debug|x86.Build.0 = Debug|Any CPU
6798+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
6799+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|Any CPU.Build.0 = Release|Any CPU
6800+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|x64.ActiveCfg = Release|Any CPU
6801+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|x64.Build.0 = Release|Any CPU
6802+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|x86.ActiveCfg = Release|Any CPU
6803+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8}.Release|x86.Build.0 = Release|Any CPU
6804+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6805+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
6806+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|x64.ActiveCfg = Debug|Any CPU
6807+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|x64.Build.0 = Debug|Any CPU
6808+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|x86.ActiveCfg = Debug|Any CPU
6809+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Debug|x86.Build.0 = Debug|Any CPU
6810+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
6811+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|Any CPU.Build.0 = Release|Any CPU
6812+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|x64.ActiveCfg = Release|Any CPU
6813+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|x64.Build.0 = Release|Any CPU
6814+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|x86.ActiveCfg = Release|Any CPU
6815+
{B32C5882-2313-40D0-A003-2FF33724CFE6}.Release|x86.Build.0 = Release|Any CPU
6816+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6817+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|Any CPU.Build.0 = Debug|Any CPU
6818+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|x64.ActiveCfg = Debug|Any CPU
6819+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|x64.Build.0 = Debug|Any CPU
6820+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|x86.ActiveCfg = Debug|Any CPU
6821+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Debug|x86.Build.0 = Debug|Any CPU
6822+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|Any CPU.ActiveCfg = Release|Any CPU
6823+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|Any CPU.Build.0 = Release|Any CPU
6824+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|x64.ActiveCfg = Release|Any CPU
6825+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|x64.Build.0 = Release|Any CPU
6826+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|x86.ActiveCfg = Release|Any CPU
6827+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00}.Release|x86.Build.0 = Release|Any CPU
67426828
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67436829
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|Any CPU.Build.0 = Debug|Any CPU
67446830
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -7502,6 +7588,13 @@ Global
75027588
{F71FE795-9923-461B-9809-BB1821A276D0} = {60D51C98-2CC0-40DF-B338-44154EFEE2FF}
75037589
{8294A74F-7DAA-4B69-BC56-7634D93C9693} = {F71FE795-9923-461B-9809-BB1821A276D0}
75047590
{157605CB-5170-4C1A-980F-4BAE42DB60DE} = {F71FE795-9923-461B-9809-BB1821A276D0}
7591+
{2531F00A-54EB-4074-9C0B-9AF9FB3679DC} = {0508E463-0269-40C9-B5C2-3B600FB2A28B}
7592+
{85D67E40-4B11-48ED-8C43-34590A1FB9ED} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
7593+
{C0EF53A5-5A94-4849-86B0-2297EA08D649} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
7594+
{4FDD820F-8397-41B7-956E-F257DD044BD8} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
7595+
{CA7C7A53-446F-453A-A57B-78BB1443B8A8} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
7596+
{B32C5882-2313-40D0-A003-2FF33724CFE6} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
7597+
{26F88A06-319C-43F3-9FD9-8BC2D29F8C00} = {2531F00A-54EB-4074-9C0B-9AF9FB3679DC}
75057598
{FED4267E-E5E4-49C5-98DB-8B3F203596EE} = {562D5067-8CD8-4F19-BCBB-873204932C61}
75067599
{6B2734BF-C61D-4889-ABBF-456A4075D59B} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
75077600
{83371889-9A3E-4D16-AE77-EB4F83BC6374} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
using Microsoft.JSInterop;
6+
7+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
8+
{
9+
internal static class HeadManagementJSRuntimeExtensions
10+
{
11+
private const string JsFunctionsPrefix = "_blazorHeadManager";
12+
13+
public static ValueTask SetTitleAsync(this IJSRuntime jsRuntime, string title)
14+
{
15+
return jsRuntime.InvokeVoidAsync($"{JsFunctionsPrefix}.setTitle", title);
16+
}
17+
18+
public static ValueTask AddOrUpdateHeadTagAsync(this IJSRuntime jsRuntime, TagElement tag, string id)
19+
{
20+
return jsRuntime.InvokeVoidAsync($"{JsFunctionsPrefix}.addOrUpdateHeadTag", tag, id);
21+
}
22+
23+
public static ValueTask RemoveHeadTagAsync(this IJSRuntime jsRuntime, string id)
24+
{
25+
return jsRuntime.InvokeVoidAsync($"{JsFunctionsPrefix}.removeHeadTag", id);
26+
}
27+
}
28+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text.Json;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Components.Rendering;
9+
using Microsoft.JSInterop;
10+
11+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
12+
{
13+
/// <summary>
14+
/// Serves as a base for components that represent tags in the HTML head.
15+
/// </summary>
16+
public abstract class HeadTagBase : ComponentBase, IDisposable
17+
{
18+
private readonly string _id = Guid.NewGuid().ToString("N");
19+
20+
private TagElement _tagElement;
21+
22+
private bool _hasRendered;
23+
24+
[Inject]
25+
private IJSRuntime JSRuntime { get; set; } = default!;
26+
27+
/// <summary>
28+
/// Gets or sets a collection of additional attributes that will be applied to the meta element.
29+
/// </summary>
30+
[Parameter(CaptureUnmatchedValues = true)]
31+
public IReadOnlyDictionary<string, object>? Attributes { get; set; }
32+
33+
/// <summary>
34+
/// Gets the name of the tag being represented.
35+
/// </summary>
36+
protected abstract string TagName { get; }
37+
38+
/// <inheritdoc />
39+
protected override void OnParametersSet()
40+
{
41+
_tagElement = new TagElement(TagName, Attributes);
42+
}
43+
44+
/// <inheritdoc />
45+
protected override async Task OnAfterRenderAsync(bool firstRender)
46+
{
47+
_hasRendered = true;
48+
49+
await JSRuntime.AddOrUpdateHeadTagAsync(_tagElement, _id);
50+
}
51+
52+
/// <inheritdoc />
53+
protected override void BuildRenderTree(RenderTreeBuilder builder)
54+
{
55+
builder.AddMarkupContent(0, $"<!--Head:{JsonSerializer.Serialize(_tagElement, JsonSerializerOptionsProvider.Options)}-->");
56+
}
57+
58+
/// <inheritdoc />
59+
public void Dispose()
60+
{
61+
if (_hasRendered)
62+
{
63+
_ = JSRuntime.RemoveHeadTagAsync(_id);
64+
}
65+
}
66+
}
67+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
5+
{
6+
/// <summary>
7+
/// A component that adds a link tag to the HTML head.
8+
/// </summary>
9+
public sealed class Link : HeadTagBase
10+
{
11+
/// <inheritdoc />
12+
protected override string TagName => "link";
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
5+
{
6+
/// <summary>
7+
/// A component that adds a meta tag to the HTML head.
8+
/// </summary>
9+
public sealed class Meta : HeadTagBase
10+
{
11+
/// <inheritdoc />
12+
protected override string TagName => "meta";
13+
}
14+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
6+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
7+
{
8+
internal readonly struct TagElement
9+
{
10+
public string Type => "tag";
11+
12+
public string TagName { get; }
13+
14+
public IReadOnlyDictionary<string, object>? Attributes { get; }
15+
16+
public TagElement(string tagName, IReadOnlyDictionary<string, object>? attributes)
17+
{
18+
TagName = tagName;
19+
Attributes = attributes;
20+
}
21+
}
22+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Text.Json;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Components.Rendering;
7+
using Microsoft.JSInterop;
8+
9+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
10+
{
11+
/// <summary>
12+
/// A component that changes the title of the document.
13+
/// </summary>
14+
public sealed class Title : ComponentBase
15+
{
16+
[Inject]
17+
private IJSRuntime JSRuntime { get; set; } = default!;
18+
19+
/// <summary>
20+
/// Gets or sets the value to use as the document's title.
21+
/// </summary>
22+
[Parameter]
23+
public string Value { get; set; } = string.Empty;
24+
25+
/// <inheritdoc />
26+
protected override async Task OnAfterRenderAsync(bool firstRender)
27+
{
28+
await JSRuntime.SetTitleAsync(Value);
29+
}
30+
31+
/// <inheritdoc />
32+
protected override void BuildRenderTree(RenderTreeBuilder builder)
33+
{
34+
builder.AddMarkupContent(0, $"<!--Head:{JsonSerializer.Serialize(new TitleElement(Value), JsonSerializerOptionsProvider.Options)}-->");
35+
}
36+
}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Components.Web.Extensions.Head
5+
{
6+
internal readonly struct TitleElement
7+
{
8+
public string Type => "title";
9+
10+
public string Title { get; }
11+
12+
public TitleElement(string title)
13+
{
14+
Title = title;
15+
}
16+
}
17+
}

src/Components/Web.Extensions/src/Microsoft.AspNetCore.Components.Web.Extensions.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
44
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
@@ -9,6 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12+
<Reference Include="Microsoft.AspNetCore.Components" />
1213
<Reference Include="Microsoft.AspNetCore.DataProtection" />
1314
<Reference Include="Microsoft.JSInterop" />
1415
</ItemGroup>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using System.Runtime.CompilerServices;
2+
3+
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Web.Extensions.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

0 commit comments

Comments
 (0)