Optimizing TagBuilder.CreateSanitizedId to create buffer only when needed.
- Tested with a page containing 33% of invalid Ids which go through TagBuilder.CreateSanitizedId. - Ran 10,000 requests with 20 in parallel and measured perf. - Data before the change: System.String allocated by CreateSanitizedId: 1.84 mb System.Text.StringBuilder allocated by CreateSanitizedId: 1.68 mb - Data after the change: System.String allocated by CreateSanitizedId: 0.720 mb System.Text.StringBuilder allocated by CreateSanitizedId: 0.560 mb Around 60% improvement from the original case.
This commit is contained in:
parent
4b18bfb494
commit
57f1ae755f
|
|
@ -77,16 +77,40 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there are no invalid characters in the string, then we don't have to create the buffer.
|
||||||
|
var firstIndexOfInvalidCharacter = 1;
|
||||||
|
for (; firstIndexOfInvalidCharacter < name.Length; firstIndexOfInvalidCharacter++)
|
||||||
|
{
|
||||||
|
if (!Html401IdUtil.IsValidIdCharacter(name[firstIndexOfInvalidCharacter]))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var firstChar = name[0];
|
var firstChar = name[0];
|
||||||
if (!Html401IdUtil.IsAsciiLetter(firstChar))
|
var startsWithAsciiLetter = Html401IdUtil.IsAsciiLetter(firstChar);
|
||||||
|
if (!startsWithAsciiLetter)
|
||||||
{
|
{
|
||||||
// The first character must be a letter according to the HTML 4.01 specification.
|
// The first character must be a letter according to the HTML 4.01 specification.
|
||||||
firstChar = 'z';
|
firstChar = 'z';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (firstIndexOfInvalidCharacter == name.Length && startsWithAsciiLetter)
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
var stringBuffer = new StringBuilder(name.Length);
|
var stringBuffer = new StringBuilder(name.Length);
|
||||||
stringBuffer.Append(firstChar);
|
stringBuffer.Append(firstChar);
|
||||||
for (var index = 1; index < name.Length; index++)
|
|
||||||
|
// Characters until 'firstIndexOfInvalidCharacter' have already been checked for validity.
|
||||||
|
// So just copying them. This avoids running them through Html401IdUtil.IsValidIdCharacter again.
|
||||||
|
for (var index = 1; index < firstIndexOfInvalidCharacter; index++)
|
||||||
|
{
|
||||||
|
stringBuffer.Append(name[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var index = firstIndexOfInvalidCharacter; index < name.Length; index++)
|
||||||
{
|
{
|
||||||
var thisChar = name[index];
|
var thisChar = name[index];
|
||||||
if (Html401IdUtil.IsValidIdCharacter(thisChar))
|
if (Html401IdUtil.IsValidIdCharacter(thisChar))
|
||||||
|
|
|
||||||
|
|
@ -116,5 +116,18 @@ namespace Microsoft.AspNet.Mvc.Core.Rendering
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("HtmlEncode[[TestValue]]", tagBuilder.InnerHtml);
|
Assert.Equal("HtmlEncode[[TestValue]]", tagBuilder.InnerHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("HelloWorld", "HelloWorld")]
|
||||||
|
[InlineData("¡HelloWorld", "zHelloWorld")]
|
||||||
|
[InlineData("Hello¡World", "Hello-World")]
|
||||||
|
public void CreateSanitizedIdCreatesId(string input, string output)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var result = TagBuilder.CreateSanitizedId(input, "-");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(output, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue