Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fortunes endpoint that returns RazorComponentResult to the Minimal project #2041

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Fortunes</title>
</head>
<body>
<table>
<tr><th>id</th><th>message</th></tr>
@foreach (var item in Rows)
{
<tr><td>@item.Id</td><td>@item.Message</td></tr>
}
</table>
</body>
</html>
@code {
[Parameter]
public required List<Fortune> Rows { get; set; }
}
29 changes: 27 additions & 2 deletions src/BenchmarksApps/TechEmpower/BlazorSSR/Database/Db.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public async Task<List<Fortune>> LoadFortunesRowsDapper()
await using var connection = _dataSource.CreateConnection();
var result = (await connection.QueryAsync<Fortune>($"SELECT id, message FROM fortune")).AsList();

result.Add(new Fortune { Id = 0, Message = "Additional fortune added at request time." });
result.Add(new() { Id = 0, Message = "Additional fortune added at request time." });
result.Sort(FortuneSortComparison);

return result;
Expand All @@ -37,11 +37,36 @@ public async Task<List<Fortune>> LoadFortunesRowsEf(AppDbContext dbContext)
result.Add(fortune);
}

result.Add(new Fortune { Id = 0, Message = "Additional fortune added at request time." });
result.Add(new() { Id = 0, Message = "Additional fortune added at request time." });
result.Sort(FortuneSortComparison);

return result;
}

public Task<List<Fortune>> LoadFortunesRowsNoDb()
{
// Benchmark requirements explicitly prohibit pre-initializing the list size
var result = new List<Fortune>
{
new() { Id = 1, Message = "fortune: No such file or directory" },
new() { Id = 2, Message = "A computer scientist is someone who fixes things that aren't broken." },
new() { Id = 3, Message = "After enough decimal places, nobody gives a damn." },
new() { Id = 4, Message = "A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1" },
new() { Id = 5, Message = "A computer program does what you tell it to do, not what you want it to do." },
new() { Id = 6, Message = "Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen" },
new() { Id = 7, Message = "Any program that runs right is obsolete." },
new() { Id = 8, Message = "A list is only as strong as its weakest link. — Donald Knuth" },
new() { Id = 9, Message = "Feature: A bug with seniority." },
new() { Id = 10, Message = "Computers make very fast, very accurate mistakes." },
new() { Id = 11, Message = "<script>alert(\"This should not be displayed in a browser alert box.\");</script>" },
new() { Id = 12, Message = "フレームワークのベンチマーク" },
new() { Id = 0, Message = "Additional fortune added at request time." }
};

result.Sort(FortuneSortComparison);

return Task.FromResult(result);
}

ValueTask IAsyncDisposable.DisposeAsync() => _dataSource.DisposeAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using BlazorSSR.Components;
using BlazorSSR.Models;

namespace BlazorSSR;

internal readonly struct FortunesRazorParameters(List<Fortune> model) : IReadOnlyDictionary<string, object?>
{
private const string ModelKeyName = nameof(FortunesParameters.Rows);

private readonly KeyValuePair<string, object?> _modelKvp = new(ModelKeyName, model);

public object? this[string key] => KeyIsModel(key) ? model : null;

public IEnumerable<string> Keys { get; } = [ModelKeyName];

public IEnumerable<object?> Values { get; } = [model];

public int Count { get; } = 1;

public bool ContainsKey(string key) => KeyIsModel(key);

public IEnumerator<KeyValuePair<string, object?>> GetEnumerator() => new Enumerator(_modelKvp);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value)
{
if (KeyIsModel(key))
{
value = model;
return true;
}
value = default;
return false;
}

private static bool KeyIsModel(string key) => ModelKeyName.Equals(key, StringComparison.Ordinal);

private struct Enumerator(KeyValuePair<string, object?> kvp) : IEnumerator<KeyValuePair<string, object?>>
{
private bool _moved;

public readonly KeyValuePair<string, object?> Current { get; } = kvp;

readonly object IEnumerator.Current => Current;

public bool MoveNext()
{
if (_moved)
{
return false;
}
_moved = true;
return true;
}

public readonly void Dispose() { }

public void Reset() => throw new NotSupportedException();
}
}
13 changes: 12 additions & 1 deletion src/BenchmarksApps/TechEmpower/BlazorSSR/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
builder.Services.AddRazorComponents();
builder.Services.AddSingleton(serviceProvider =>
{
// TODO: This custom configured HtmlEncoder won't actually be used until Blazor supports it: https://github.com/dotnet/aspnetcore/issues/47477
var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
settings.AllowCharacter('\u2014'); // allow EM DASH through
return HtmlEncoder.Create(settings);
Expand All @@ -40,6 +39,18 @@
app.MapGet("/direct/fortunes", () => new RazorComponentResult<Fortunes>());
app.MapGet("/direct/fortunes-ef", () => new RazorComponentResult<FortunesEf>());

app.MapGet("/direct/fortunes/params", async (HttpContext context, Db db) => {
var fortunes = await db.LoadFortunesRowsDapper();
//var fortunes = await db.LoadFortunesRowsNoDb(); // Don't call the database
var parameters = new Dictionary<string, object?> { { nameof(FortunesParameters.Rows), fortunes } };
//var parameters = new FortunesRazorParameters(fortunes); // Custom parameters class to avoid allocating a Dictionary
var result = new RazorComponentResult<FortunesParameters>(parameters)
{
PreventStreamingRendering = true
};
return result;
});

app.Lifetime.ApplicationStarted.Register(() => Console.WriteLine("Application started. Press Ctrl+C to shut down."));
app.Lifetime.ApplicationStopping.Register(() => Console.WriteLine("Application is shutting down..."));

Expand Down
33 changes: 33 additions & 0 deletions src/BenchmarksApps/TechEmpower/BlazorSSR/blazorssr.benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ scenarios:
presetHeaders: html
path: /fortunes-ef

fortunes-direct:
db:
job: postgresql
application:
job: blazorssr
load:
job: wrk
variables:
presetHeaders: html
path: /direct/fortunes

fortunes-direct-ef:
db:
job: postgresql
application:
job: blazorssr
load:
job: wrk
variables:
presetHeaders: html
path: /direct/fortunes-ef

fortunes-direct-params:
db:
job: postgresql
application:
job: blazorssr
load:
job: wrk
variables:
presetHeaders: html
path: /direct/fortunes/params

profiles:
# this profile uses the local folder as the source
# instead of the public repository
Expand Down
27 changes: 26 additions & 1 deletion src/BenchmarksApps/TechEmpower/Minimal/Database/Db.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Data.Common;
using System.Data.Common;
using Dapper;
using Minimal.Models;

Expand Down Expand Up @@ -99,4 +99,29 @@ public async Task<List<Fortune>> LoadFortunesRows()

return result;
}

public Task<List<Fortune>> LoadFortunesRowsNoDb()
{
// Benchmark requirements explicitly prohibit pre-initializing the list size
var result = new List<Fortune>
{
new(1, "fortune: No such file or directory"),
new(2, "A computer scientist is someone who fixes things that aren't broken."),
new(3, "After enough decimal places, nobody gives a damn."),
new(4, "A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1"),
new(5, "A computer program does what you tell it to do, not what you want it to do."),
new(6, "Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen"),
new(7, "Any program that runs right is obsolete."),
new(8, "A list is only as strong as its weakest link. — Donald Knuth"),
new(9, "Feature: A bug with seniority."),
new(10, "Computers make very fast, very accurate mistakes."),
new(11, "<script>alert(\"This should not be displayed in a browser alert box.\");</script>"),
new(12, "フレームワークのベンチマーク"),
new(0, "Additional fortune added at request time.")
};

result.Sort(FortuneSortComparison);

return Task.FromResult(result);
}
}
9 changes: 4 additions & 5 deletions src/BenchmarksApps/TechEmpower/Minimal/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Microsoft.AspNetCore.Http.HttpResults;
using RazorSlices;
using Minimal;
using Minimal.Database;
using Minimal.Models;
Expand All @@ -23,6 +22,7 @@

// Add services to the container.
builder.Services.AddSingleton(new Db(appSettings));
builder.Services.AddSingleton(CreateHtmlEncoder());

var app = builder.Build();

Expand All @@ -38,10 +38,9 @@

app.MapGet("/db/result", async (Db db) => Results.Json(await db.LoadSingleQueryRow()));

var htmlEncoder = CreateHtmlEncoder();

app.MapGet("/fortunes", async (HttpContext context, Db db) => {
app.MapGet("/fortunes", async (HttpContext context, Db db, HtmlEncoder htmlEncoder) => {
var fortunes = await db.LoadFortunesRows();
//var fortunes = await db.LoadFortunesRowsNoDb(); // Don't call the database
var template = (RazorSliceHttpResult<List<Fortune>>)Fortunes.Create(fortunes);
template.HtmlEncoder = htmlEncoder;
return template;
Expand All @@ -65,4 +64,4 @@ static HtmlEncoder CreateHtmlEncoder()
var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
settings.AllowCharacter('\u2014'); // allow EM DASH through
return HtmlEncoder.Create(settings);
}
}
Loading