Skip to content

Commit 126c09c

Browse files
committed
Fixing Blob bindings
1 parent acf3403 commit 126c09c

File tree

8 files changed

+87
-46
lines changed

8 files changed

+87
-46
lines changed

sample/BlobTrigger-CSharp/function.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
"bindings": [
33
{
44
"type": "blobTrigger",
5+
"name": "blob",
56
"direction": "in",
6-
"path": "samples-workitems-csharp"
7+
"path": "samples-input-csharp/{name}"
78
},
89
{
910
"type": "blob",
1011
"name": "output",
1112
"direction": "out",
12-
"path": "samples-workitems/{id}"
13+
"path": "samples-output-csharp/{name}"
1314
}
1415
]
1516
}

sample/BlobTrigger-CSharp/run.csx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ using System.Linq;
33
using System.Threading.Tasks;
44
using Microsoft.Azure.WebJobs.Host;
55

6-
public static void Run(string id, out string output, TraceWriter log)
6+
public static void Run(string blob, out string output, TraceWriter log)
77
{
8-
log.Verbose($"CSharp Blob trigger function processed a work item. Item={id}");
8+
log.Verbose($"CSharp Blob trigger function processed a blob. Blob={blob}");
99

10-
output = "test";
10+
output = blob;
1111
}

sample/BlobTrigger/function.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
{
44
"type": "blobTrigger",
55
"direction": "in",
6-
"path": "samples-workitems"
6+
"path": "samples-input/{name}"
7+
},
8+
{
9+
"type": "blob",
10+
"name": "output",
11+
"direction": "out",
12+
"path": "samples-output/{name}"
713
}
814
]
915
}

sample/BlobTrigger/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
module.exports = function (context, workItem) {
2-
console.log('Node.js blob trigger function processed work item ' + workItem.id);
3-
context.done();
1+
module.exports = function (context, blob) {
2+
console.log('Node.js blob trigger function processed blob ' + blob);
3+
context.done(null, {
4+
output: blob
5+
});
46
}

src/WebJobs.Script/Description/NodeFunctionInvoker.cs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Collections.ObjectModel;
7-
using System.Diagnostics;
87
using System.Dynamic;
98
using System.Globalization;
109
using System.IO;
@@ -100,14 +99,7 @@ public override async Task Invoke(object[] parameters)
10099

101100
var scriptExecutionContext = CreateScriptExecutionContext(input, traceWriter, TraceWriter, binder, functionExecutionContext);
102101

103-
// if there are any binding parameters in the output bindings,
104-
// parse the input as json to get the binding data
105-
Dictionary<string, string> bindingData = new Dictionary<string, string>();
106-
if (_outputBindings.Any(p => p.HasBindingParameters) ||
107-
_inputBindings.Any(p => p.HasBindingParameters))
108-
{
109-
bindingData = GetBindingData(input);
110-
}
102+
Dictionary<string, string> bindingData = GetBindingData(input, binder, _inputBindings, _outputBindings);
111103
bindingData["InvocationId"] = functionExecutionContext.InvocationId.ToString();
112104

113105
await ProcessInputBindingsAsync(binder, scriptExecutionContext, bindingData);
@@ -375,12 +367,5 @@ private bool TryDeserializeJsonObject(string json, out Dictionary<string, object
375367
return false;
376368
}
377369
}
378-
379-
private static bool IsJson(string input)
380-
{
381-
input = input.Trim();
382-
return (input.StartsWith("{", StringComparison.OrdinalIgnoreCase) && input.EndsWith("}", StringComparison.OrdinalIgnoreCase))
383-
|| (input.StartsWith("[", StringComparison.OrdinalIgnoreCase) && input.EndsWith("]", StringComparison.OrdinalIgnoreCase));
384-
}
385370
}
386371
}

src/WebJobs.Script/Description/ScriptFunctionInvoker.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,7 @@ internal async Task ExecuteScriptAsync(string path, string arguments, object[] i
114114
Dictionary<string, string> environmentVariables = new Dictionary<string, string>();
115115
InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, functionExecutionContext);
116116

117-
// if there are any parameters in the bindings,
118-
// parse the input as json to get the binding data
119-
Dictionary<string, string> bindingData = new Dictionary<string, string>();
120-
if (_outputBindings.Any(p => p.HasBindingParameters) ||
121-
_inputBindings.Any(p => p.HasBindingParameters))
122-
{
123-
bindingData = GetBindingData(stdin);
124-
}
117+
Dictionary<string, string> bindingData = GetBindingData(stdin, binder, _inputBindings, _outputBindings);
125118
bindingData["InvocationId"] = invocationId;
126119

127120
await ProcessInputBindingsAsync(functionInstanceOutputPath, binder, bindingData, environmentVariables);

