Skip to content

Commit ac80de9

Browse files
committed
Add Fortunes endpoint that returns RazorComponentResult
1 parent cf5b6ee commit ac80de9

File tree

6 files changed

+113
-5
lines changed

6 files changed

+113
-5
lines changed

src/BenchmarksApps/TechEmpower/Minimal/Database/Db.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Data.Common;
1+
using System.Data.Common;
22
using Dapper;
33
using Minimal.Models;
44

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

100100
return result;
101101
}
102+
103+
public Task<List<Fortune>> LoadFortunesRowsNoDb()
104+
{
105+
// Benchmark requirements explicitly prohibit pre-initializing the list size
106+
var result = new List<Fortune>
107+
{
108+
new(1, "fortune: No such file or directory"),
109+
new(2, "A computer scientist is someone who fixes things that aren't broken."),
110+
new(3, "After enough decimal places, nobody gives a damn."),
111+
new(4, "A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1"),
112+
new(5, "A computer program does what you tell it to do, not what you want it to do."),
113+
new(6, "Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen"),
114+
new(7, "Any program that runs right is obsolete."),
115+
new(8, "A list is only as strong as its weakest link. — Donald Knuth"),
116+
new(9, "Feature: A bug with seniority."),
117+
new(10, "Computers make very fast, very accurate mistakes."),
118+
new(11, "<script>alert(\"This should not be displayed in a browser alert box.\");</script>"),
119+
new(12, "フレームワークのベンチマーク"),
120+
new(0, "Additional fortune added at request time.")
121+
};
122+
123+
result.Sort(FortuneSortComparison);
124+
125+
return Task.FromResult(result);
126+
}
102127
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Collections;
2+
using System.Diagnostics.CodeAnalysis;
3+
using Minimal.Models;
4+
using Minimal.Templates;
5+
6+
namespace Minimal;
7+
8+
internal readonly struct FortunesRazorParameters(List<Fortune> model) : IReadOnlyDictionary<string, object?>
9+
{
10+
private const string ModelKeyName = nameof(FortunesRazor.Model);
11+
12+
private readonly KeyValuePair<string, object?> _modelKvp = new(ModelKeyName, model);
13+
14+
public object? this[string key] => KeyIsModel(key) ? model : null;
15+
16+
public IEnumerable<string> Keys { get; } = [ModelKeyName];
17+
18+
public IEnumerable<object?> Values { get; } = [model];
19+
20+
public int Count { get; } = 1;
21+
22+
public bool ContainsKey(string key) => KeyIsModel(key);
23+
24+
public IEnumerator<KeyValuePair<string, object?>> GetEnumerator() => new Enumerator(_modelKvp);
25+
26+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
27+
28+
public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value)
29+
{
30+
if (KeyIsModel(key))
31+
{
32+
value = model;
33+
return true;
34+
}
35+
value = default;
36+
return false;
37+
}
38+
39+
private static bool KeyIsModel(string key) => ModelKeyName.Equals(key, StringComparison.Ordinal);
40+
41+
private struct Enumerator(KeyValuePair<string, object?> kvp) : IEnumerator<KeyValuePair<string, object?>>
42+
{
43+
private bool _moved;
44+
45+
public readonly KeyValuePair<string, object?> Current { get; } = kvp;
46+
47+
readonly object IEnumerator.Current => Current;
48+
49+
public bool MoveNext()
50+
{
51+
if (_moved)
52+
{
53+
return false;
54+
}
55+
_moved = true;
56+
return true;
57+
}
58+
59+
public readonly void Dispose() { }
60+
61+
public void Reset() => throw new NotSupportedException();
62+
}
63+
}

src/BenchmarksApps/TechEmpower/Minimal/Program.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Text.Encodings.Web;
22
using System.Text.Unicode;
33
using Microsoft.AspNetCore.Http.HttpResults;
4-
using RazorSlices;
54
using Minimal;
65
using Minimal.Database;
76
using Minimal.Models;
@@ -23,6 +22,7 @@
2322

2423
// Add services to the container.
2524
builder.Services.AddSingleton(new Db(appSettings));
25+
builder.Services.AddRazorComponents();
2626

2727
var app = builder.Build();
2828

@@ -42,11 +42,24 @@
4242

4343
app.MapGet("/fortunes", async (HttpContext context, Db db) => {
4444
var fortunes = await db.LoadFortunesRows();
45+
//var fortunes = await db.LoadFortunesRowsNoDb(); // Don't call the database
4546
var template = (RazorSliceHttpResult<List<Fortune>>)Fortunes.Create(fortunes);
4647
template.HtmlEncoder = htmlEncoder;
4748
return template;
4849
});
4950

51+
app.MapGet("/fortunes/razor", async (HttpContext context, Db db) => {
52+
var fortunes = await db.LoadFortunesRows();
53+
//var fortunes = await db.LoadFortunesRowsNoDb(); // Don't call the database
54+
var parameters = new Dictionary<string, object?> { { nameof(FortunesRazor.Model), fortunes } };
55+
//var parameters = new FortunesRazorParameters(fortunes); // Custom parameters class to avoid allocating a Dictionary
56+
var result = new RazorComponentResult<FortunesRazor>(parameters)
57+
{
58+
PreventStreamingRendering = true
59+
};
60+
return result;
61+
});
62+
5063
app.MapGet("/queries/{count}", async (Db db, int count) => await db.LoadMultipleQueriesRows(count));
5164

5265
app.MapGet("/queries/{count}/result", async (Db db, int count) => Results.Json(await db.LoadMultipleQueriesRows(count)));
@@ -65,4 +78,4 @@ static HtmlEncoder CreateHtmlEncoder()
6578
var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
6679
settings.AllowCharacter('\u2014'); // allow EM DASH through
6780
return HtmlEncoder.Create(settings);
68-
}
81+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>@foreach (var item in Model){<tr><td>@(new MarkupString(item.Id.ToString(CultureInfo.InvariantCulture)))</td><td>@item.Message</td></tr>}</table></body></html>
2+
@code {
3+
[Parameter]
4+
public required List<Fortune> Model { get; set; }
5+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@using System.Globalization;
2+
@using Minimal.Models;

src/BenchmarksApps/TechEmpower/Minimal/minimal.benchmarks.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ scenarios:
7878
presetHeaders: html
7979
path: /fortunes
8080

81-
fortunes_result:
81+
fortunes_razor:
8282
db:
8383
job: postgresql
8484
application:
@@ -87,7 +87,7 @@ scenarios:
8787
job: wrk
8888
variables:
8989
presetHeaders: html
90-
path: /fortunes/result
90+
path: /fortunes/razor
9191

9292
single_query:
9393
db:

0 commit comments

Comments
 (0)