|
3 | 3 |
|
4 | 4 | using System;
|
5 | 5 | using System.Collections.Generic;
|
| 6 | +using System.Collections.ObjectModel; |
6 | 7 | using System.Diagnostics;
|
7 | 8 | using System.IO;
|
8 | 9 | using System.Linq;
|
| 10 | +using System.Reflection; |
9 | 11 | using System.Threading.Tasks;
|
10 | 12 | using Microsoft.Azure.WebJobs.Host;
|
| 13 | +using Microsoft.Azure.WebJobs.Script.Binding; |
11 | 14 | using Newtonsoft.Json.Linq;
|
12 | 15 |
|
13 | 16 | namespace Microsoft.Azure.WebJobs.Script.Description
|
@@ -64,27 +67,77 @@ protected virtual void OnScriptFileChanged(object sender, FileSystemEventArgs e)
|
64 | 67 | {
|
65 | 68 | }
|
66 | 69 |
|
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) |
68 | 71 | {
|
69 | 72 | Dictionary<string, string> bindingData = new Dictionary<string, string>();
|
70 | 73 |
|
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)) |
72 | 84 | {
|
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 | + } |
79 | 104 | }
|
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) |
81 | 127 | {
|
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 | + } |
85 | 133 | }
|
| 134 | + } |
86 | 135 |
|
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)); |
88 | 141 | }
|
89 | 142 |
|
90 | 143 | protected virtual void Dispose(bool disposing)
|
|
0 commit comments