Skip to content

Commit e5bb938

Browse files
authored
Replaced dynamic usage with static typing in ConvertFromHttpMessageToExpando method for improved performance. (#11054)
1 parent c2f4e50 commit e5bb938

File tree

2 files changed

+60
-42
lines changed

2 files changed

+60
-42
lines changed

release_notes.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
### Release notes
2-
3-
<!-- Please add your release notes in the following format:
4-
- My change description (#PR)
5-
-->
6-
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
7-
- Fix invocation timeout when incoming request contains "x-ms-invocation-id" header (#10980)
8-
- Warn if .azurefunctions folder does not exist (#10967)
1+
### Release notes
2+
3+
<!-- Please add your release notes in the following format:
4+
- My change description (#PR)
5+
-->
6+
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
7+
- Fix invocation timeout when incoming request contains "x-ms-invocation-id" header (#10980)
8+
- Warn if .azurefunctions folder does not exist (#10967)
9+
- Memory allocation & CPU optimizations in `GrpcMessageExtensionUtilities.ConvertFromHttpMessageToExpando` (#11054)

src/WebJobs.Script.Grpc/MessageExtensions/GrpcMessageExtensionUtilities.cs

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Dynamic;
7-
using System.Linq;
87
using Microsoft.AspNetCore.Http;
98
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
109
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
@@ -13,30 +12,58 @@ namespace Microsoft.Azure.WebJobs.Script.Grpc
1312
{
1413
internal static class GrpcMessageExtensionUtilities
1514
{
16-
public static object ConvertFromHttpMessageToExpando(RpcHttp inputMessage)
15+
private static readonly object BoxedTrue = true;
16+
private static readonly object BoxedFalse = false;
17+
private static readonly IReadOnlyDictionary<string, object> EmptyHeaders = new Dictionary<string, object>();
18+
19+
public static ExpandoObject ConvertFromHttpMessageToExpando(RpcHttp inputMessage)
1720
{
18-
if (inputMessage == null)
21+
if (inputMessage is null)
1922
{
2023
return null;
2124
}
2225

23-
dynamic expando = new ExpandoObject();
24-
expando.method = inputMessage.Method;
25-
expando.query = inputMessage.Query as IDictionary<string, string>;
26-
expando.statusCode = inputMessage.StatusCode;
27-
expando.headers = inputMessage.Headers.ToDictionary(p => p.Key, p => (object)p.Value);
28-
expando.enableContentNegotiation = inputMessage.EnableContentNegotiation;
26+
var expando = new ExpandoObject();
27+
IDictionary<string, object> dict = expando;
28+
29+
dict["method"] = inputMessage.Method;
30+
dict["query"] = inputMessage.Query;
31+
dict["statusCode"] = inputMessage.StatusCode;
32+
dict["enableContentNegotiation"] = inputMessage.EnableContentNegotiation ? BoxedTrue : BoxedFalse;
2933

30-
expando.cookies = new List<Tuple<string, string, CookieOptions>>();
31-
foreach (RpcHttpCookie cookie in inputMessage.Cookies)
34+
if (inputMessage.Headers is { Count: > 0 })
35+
{
36+
var headerDict = new Dictionary<string, object>(inputMessage.Headers.Count);
37+
foreach (var kvp in inputMessage.Headers)
38+
{
39+
headerDict[kvp.Key] = kvp.Value;
40+
}
41+
dict["headers"] = headerDict;
42+
}
43+
else
3244
{
33-
expando.cookies.Add(RpcHttpCookieConverter(cookie));
45+
dict["headers"] = EmptyHeaders;
3446
}
3547

36-
if (inputMessage.Body != null)
48+
if (inputMessage.Cookies is { Count: > 0 })
3749
{
38-
expando.body = inputMessage.Body.ToObject();
50+
var cookiesList = new List<Tuple<string, string, CookieOptions>>(inputMessage.Cookies.Count);
51+
foreach (var cookie in inputMessage.Cookies)
52+
{
53+
cookiesList.Add(RpcHttpCookieConverter(cookie));
54+
}
55+
dict["cookies"] = cookiesList;
3956
}
57+
else
58+
{
59+
dict["cookies"] = Array.Empty<Tuple<string, string, CookieOptions>>();
60+
}
61+
62+
if (inputMessage.Body is not null)
63+
{
64+
dict["body"] = inputMessage.Body.ToObject();
65+
}
66+
4067
return expando;
4168
}
4269

@@ -80,27 +107,17 @@ public static Tuple<string, string, CookieOptions> RpcHttpCookieConverter(RpcHtt
80107

81108
internal static void UpdateWorkerMetadata(this WorkerMetadata workerMetadata, RpcWorkerConfig workerConfig)
82109
{
83-
workerMetadata.RuntimeName = string.IsNullOrEmpty(workerMetadata.RuntimeName)
84-
? workerConfig.Description.Language : workerMetadata.RuntimeName;
85-
workerMetadata.RuntimeVersion = string.IsNullOrEmpty(workerMetadata.RuntimeVersion)
86-
? workerConfig.Description.DefaultRuntimeVersion : workerMetadata.RuntimeVersion;
110+
workerMetadata.RuntimeName ??= workerConfig.Description.Language;
111+
workerMetadata.RuntimeVersion ??= workerConfig.Description.DefaultRuntimeVersion;
87112
}
88113

89-
private static SameSiteMode RpcSameSiteEnumConverter(RpcHttpCookie.Types.SameSite sameSite)
114+
private static SameSiteMode RpcSameSiteEnumConverter(RpcHttpCookie.Types.SameSite sameSite) => sameSite switch
90115
{
91-
switch (sameSite)
92-
{
93-
case RpcHttpCookie.Types.SameSite.Strict:
94-
return SameSiteMode.Strict;
95-
case RpcHttpCookie.Types.SameSite.Lax:
96-
return SameSiteMode.Lax;
97-
case RpcHttpCookie.Types.SameSite.None:
98-
return SameSiteMode.Unspecified;
99-
case RpcHttpCookie.Types.SameSite.ExplicitNone:
100-
return SameSiteMode.None;
101-
default:
102-
return SameSiteMode.Unspecified;
103-
}
104-
}
116+
RpcHttpCookie.Types.SameSite.Strict => SameSiteMode.Strict,
117+
RpcHttpCookie.Types.SameSite.Lax => SameSiteMode.Lax,
118+
RpcHttpCookie.Types.SameSite.None => SameSiteMode.Unspecified,
119+
RpcHttpCookie.Types.SameSite.ExplicitNone => SameSiteMode.None,
120+
_ => SameSiteMode.Unspecified
121+
};
105122
}
106-
}
123+
}

0 commit comments

Comments
 (0)