Skip to content

Commit 7d27511

Browse files
authored
Add null check to ScriptInvocationContextExtensions.ToRpcInvocationRequest (#6478)
1 parent 0f2cc24 commit 7d27511

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

src/WebJobs.Script/Workers/MessageExtensions/ScriptInvocationContextExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ public static async Task<InvocationRequest> ToRpcInvocationRequest(this ScriptIn
3434

3535
foreach (var input in context.Inputs)
3636
{
37-
if (!rpcValueCache.TryGetValue(input.val, out TypedData rpcValue))
37+
TypedData rpcValue = null;
38+
if (input.val == null || !rpcValueCache.TryGetValue(input.val, out rpcValue))
3839
{
3940
rpcValue = await input.val.ToRpc(logger, capabilities);
41+
if (input.val != null)
42+
{
43+
rpcValueCache.Add(input.val, rpcValue);
44+
}
4045
}
4146

4247
var parameterBinding = new ParameterBinding

test/WebJobs.Script.Tests/Workers/ScriptInvocationContextExtensionsTests.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Google.Protobuf.Collections;
99
using Microsoft.AspNetCore.Http;
10+
using Microsoft.AspNetCore.Mvc.ModelBinding;
1011
using Microsoft.Azure.WebJobs.Script.Description;
1112
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
1213
using Microsoft.Azure.WebJobs.Script.Workers;
@@ -148,6 +149,137 @@ public async Task ToRpcInvocationRequest_Http_OmitsDuplicateBodyOfBindingData()
148149
Assert.True(result.TriggerMetadata.ContainsKey("query"));
149150
}
150151

152+
[Fact]
153+
public async Task ToRpcInvocationRequest_MultipleInputBindings()
154+
{
155+
var logger = new TestLogger("test");
156+
157+
var httpContext = new DefaultHttpContext();
158+
httpContext.Request.Host = new HostString("local");
159+
httpContext.Request.Path = "/test";
160+
httpContext.Request.Method = "Post";
161+
162+
var poco = new TestPoco { Id = 1, Name = "Test" };
163+
164+
var bindingData = new Dictionary<string, object>
165+
{
166+
{ "req", httpContext.Request },
167+
{ "$request", httpContext.Request },
168+
{ "headers", httpContext.Request.Headers.ToDictionary(p => p.Key, p => p.Value) },
169+
{ "query", httpContext.Request.QueryString.ToString() },
170+
{ "sys", new SystemBindingData() }
171+
};
172+
173+
var inputs = new List<(string name, DataType type, object val)>
174+
{
175+
("req", DataType.String, httpContext.Request),
176+
("blob", DataType.String, null), // verify that null values are handled
177+
("foo", DataType.String, "test"),
178+
("bar1", DataType.String, poco),
179+
("bar2", DataType.String, poco)
180+
};
181+
182+
var invocationContext = new ScriptInvocationContext()
183+
{
184+
ExecutionContext = new ExecutionContext()
185+
{
186+
InvocationId = Guid.NewGuid(),
187+
FunctionName = "Test",
188+
},
189+
BindingData = bindingData,
190+
Inputs = inputs,
191+
ResultSource = new TaskCompletionSource<ScriptInvocationResult>(),
192+
Logger = logger,
193+
AsyncExecutionContext = System.Threading.ExecutionContext.Capture()
194+
};
195+
196+
var functionMetadata = new FunctionMetadata
197+
{
198+
Name = "Test"
199+
};
200+
201+
var httpTriggerBinding = new BindingMetadata
202+
{
203+
Name = "req",
204+
Type = "httpTrigger",
205+
Direction = BindingDirection.In,
206+
Raw = new JObject()
207+
};
208+
209+
var blobInputBinding = new BindingMetadata
210+
{
211+
Name = "blob",
212+
Type = "blob",
213+
Direction = BindingDirection.In
214+
};
215+
216+
var fooInputBinding = new BindingMetadata
217+
{
218+
Name = "foo",
219+
Type = "foo",
220+
Direction = BindingDirection.In
221+
};
222+
223+
var barInputBinding1 = new BindingMetadata
224+
{
225+
Name = "bar1",
226+
Type = "bar",
227+
Direction = BindingDirection.In
228+
};
229+
230+
var barInputBinding2 = new BindingMetadata
231+
{
232+
Name = "bar2",
233+
Type = "bar",
234+
Direction = BindingDirection.In
235+
};
236+
237+
var httpOutputBinding = new BindingMetadata
238+
{
239+
Name = "res",
240+
Type = "http",
241+
Direction = BindingDirection.Out,
242+
Raw = new JObject(),
243+
DataType = DataType.String
244+
};
245+
246+
functionMetadata.Bindings.Add(httpTriggerBinding);
247+
functionMetadata.Bindings.Add(blobInputBinding);
248+
functionMetadata.Bindings.Add(fooInputBinding);
249+
functionMetadata.Bindings.Add(barInputBinding1);
250+
functionMetadata.Bindings.Add(barInputBinding2);
251+
functionMetadata.Bindings.Add(httpOutputBinding);
252+
invocationContext.FunctionMetadata = functionMetadata;
253+
254+
Capabilities capabilities = new Capabilities(logger);
255+
var result = await invocationContext.ToRpcInvocationRequest(logger, capabilities);
256+
Assert.Equal(5, result.InputData.Count);
257+
258+
Assert.Equal("req", result.InputData[0].Name);
259+
var resultHttp = result.InputData[0].Data;
260+
Assert.Equal("http://local/test", ((RpcHttp)result.InputData[0].Data.Http).Url);
261+
262+
// verify the null input was propagated properly
263+
Assert.Equal("blob", result.InputData[1].Name);
264+
Assert.Equal(string.Empty, result.InputData[1].Data.String);
265+
266+
Assert.Equal("foo", result.InputData[2].Name);
267+
Assert.Equal("test", result.InputData[2].Data.String);
268+
269+
Assert.Equal("bar1", result.InputData[3].Name);
270+
var resultPoco = result.InputData[3].Data;
271+
Assert.Equal("{\"Name\":\"Test\",\"Id\":1}", resultPoco.Json);
272+
273+
Assert.Equal("bar2", result.InputData[4].Name);
274+
Assert.Same(resultPoco, result.InputData[4].Data);
275+
276+
Assert.Equal(4, result.TriggerMetadata.Count);
277+
Assert.Same(resultHttp, result.TriggerMetadata["req"]);
278+
Assert.Same(resultHttp, result.TriggerMetadata["$request"]);
279+
Assert.True(result.TriggerMetadata.ContainsKey("headers"));
280+
Assert.True(result.TriggerMetadata.ContainsKey("query"));
281+
}
282+
151283
private class TestPoco
152284
{
153285
public string Name { get; set; }

0 commit comments

Comments
 (0)