Support IConnectionProvider. Closes #11

This commit is contained in:
Ahmed ElSayed 2017-04-25 18:44:46 -07:00
Родитель 1718afd2c3
Коммит d51dff065a
7 изменённых файлов: 300 добавлений и 0 удалений

Просмотреть файл

@ -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>