将中间件的值注入 Razor 页面 HTML 正文
Inject value from middleware into Razor Page HTML body
我有一个计算 Razor 页面执行时间的中间件:
app.Use(async (context, next) =>
{
var sw = new Stopwatch();
sw.Start();
await next.Invoke();
sw.Stop();
await context.Response.WriteAsync($"<div class=\"container\">Processing time: {sw.ElapsedMilliseconds} ms<div>");
});
它工作正常,但是 WriteAsync
创建的 HTML 被添加到响应的最后,在关闭 </html>
标签之后。
我如何放置 - 传递或注入 - 中间件计算的 sw.ElapsedMilliseconds
值在 HTML 体内的特定位置?使用 ASP.NET 核心 6.0.
也许你可以使用 HTML 敏捷包。
您可以使用LoadHtml
和HtmlNode.CreateNode
方法创建您要插入的html元素,然后使用DocumentNode.SelectSingleNode
到select您要插入的位置。
测试可以参考以下代码:
自定义中间件:
//Install-Package HtmlAgilityPack
public class ResponseMeasurementMiddleware
{
private readonly RequestDelegate _next;
public ResponseMeasurementMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var originalBody = context.Response.Body;
var newBody = new MemoryStream();
context.Response.Body = newBody;
var watch = new Stopwatch();
long responseTime = 0;
watch.Start();
await _next(context);
// read the new body
responseTime = watch.ElapsedMilliseconds;
newBody.Position = 0;
var newContent = await new StreamReader(newBody).ReadToEndAsync();
// calculate the updated html
var updatedHtml = CreateDataNode(newContent, responseTime);
// set the body = updated html
var updatedStream = GenerateStreamFromString(updatedHtml);
await updatedStream.CopyToAsync(originalBody);
context.Response.Body = originalBody;
}
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
private string CreateDataNode(string originalHtml, long responseTime)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(originalHtml);
HtmlNode testNode = HtmlNode.CreateNode($"<div class=\"container\">Processing time: {responseTime.ToString()} ms.</div>");
var htmlBody = htmlDoc.DocumentNode.SelectSingleNode(".//body/div");
if (htmlBody != null)
{
htmlBody.InsertBefore(testNode, htmlBody.FirstChild);
}
string rawHtml = htmlDoc.DocumentNode.OuterHtml; //using this results in a page that displays my inserted HTML correctly, but duplicates the original page content.
//rawHtml = "some text"; uncommenting this results in a page with the correct format: this text, followed by the original contents of the page
return rawHtml;
}
}
htmlDoc.DocumentNode.SelectSingleNode(".//body/div")
和htmlBody.InsertBefore(testNode, htmlBody.FirstChild)
可以自定义插入的位置。
并使用自定义中间件:
app.UseMiddleware<ResponseMeasurementMiddleware>();
测试结果:
我有一个计算 Razor 页面执行时间的中间件:
app.Use(async (context, next) =>
{
var sw = new Stopwatch();
sw.Start();
await next.Invoke();
sw.Stop();
await context.Response.WriteAsync($"<div class=\"container\">Processing time: {sw.ElapsedMilliseconds} ms<div>");
});
它工作正常,但是 WriteAsync
创建的 HTML 被添加到响应的最后,在关闭 </html>
标签之后。
我如何放置 - 传递或注入 - 中间件计算的 sw.ElapsedMilliseconds
值在 HTML 体内的特定位置?使用 ASP.NET 核心 6.0.
也许你可以使用 HTML 敏捷包。
您可以使用LoadHtml
和HtmlNode.CreateNode
方法创建您要插入的html元素,然后使用DocumentNode.SelectSingleNode
到select您要插入的位置。
测试可以参考以下代码:
自定义中间件:
//Install-Package HtmlAgilityPack
public class ResponseMeasurementMiddleware
{
private readonly RequestDelegate _next;
public ResponseMeasurementMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var originalBody = context.Response.Body;
var newBody = new MemoryStream();
context.Response.Body = newBody;
var watch = new Stopwatch();
long responseTime = 0;
watch.Start();
await _next(context);
// read the new body
responseTime = watch.ElapsedMilliseconds;
newBody.Position = 0;
var newContent = await new StreamReader(newBody).ReadToEndAsync();
// calculate the updated html
var updatedHtml = CreateDataNode(newContent, responseTime);
// set the body = updated html
var updatedStream = GenerateStreamFromString(updatedHtml);
await updatedStream.CopyToAsync(originalBody);
context.Response.Body = originalBody;
}
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
private string CreateDataNode(string originalHtml, long responseTime)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(originalHtml);
HtmlNode testNode = HtmlNode.CreateNode($"<div class=\"container\">Processing time: {responseTime.ToString()} ms.</div>");
var htmlBody = htmlDoc.DocumentNode.SelectSingleNode(".//body/div");
if (htmlBody != null)
{
htmlBody.InsertBefore(testNode, htmlBody.FirstChild);
}
string rawHtml = htmlDoc.DocumentNode.OuterHtml; //using this results in a page that displays my inserted HTML correctly, but duplicates the original page content.
//rawHtml = "some text"; uncommenting this results in a page with the correct format: this text, followed by the original contents of the page
return rawHtml;
}
}
htmlDoc.DocumentNode.SelectSingleNode(".//body/div")
和htmlBody.InsertBefore(testNode, htmlBody.FirstChild)
可以自定义插入的位置。
并使用自定义中间件:
app.UseMiddleware<ResponseMeasurementMiddleware>();
测试结果: