Support IConnectionProvider. Closes #11
This commit is contained in:
Родитель
1718afd2c3
Коммит
d51dff065a
|
@ -48,5 +48,11 @@ namespace SDKFuncs
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
[FunctionName("QueueFunc")]
|
||||
public static void RunQueue([QueueTrigger("queue1")] string message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,41 @@ namespace MakeFunctionJson
|
|||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="attribute"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetValue<T>(this Attribute attribute, string propertyName)
|
||||
{
|
||||
var property = attribute.GetType().GetProperty(propertyName);
|
||||
if (property != null)
|
||||
{
|
||||
return (T)property.GetValue(attribute);
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="propertyValue"></param>
|
||||
public static void SetValue(this Attribute attribute, string propertyName, object propertyValue)
|
||||
{
|
||||
var property = attribute.GetType().GetProperty(propertyName);
|
||||
if (property != null)
|
||||
{
|
||||
property.SetValue(attribute, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetPropertyValue(PropertyInfo property, object propertyValue, out string value)
|
||||
{
|
||||
value = null;
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace MakeFunctionJson
|
|||
var bindings = parameterInfo
|
||||
.GetCustomAttributes()
|
||||
.Where(a => a.IsWebJobsAttribute()) // this has to return at least 1.
|
||||
.Select(a => TypeUtility.GetResolvedAttribute(parameterInfo, a))
|
||||
.Select(a => a.ToJObject()) // Convert the Attribute into a JObject.
|
||||
.Select(obj =>
|
||||
{
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MakeFunctionJson
|
||||
{
|
||||
internal static class TypeInfoExtensions
|
||||
{
|
||||
public static bool IsImplementing(this TypeInfo typeInfo, string interfaceName)
|
||||
{
|
||||
return typeInfo.ImplementedInterfaces.Any(i => i.Name.Equals(interfaceName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MakeFunctionJson
|
||||
{
|
||||
/// <summary>
|
||||
/// Code is __mostly__ a copy of https://github.com/Azure/azure-webjobs-sdk/blob/ab0ad6449460b70534ab0472ee4bbb92be8157fc/src/Microsoft.Azure.WebJobs.Host/TypeUtility.cs
|
||||
/// </summary>
|
||||
internal static class TypeUtility
|
||||
{
|
||||
internal static string GetFriendlyName(Type type)
|
||||
{
|
||||
if (TypeUtility.IsNullable(type))
|
||||
{
|
||||
return string.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", type.GetGenericArguments()[0].Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsNullable(Type type)
|
||||
{
|
||||
return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
}
|
||||
|
||||
internal static bool IsJObject(Type type)
|
||||
{
|
||||
return type == typeof(JObject);
|
||||
}
|
||||
|
||||
// Task<T> --> T
|
||||
// Task --> void
|
||||
// T --> T
|
||||
internal static Type UnwrapTaskType(Type type)
|
||||
{
|
||||
if (type == typeof(Task))
|
||||
{
|
||||
return typeof(void);
|
||||
}
|
||||
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
return type.GetGenericArguments()[0];
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walk from the parameter up to the containing type, looking for an instance
|
||||
/// of the specified attribute type, returning it if found.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter to check.</param>
|
||||
internal static T GetHierarchicalAttributeOrNull<T>(ParameterInfo parameter) where T : Attribute
|
||||
{
|
||||
return (T)GetHierarchicalAttributeOrNull(parameter, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walk from the parameter up to the containing type, looking for an instance
|
||||
/// of the specified attribute type, returning it if found.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter to check.</param>
|
||||
/// <param name="attributeType">The attribute type to look for.</param>
|
||||
internal static Attribute GetHierarchicalAttributeOrNull(ParameterInfo parameter, Type attributeType)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var attribute = parameter.GetCustomAttribute(attributeType);
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
|
||||
var method = parameter.Member as MethodInfo;
|
||||
if (method == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GetHierarchicalAttributeOrNull(method, attributeType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walk from the method up to the containing type, looking for an instance
|
||||
/// of the specified attribute type, returning it if found.
|
||||
/// </summary>
|
||||
/// <param name="method">The method to check.</param>
|
||||
internal static T GetHierarchicalAttributeOrNull<T>(MethodInfo method) where T : Attribute
|
||||
{
|
||||
return (T)GetHierarchicalAttributeOrNull(method, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walk from the method up to the containing type, looking for an instance
|
||||
/// of the specified attribute type, returning it if found.
|
||||
/// </summary>
|
||||
/// <param name="method">The method to check.</param>
|
||||
/// <param name="type">The attribute type to look for.</param>
|
||||
internal static Attribute GetHierarchicalAttributeOrNull(MethodInfo method, Type type)
|
||||
{
|
||||
var attribute = method.GetCustomAttribute(type);
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
|
||||
attribute = method.DeclaringType.GetTypeInfo().GetCustomAttribute(type);
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static Attribute GetResolvedAttribute(ParameterInfo parameter, Attribute attribute)
|
||||
{
|
||||
if (attribute != null &&
|
||||
attribute.GetType().GetTypeInfo().IsImplementing("IConnectionProvider") &&
|
||||
string.IsNullOrEmpty(attribute.GetValue<string>("Connection")))
|
||||
{
|
||||
// if the attribute doesn't specify an explicit connection, walk up
|
||||
// the hierarchy looking for an override specified via attribute
|
||||
var connectionProviderAttribute = attribute
|
||||
.GetType()
|
||||
.GetTypeInfo()
|
||||
.GetCustomAttributes()
|
||||
.FirstOrDefault(a => a.GetType().Name == "ConnectionProviderAttribute");
|
||||
|
||||
if (connectionProviderAttribute?.GetValue<Type>("ProviderType") != null)
|
||||
{
|
||||
var connectionOverrideProvider = GetHierarchicalAttributeOrNull(parameter, connectionProviderAttribute.GetValue<Type>("ProviderType"));
|
||||
if (connectionOverrideProvider != null &&
|
||||
connectionOverrideProvider.GetType().GetTypeInfo().IsImplementing("IConnectionProvider"))
|
||||
{
|
||||
var iConnectionProvider = connectionOverrideProvider.GetType().GetTypeInfo().GetInterface("IConnectionProvider");
|
||||
var propertyInfo = iConnectionProvider.GetProperty("Connection");
|
||||
var connectionValue = (string) propertyInfo.GetValue(attribute);
|
||||
connectionValue = connectionValue
|
||||
?? connectionOverrideProvider.GetValue<string>("Connection")
|
||||
?? connectionOverrideProvider.GetValue<string>("Account");
|
||||
if (!string.IsNullOrEmpty(connectionValue))
|
||||
{
|
||||
attribute.SetValue("Connection", connectionValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
public static bool IsAsync(MethodInfo methodInfo)
|
||||
{
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(methodInfo));
|
||||
}
|
||||
|
||||
var stateMachineAttribute = methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>();
|
||||
if (stateMachineAttribute != null)
|
||||
{
|
||||
var stateMachineType = stateMachineAttribute.StateMachineType;
|
||||
if (stateMachineType != null)
|
||||
{
|
||||
return stateMachineType.GetTypeInfo().GetCustomAttribute<CompilerGeneratedAttribute>() != null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsAsyncVoid(MethodInfo methodInfo)
|
||||
{
|
||||
return IsAsync(methodInfo) && (methodInfo.ReturnType == typeof(void));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
|
||||
namespace Microsoft.NET.Sdk.Functions.Test
|
||||
{
|
||||
[StorageAccount("bar")]
|
||||
public class FunctionsClass1
|
||||
{
|
||||
[FunctionName("QueueFunc")]
|
||||
[StorageAccount("foo")]
|
||||
public static void RunQueue([QueueTrigger("queue1")] string message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[StorageAccount("bar")]
|
||||
public class FunctionsClass2
|
||||
{
|
||||
[FunctionName("QueueFunc")]
|
||||
[StorageAccount("foo")]
|
||||
public static void RunQueue([QueueTrigger("queue1")] string message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[StorageAccount("bar")]
|
||||
public class FunctionsClass3
|
||||
{
|
||||
[FunctionName("QueueFunc")]
|
||||
[StorageAccount("foo")]
|
||||
public static void RunQueue([StorageAccount("foobar")][QueueTrigger("queue1")] string message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[StorageAccount("bar")]
|
||||
public class FunctionsClass4
|
||||
{
|
||||
[FunctionName("QueueFunc")]
|
||||
[StorageAccount("foo")]
|
||||
public static void RunQueue([StorageAccount("foobar")][QueueTrigger("queue1", Connection = "foobarfoobar")] string message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class IConnectionProviderTests
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -204,6 +204,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="GeneralWebJobsAttributesTests.cs" />
|
||||
<Compile Include="HttpTriggerTests.cs" />
|
||||
<Compile Include="IConnectionProviderTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServiceBusTriggerTests.cs" />
|
||||
</ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче