Skip to content

Instantly share code, notes, and snippets.

@roryprimrose
Created May 27, 2018 04:43

Revisions

  1. roryprimrose created this gist May 27, 2018.
    171 changes: 171 additions & 0 deletions Function1.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,171 @@

    namespace FunctionApp1
    {
    using Autofac;
    using Autofac.Core;
    using EnsureThat;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Description;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Azure.WebJobs.Host.Config;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Concurrent;
    using System.Linq;
    using System.Reflection;
    using Module = Autofac.Module;

    public static class Function1
    {
    [FunctionName("Function1")]
    public static void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer,
    [Inject(typeof(ISomething))]ISomething something,
    ILogger log)
    {
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

    var value = something.GetSomething();

    log.LogInformation("Found value " + value);
    }
    }

    public interface ISomething
    {
    string GetSomething();
    }

    public class Something : ISomething
    {
    private readonly ILogger _logger;

    public Something(ILogger logger)
    {
    _logger = logger;
    }

    public string GetSomething()
    {
    _logger.LogInformation("Hey, we are doing something and dependency injection works!");

    return Guid.NewGuid().ToString();
    }
    }

    [Binding]
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
    public class InjectAttribute : Attribute
    {
    public InjectAttribute(Type type)
    {
    Type = type;
    }

    public Type Type { get; }
    }

    public class InjectConfiguration : IExtensionConfigProvider
    {
    private static readonly object _syncLock = new object();
    private static IContainer _container;

    public void Initialize(ExtensionConfigContext context)
    {
    InitializeContainer(context);

    context
    .AddBindingRule<InjectAttribute>()
    .BindToInput<dynamic>(i => _container.Resolve(i.Type));
    }

    private void InitializeContainer(ExtensionConfigContext context)
    {
    if (_container != null)
    {
    return;
    }

    lock (_syncLock)
    {
    if (_container != null)
    {
    return;
    }

    _container = ContainerConfig.BuildContainer(context.Config.LoggerFactory);
    }
    }
    }

    public static class ContainerConfig
    {
    public static IContainer BuildContainer(ILoggerFactory factory)
    {
    var builder = new ContainerBuilder();

    var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Any()).ToArray();

    builder.RegisterTypes(assemblyTypes).AsImplementedInterfaces();

    builder.RegisterInstance(factory).As<ILoggerFactory>();
    builder.RegisterModule<LoggerModule>();

    return builder.Build();
    }
    }

    public class LoggerModule : Module
    {
    private static readonly ConcurrentDictionary<Type, object> _logCache = new ConcurrentDictionary<Type, object>();

    private interface ILoggerWrapper
    {
    object Create(ILoggerFactory factory);
    }

    protected override void AttachToComponentRegistration(
    IComponentRegistry componentRegistry,
    IComponentRegistration registration)
    {
    Ensure.Any.IsNotNull(registration, nameof(registration));

    // Handle constructor parameters.
    registration.Preparing += OnComponentPreparing;
    }

    private static object GetLogger(IComponentContext context, Type declaringType)
    {
    return _logCache.GetOrAdd(
    declaringType,
    x =>
    {
    var factory = context.Resolve<ILoggerFactory>();
    var loggerName = "Function." + declaringType.FullName + ".User";

    return factory.CreateLogger(loggerName);
    });
    }

    private static void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
    var t = e.Component.Activator.LimitType;

    if (t.FullName.IndexOf(nameof(FunctionApp1), StringComparison.OrdinalIgnoreCase) == -1)
    {
    return;
    }

    if (t.FullName.EndsWith("[]", StringComparison.OrdinalIgnoreCase))
    {
    // Ignore IEnumerable types
    return;
    }

    e.Parameters = e.Parameters.Union(
    new[]
    {
    new ResolvedParameter((p, i) => p.ParameterType == typeof(ILogger), (p, i) => GetLogger(i, t))
    });
    }
    }
    }
    20 changes: 20 additions & 0 deletions FunctionApp1.csproj
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    <Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <AzureFunctionsVersion>v2</AzureFunctionsVersion>
    </PropertyGroup>
    <ItemGroup>
    <PackageReference Include="Autofac" Version="4.8.1" />
    <PackageReference Include="Ensure.That" Version="8.0.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.13" />
    </ItemGroup>
    <ItemGroup>
    <None Update="host.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
    </ItemGroup>
    </Project>