Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Commit 4c7bdcf

Browse files
committed
Reduce string allocations in PrimeCache
Return Task<IHtmlContent> instead of Task<HtmlString> and write directly to the TextWriter instead of concatenating/formatting strings.
1 parent 7052fa0 commit 4c7bdcf

File tree

1 file changed

+44
-13
lines changed

1 file changed

+44
-13
lines changed

src/Microsoft.AspNetCore.AngularServices/PrimeCacheHelper.cs

+44-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
using System;
2+
using System.IO;
23
using System.Net;
34
using System.Net.Http;
5+
using System.Text.Encodings.Web;
46
using System.Threading.Tasks;
5-
using Microsoft.AspNetCore.Mvc.Rendering;
67
using Microsoft.AspNetCore.Html;
8+
using Microsoft.AspNetCore.Mvc.Rendering;
79
using Microsoft.Extensions.Logging;
810
using Newtonsoft.Json;
911

1012
namespace Microsoft.AspNetCore.AngularServices
1113
{
1214
public static class PrimeCacheHelper
1315
{
14-
public static async Task<HtmlString> PrimeCache(this IHtmlHelper html, string url)
16+
public static async Task<IHtmlContent> PrimeCache(this IHtmlHelper html, string url)
1517
{
1618
// TODO: Consider deduplicating the PrimeCache calls (that is, if there are multiple requests to precache
1719
// the same URL, only return nonempty for one of them). This will make it easier to auto-prime-cache any
@@ -33,26 +35,55 @@ public static async Task<HtmlString> PrimeCache(this IHtmlHelper html, string ur
3335
request.Path.ToUriComponent(),
3436
request.QueryString.ToUriComponent());
3537
var fullUri = new Uri(new Uri(baseUriString), url);
36-
var response = await new HttpClient().GetAsync(fullUri.ToString());
37-
var responseBody = await response.Content.ReadAsStringAsync();
38-
return new HtmlString(FormatAsScript(url, response.StatusCode, responseBody));
38+
var response = await new HttpClient().GetAsync(fullUri.ToString()).ConfigureAwait(false);
39+
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
40+
return new PrimeCacheScript(url, response.StatusCode, responseBody);
3941
}
4042
catch (Exception ex)
4143
{
4244
var logger = (ILogger)html.ViewContext.HttpContext.RequestServices.GetService(typeof(ILogger));
4345
logger?.LogWarning("Error priming cache for URL: " + url, ex);
44-
return new HtmlString(string.Empty);
46+
return HtmlString.Empty;
4547
}
4648
}
4749

48-
private static string FormatAsScript(string url, HttpStatusCode responseStatusCode, string responseBody)
50+
private sealed class PrimeCacheScript : IHtmlContent
4951
{
50-
var preCachedUrl = JsonConvert.SerializeObject(url);
51-
var preCachedJson = JsonConvert.SerializeObject(new { statusCode = responseStatusCode, body = responseBody });
52-
return "<script>"
53-
+ "window.__preCachedResponses = window.__preCachedResponses || {};"
54-
+ $"window.__preCachedResponses[{preCachedUrl}] = {preCachedJson};"
55-
+ "</script>";
52+
private readonly string _url;
53+
private readonly HttpStatusCode _responseStatusCode;
54+
private readonly string _responseBody;
55+
56+
public PrimeCacheScript(string url, HttpStatusCode responseStatusCode, string responseBody)
57+
{
58+
_url = url;
59+
_responseStatusCode = responseStatusCode;
60+
_responseBody = responseBody;
61+
}
62+
63+
// These properties exist to be serialized as JSON without having to allocate an anonymous object.
64+
public HttpStatusCode statusCode => _responseStatusCode;
65+
public string body => _responseBody;
66+
67+
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
68+
{
69+
if (writer == null)
70+
{
71+
throw new ArgumentNullException(nameof(writer));
72+
}
73+
74+
if (encoder == null)
75+
{
76+
throw new ArgumentNullException(nameof(encoder));
77+
}
78+
79+
var serializer = new JsonSerializer();
80+
var jsonWriter = new JsonTextWriter(writer);
81+
jsonWriter.WriteRaw("<script>window.__preCachedResponses=window.__preCachedResponses||{},window.__preCachedResponses[");
82+
serializer.Serialize(jsonWriter, _url);
83+
jsonWriter.WriteRaw("]=");
84+
serializer.Serialize(jsonWriter, this);
85+
jsonWriter.WriteRaw(";</script>");
86+
}
5687
}
5788
}
5889
}

0 commit comments

Comments
 (0)