src/WebJobs.Script/Description/ScriptFunctionInvokerBase.cs

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Collections.ObjectModel;
67
using System.Diagnostics;
78
using System.IO;
89
using System.Linq;
10+
using System.Reflection;
911
using System.Threading.Tasks;
1012
using Microsoft.Azure.WebJobs.Host;
13+
using Microsoft.Azure.WebJobs.Script.Binding;
1114
using Newtonsoft.Json.Linq;
1215

1316
namespace Microsoft.Azure.WebJobs.Script.Description
@@ -64,27 +67,77 @@ protected virtual void OnScriptFileChanged(object sender, FileSystemEventArgs e)
6467
{
6568
}
6669

67-
protected static Dictionary<string, string> GetBindingData(object value)
70+
protected static Dictionary<string, string> GetBindingData(object value, IBinder binder, Collection<FunctionBinding> inputBindings, Collection<FunctionBinding> outputBindings)
6871
{
6972
Dictionary<string, string> bindingData = new Dictionary<string, string>();
7073

71-
try
74+
// first apply any existing binding data
75+
ApplyAmbientBindingData(binder, bindingData);
76+
77+
// If there are any parameters in the bindings,
78+
// get the binding data. In dynamic script cases we need
79+
// to parse this POCO data ourselves - it won't be in the existing
80+
// binding data because all the POCO binders require strong
81+
// typing
82+
if (outputBindings.Any(p => p.HasBindingParameters) ||
83+
inputBindings.Any(p => p.HasBindingParameters))
7284
{
73-
// parse the object skipping any nested objects (binding data
74-
// only includes top level properties)
75-
JObject parsed = JObject.Parse(value as string);
76-
bindingData = parsed.Children<JProperty>()
77-
.Where(p => p.Value.Type != JTokenType.Object)
78-
.ToDictionary(p => p.Name, p => (string)p);
85+
try
86+
{
87+
string json = value as string;
88+
if (!string.IsNullOrEmpty(json) && IsJson(json))
89+
{
90+
// parse the object skipping any nested objects (binding data
91+
// only includes top level properties)
92+
JObject parsed = JObject.Parse(json);
93+
bindingData = parsed.Children<JProperty>()
94+
.Where(p => p.Value.Type != JTokenType.Object)
95+
.ToDictionary(p => p.Name, p => (string)p);
96+
}
97+
}
98+
catch
99+
{
100+
// it's not an error if the incoming message isn't JSON
101+
// there are cases where there will be output binding parameters
102+
// that don't bind to JSON properties
103+
}
79104
}
80-
catch
105+
106+
return bindingData;
107+
}
108+
109+
/// <summary>
110+
/// TEMP HACK
111+
/// We need to merge the ambient binding data that already exists in the IBinder
112+
/// with our binding data. We have to do this rather than relying solely on
113+
/// IBinder.BindAsync because we need to include any POCO values we get from parsing
114+
/// JSON bodies, etc.
115+
/// </summary>
116+
protected static void ApplyAmbientBindingData(IBinder binder, IDictionary<string, string> bindingData)
117+
{
118+
// TEMP: Dig the ambient binding data out of the binder
119+
FieldInfo fieldInfo = binder.GetType().GetField("_bindingSource", BindingFlags.NonPublic | BindingFlags.Instance);
120+
var bindingSource = fieldInfo.GetValue(binder);
121+
PropertyInfo propertyInfo = bindingSource.GetType().GetProperty("AmbientBindingContext");
122+
var ambientBindingContext = propertyInfo.GetValue(bindingSource);
123+
propertyInfo = ambientBindingContext.GetType().GetProperty("BindingData");
124+
IDictionary<string, object> ambientBindingData = (IDictionary<string, object>)propertyInfo.GetValue(ambientBindingContext);
125+
126+
if (ambientBindingData != null)
81127
{
82-
// it's not an error if the incoming message isn't JSON
83-
// there are cases where there will be output binding parameters
84-
// that don't bind to JSON properties
128+
// apply the binding data to ours
129+
foreach (var item in ambientBindingData)
130+
{
131+
bindingData[item.Key] = item.Value.ToString();
132+
}
85133
}
134+
}
86135

87-
return bindingData;
136+
protected static bool IsJson(string input)
137+
{
138+
input = input.Trim();
139+
return (input.StartsWith("{", StringComparison.OrdinalIgnoreCase) && input.EndsWith("}", StringComparison.OrdinalIgnoreCase))
140+
|| (input.StartsWith("[", StringComparison.OrdinalIgnoreCase) && input.EndsWith("]", StringComparison.OrdinalIgnoreCase));
88141
}
89142

90143
protected virtual void Dispose(bool disposing)

src/src.ruleset

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<Rule Id="CA904" Action="None" />
1717
<Rule Id="CA905" Action="None" />
1818
<Rule Id="CA908" Action="None" />
19+
<Rule Id="CA1062" Action="None" />
1920
<Rule Id="CA1303" Action="None" /> <!-- Enable when we move literals to resx -->
2021
</Rules>
2122
</RuleSet>

0 commit comments

Comments
 (0)