I’ve been building a little console app to be run as an Azure web job for my side project. I want to re-use some of the services in the business logic layer that serves the website this web job is for. This requires some dependencies injection in this console app.
There is a Schedule service that I want to inject which implements the following interface
public interface IScheduleQueryService : IQueryService { Schedule GetSchedule(string id); }
public class ScheduleQueryService : IScheduleQueryService { public Schedule GetSchedule(string id) { Schedule schedule; // Logics to get schedule return schedule; } }
Next, a custom dependency resolver needs to be created where Unity container, that the service is registered to, will be used to resolve dependencies. Create a class that implements IDependencyResolver. This interface requires implementation for two methods GetService and GetServices. This is where Unity container is used to resolve dependencies.
/// <summary> /// The <see cref="UnityDependencyResolver"/> /// class is used to provide dependency resolution support using an <see cref="IUnityContainer"/> instance. /// </summary> public class UnityDependencyResolver : IDependencyResolver { /// <summary> /// Stores whether this instance has been disposed. /// </summary> private bool _isDisposed; private IUnityContainer _container; /// <summary> /// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class. /// </summary> /// <param name="container"> /// The container. /// </param> public UnityDependencyResolver(IUnityContainer container) { Contract.Requires<ArgumentNullException>(container != null); _container = container; } /// <summary> /// Begins the scope. /// </summary> /// <returns> /// A <see cref="IDependencyScope"/> instance. /// </returns> public IDependencyScope BeginScope() { if (_isDisposed) { throw new ObjectDisposedException(GetType().Name); } var child = this._container.CreateChildContainer(); return new UnityDependencyResolver(child); } /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Gets the service. /// </summary> /// <param name="serviceType"> /// Type of the service. /// </param> /// <returns> /// A <see cref="Object"/> instance. /// </returns> public object GetService(Type serviceType) { try { return this._container.Resolve(serviceType); } catch (ResolutionFailedException) { return null; } } /// <summary> /// Gets the services. /// </summary> /// <param name="serviceType"> /// Type of the service. /// </param> /// <returns> /// A <see cref="IEnumerable<T>"/> instance. /// </returns> public IEnumerable<object> GetServices(Type serviceType) { try { return this._container.ResolveAll(serviceType); } catch (ResolutionFailedException) { return new List<object>(); } } /// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> /// <param name="disposing"> /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources. /// </param> protected virtual void Dispose(bool disposing) { if (_isDisposed) { return; } if (disposing) { // Free managed resources _container.Dispose(); } // Free native resources if there are any _isDisposed = true; } }
Then I create a method in the console app to register this service. There are two ways to do this. The service can be registered individually.
public void SetupUnity() { var container = new UnityContainer(); container.RegisterType<IScheduleQueryService, ScheduleQueryService>(); // Set custom dependency resolver to global config dependency resolver GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); }
However, this becomes annoying to maintain as you need to register multiple services. Another way is to scan all assemblies for anything that references the base interface, in this case it is IQueryService
public void SetupUnity() { var container = new UnityContainer(); container.RegisterTypes( AllClasses.FromLoadedAssemblies() .Where( type => typeof(IQueryService).IsAssignableFrom(type)) && !type.IsAbstract && !type.IsInterface), WithMappings.FromMatchingInterface, WithName.Default, WithLifetime.PerResolve); // Set custom dependency resolver to global config dependency resolver GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); }
To reference a service, use the dependency resolver from the global configuration.
var scheduleQueryService = (IScheduleQueryService)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IScheduleQueryService));
Here is how everything is put together.
class Program { static void Main(string[] args) { SetupUnity(); var scheduleQueryService = (IScheduleQueryService)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IScheduleQueryService)); // ... } public void SetupUnity() { var container = new UnityContainer(); container.RegisterTypes( AllClasses.FromLoadedAssemblies() .Where( type => typeof (IQueryService).IsAssignableFrom(type)) && !type.IsAbstract && !type.IsInterface), WithMappings.FromMatchingInterface, WithName.Default, WithLifetime.PerResolve); // Set custom dependency resolver to global config dependency resolver GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); } }
Tom Phan
Kavitha,
Yes that solution requires reference to System.Web.Http. If you don’t want to reference reference to System.Web.Http, you can look into HostBuilder in .Net Core 2.1. Keep in mind that it’s only in preview 1 release. I haven’t tried using Unity with HostBuilder yet so not sure if they work together.
Kavitha
Hi,
Thanks for a great article. Actually I was trying the same to use unity in my console application. But dependency resolver requires a reference to System.Web.Http which is not available for a console application. Could you please guide me how to achieve this?
Thanks,
Kavitha