Skip to content

Avoid StringBuilder.AppendFormat #3412

Closed
@paulomorgado

Description

@paulomorgado

Describe the feature

Amazon.Runtime.Internal.Marshaller.SetUserAgentHeader has this code:

private static void SetUserAgentHeader(IRequestContext requestContext)
{
    var sb = new StringBuilder(requestContext.ClientConfig.UserAgent);

    var clientAppId = requestContext.ClientConfig.ClientAppId;
    if (!string.IsNullOrEmpty(clientAppId))
        sb.AppendFormat(" app/{0}", clientAppId);

    var retryMode = requestContext.ClientConfig.RetryMode.ToString().ToLower();
    sb.AppendFormat(" cfg/retry-mode#{0}", retryMode);

    sb.AppendFormat(" md/{0}", requestContext.IsAsync ? "ClientAsync" : "ClientSync");

    sb.AppendFormat(" cfg/init-coll#{0}", AWSConfigs.InitializeCollections ? "1" : "0");

    var userAgentAddition = requestContext.OriginalRequest.UserAgentAddition;
    if (!string.IsNullOrEmpty(userAgentAddition))
    {
        sb.AppendFormat(" {0}", userAgentAddition);
    }

    var userAgent = sb.ToString();

    userAgent = InternalSDKUtils.ReplaceInvalidUserAgentCharacters(userAgent);

    if (requestContext.ClientConfig.UseAlternateUserAgentHeader)
    {
        requestContext.Request.Headers[HeaderKeys.XAmzUserAgentHeader] = userAgent;
    }
    else
    {
        requestContext.Request.Headers[HeaderKeys.UserAgentHeader] = userAgent;
    }
}

There's no practical use of `StringBuilder.AppendFormat here.

Use Case

Creating objects that do not need to be created, not only uses memory and CPU to create them, but also causes GC work.

Interpreting a format and formatting is unnecessary work when appending to a StringBuilder.

Proposed Solution

Consider using:

private static void SetUserAgentHeader(IRequestContext requestContext)
{
    var sb = new StringBuilder(requestContext.ClientConfig.UserAgent);

    var clientAppId = requestContext.ClientConfig.ClientAppId;
    if (!string.IsNullOrEmpty(clientAppId))
        sb.Append(" app/").Append(clientAppId);

    sb.Append(" cfg/retry-mode#}");
    foreach (var c in requestContext.ClientConfig.RetryMode.ToString())
        sb.Append(char.ToLowerInvariant(c));

    sb.Append(" md/").Append(requestContext.IsAsync ? "ClientAsync" : "ClientSync");

    sb.Append(" cfg/init-coll#").Append(AWSConfigs.InitializeCollections ? "1" : "0");

    var userAgentAddition = requestContext.OriginalRequest.UserAgentAddition;
    if (!string.IsNullOrEmpty(userAgentAddition))
    {
        sb.Append(' ').Append(userAgentAddition);
    }

    var userAgent = sb.ToString();

    userAgent = InternalSDKUtils.ReplaceInvalidUserAgentCharacters(userAgent);

    if (requestContext.ClientConfig.UseAlternateUserAgentHeader)
    {
        requestContext.Request.Headers[HeaderKeys.XAmzUserAgentHeader] = userAgent;
    }
    else
    {
        requestContext.Request.Headers[HeaderKeys.UserAgentHeader] = userAgent;
    }
}

Other Information

But, how much can change in the user-agent string that needs to be computed for every request?

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

AWSSDK.KeyManagementService 3.7.300.52

Targeted .NET Platform

.NET 8

Operating System and version

Windows and Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions