Skip to content

Instantly share code, notes, and snippets.

@Bio2hazard
Created July 14, 2017 22:48
Show Gist options
  • Save Bio2hazard/3817ba5f291176f465baa263350925f5 to your computer and use it in GitHub Desktop.
Save Bio2hazard/3817ba5f291176f465baa263350925f5 to your computer and use it in GitHub Desktop.
CTOR DI In Azure Webjobs
using System;
using System.Threading.Tasks;
using SimpleInjector;
namespace Your.Namespace
{
/// <summary>
/// Provides an abstraction for WebJob functions, enabling dependency injection.
/// Mandatory to have on all triggered functions for proper disposal of execution scope.
/// </summary>
public abstract class FunctionBase : IDisposable
{
private Scope containerScope;
/// <summary>
/// Initializes a new instance of <see cref="FunctionBase"/>.
/// </summary>
protected FunctionBase() { }
/// <summary>
/// Sets the execution scope for this <see cref="FunctionBase"/>
/// </summary>
/// <param name="scope">The execution scope.</param>
public void SetScope(Scope scope)
{
containerScope = scope;
}
/// <inheritdoc />
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
containerScope?.Dispose();
}
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
using System;
using Microsoft.Azure.WebJobs.Host;
using SimpleInjector;
using SimpleInjector.Extensions.ExecutionContextScoping;
namespace Your.NameSpace
{
/// <summary>
/// An activator that uses <see cref="SimpleInjector"/> to return instance of a job type.
/// </summary>
public class JobActivator : IJobActivator
{
/// <summary>
/// The container where dependencies are registered.
/// </summary>
private readonly Container container;
/// <summary>
/// Creates a new <see cref="JobActivator"/> instance.
/// </summary>
/// <param name="container"></param>
public JobActivator(Container container)
{
this.container = container;
}
/// <summary>
/// Creates a new instance of a webjob function class within it's own execution context scope.
/// </summary>
/// <typeparam name="T">The type of the webjob function class being created.</typeparam>
/// <returns>The newly created instance of a webjob function.</returns>
public T CreateInstance<T>()
{
var scope = container.BeginExecutionContextScope();
var returnClass = (T)container.GetInstance(typeof(T));
if (returnClass is FunctionBase)
{
(returnClass as FunctionBase).SetScope(scope);
}
return returnClass;
}
}
}
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions;
namespace Your.Namespace
{
// To learn more about Microsoft Azure WebJobs SDK, please see http://go.microsoft.com/fwlink/?LinkID=320976
class Program
{
// Please set the following connection strings in app.config for this WebJob to run:
// AzureWebJobsDashboard and AzureWebJobsStorage
static void Main()
{
var container = SimpleInjectorInitializer.Initialize();
var config = new JobHostConfiguration
{
JobActivator = new JobActivator(container)
};
#if DEBUG
// Enables more verbose logging, less delay between picking up messages and a shortened listener lock.
// https://github.com/Azure/azure-webjobs-sdk/wiki/Running-Locally
config.UseDevelopmentSettings();
#endif
var host = new JobHost(config);
host.RunAndBlock();
}
}
}
using System;
using System.IO;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
namespace Your.Namespace
{
/// <summary>
/// This is a sample function
/// </summary>
public class SampleFunctions : FunctionBase
{
/// <summary>
/// Dependency injected <see cref="IUserManager"/> that provides methods for interacting with user accounts.
/// </summary>
private readonly IUserManager userManager;
/// <summary>
/// Initializes a new instance of <see cref="SampleFunctions"/>.
/// </summary>
/// <param name="userManager">Dependency injected <see cref="IUserManager"/> that provides methods for interacting with user accounts.</param>
public SampleFunctions(IUserManager userManager) : base()
{
this.userManager = userManager;
}
/// <summary>
/// Does a really cool thing.
/// </summary>
/// <param name="message">Incoming message to process.</param>
/// <param name="log">A logging binder.</param>
public async Task SampleTrigger([QueueTrigger("myqueue")] string message, TextWriter log)
{
// Obviously not ideal, but this is just a example for DI
if (int.TryParse(message, out int userId))
{
var userAccount = await userManager.FindByIdAsync(userId);
if (userAccount != null)
{
var claim = new Claim("JobTest", "TestClaimValue");
if (userAccount.Claims.Exists(c => c.Type == claim.Type && c.Value == claim.Value))
{
// Remove claim
log.WriteLine("Removing claim");
await userManager.RemoveClaimAsync(userId, claim);
}
else
{
// Add claim
log.WriteLine("Adding claim");
await userManager.AddClaimAsync(userId, claim);
}
}
else
{
log.WriteLine($"User not found {message}");
}
}
else
{
log.WriteLine(message);
}
}
}
}
using System;
using System.Configuration;
using SimpleInjector;
using SimpleInjector.Extensions.ExecutionContextScoping;
namespace Your.Namespace
{
/// <summary>
/// Simple Injector Initializer
/// </summary>
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container.</summary>
public static Container Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
InitializeContainer(container);
container.Verify();
return container;
}
private static void InitializeContainer(Container container)
{
// Singleton Example
// container.RegisterSingleton<ILogger, Logger>();
// Scoped Example
// container.Register<EntityFrameworkContext>(Lifestyle.Scoped);
// container.Register<IUserManager,UserManager>(Lifestyle.Scoped);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment