This post continues in from the previous blog Self Host WebApi with Owin and Unity
The blog project and nuget package can be downloaded from here:
nuget: https://www.nuget.org/packages/Unity.SelfHostWebApiOwin
code: https://github.com/damienbod/SelfHostWebApiWithOwinAndUnityUsingNuget
In this blog, a nuget packet will be created, so unity can be used with a self hosted web Api easily.
What is required in the nuget package:
- UnityDependencyResolver: so the controllers can be injected with unity
- UnityFilterAttributeFilterProvider: so the filters can be injected with unity
First create a new project: Unity.SelfHostWebApiOwin
Now add the following classes:
UnityDependencyResolver
using System; using System.Collections.Generic; using System.Web.Http.Controllers; using System.Web.Http.Dependencies; using Microsoft.Practices.Unity; namespace Unity.SelfHostWebApiOwin { /// <summary> /// An implementation of the <see cref="IDependencyResolver"/> interface that wraps a Unity container. /// </summary> public sealed class UnityDependencyResolver : IDependencyResolver { private IUnityContainer container; private SharedDependencyScope sharedScope; /// <summary> /// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class for a container. /// </summary> /// <param name="container">The <see cref="IUnityContainer"/> to wrap with the <see cref="IDependencyResolver"/> /// interface implementation.</param> public UnityDependencyResolver(IUnityContainer container) { if (container == null) throw new ArgumentNullException("container"); this.container = container; this.sharedScope = new SharedDependencyScope(container); } /// <summary> /// Reuses the same scope to resolve all the instances. /// </summary> /// <returns>The shared dependency scope.</returns> public IDependencyScope BeginScope() { return this.sharedScope; } /// <summary> /// Disposes the wrapped <see cref="IUnityContainer"/>. /// </summary> public void Dispose() { this.container.Dispose(); this.sharedScope.Dispose(); } /// <summary> /// Resolves an instance of the default requested type from the container. /// </summary> /// <param name="serviceType">The <see cref="Type"/> of the object to get from the container.</param> /// <returns>The requested object.</returns> public object GetService(Type serviceType) { try { return this.container.Resolve(serviceType); } catch (ResolutionFailedException) { return null; } } /// <summary> /// Resolves multiply registered services. /// </summary> /// <param name="serviceType">The type of the requested services.</param> /// <returns>The requested services.</returns> public IEnumerable<object> GetServices(Type serviceType) { try { return this.container.ResolveAll(serviceType); } catch (ResolutionFailedException) { return null; } } private sealed class SharedDependencyScope : IDependencyScope { private IUnityContainer container; public SharedDependencyScope(IUnityContainer container) { this.container = container; } public object GetService(Type serviceType) { return this.container.Resolve(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return this.container.ResolveAll(serviceType); } public void Dispose() { // NO-OP, as the container is shared. } } } }
WebApiUnityActionFilterProvider
using System.Collections.Generic; using System.Web.Http; using System.Web.Http.Filters; using System.Web.Http.Controllers; using Microsoft.Practices.Unity; namespace Unity.SelfHostWebApiOwin { public class WebApiUnityActionFilterProvider : ActionDescriptorFilterProvider, IFilterProvider { private readonly IUnityContainer container; public WebApiUnityActionFilterProvider(IUnityContainer container) { this.container = container; } public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) { var filters = base.GetFilters(configuration, actionDescriptor); var filterInfoList = new List<FilterInfo>(); foreach (var filter in filters) { container.BuildUp(filter.Instance.GetType(), filter.Instance); } return filters; } } }
And then add the required nuget packages as required.
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Microsoft.AspNet.WebApi.Client" version="5.1.0" targetFramework="net45" /> <package id="Microsoft.AspNet.WebApi.Core" version="5.1.0" targetFramework="net45" /> <package id="Microsoft.AspNet.WebApi.Owin" version="5.1.0" targetFramework="net45" /> <package id="Microsoft.AspNet.WebApi.OwinSelfHost" version="5.1.0" targetFramework="net45" /> <package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" /> <package id="Microsoft.Owin.Host.HttpListener" version="2.1.0" targetFramework="net45" /> <package id="Microsoft.Owin.Hosting" version="2.1.0" targetFramework="net45" /> <package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" /> <package id="Owin" version="1.0" targetFramework="net45" /> <package id="Unity" version="3.0.1304.1" targetFramework="net45" /> </packages>
Now a nuget get package needs to be created:
Step 1: Download the latest nuget.exe (version 2.7.40906.213 or later)
Step 2: Create a Nuget package in the cmd console: nuget spec
Step 3: Edit the file and rename; for example Unity.SelfHostWebApiOwin.1.0.6-beta.nuspec
<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>Unity.SelfHostWebApiOwin</id> <title>Self Hosted Web Api using Owin and Unity</title> <version>1.0.11</version> <authors>damienbod</authors> <owners>damienbod</owners> <projectUrl>https://damienbod.wordpress.com/2013/10/12/self-hosted-web-api-using-owin-and-unity-nuget-package-documentation</projectUrl> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>Unity for self hosted WebApi</description> <iconUrl>http://www.gravatar.com/avatar/61d005637f57b5c3da8ba662cf04a9d6.png</iconUrl> <language>en-US</language> <tags>.NET ASP.NET Web Api Enterprise Library Unity Web WebApi</tags> <dependencies> <dependency id="Unity" version="3.0.1304.1" /> <dependency id="Microsoft.Web.Infrastructure" version="1.0.0.0" /> <dependency id="Microsoft.AspNet.WebApi.WebHost" version="5.1.0" /> <dependency id="Microsoft.AspNet.WebPages" version="3.1.0" /> <dependency id="Newtonsoft.Json" version="5.0.8" /> <dependency id="Owin" version="1.0" /> <dependency id="Microsoft.AspNet.WebApi.OwinSelfHost" version="5.1.0" /> <dependency id="Microsoft.AspNet.WebApi.Core" version="5.1.0" /> <dependency id="Microsoft.AspNet.WebApi.Client" version="5.1.0" /> <dependency id="Microsoft.Owin" version="2.1.0" /> <dependency id="Microsoft.Owin.Host.HttpListener" version="2.1.0" /> <dependency id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" /> </dependencies> </metadata> </package>
Step 4: Create the nuget structure:
- MyPackage
- content
- Unity.SelfHostWebApiOwin
- Startup.cs.pp
- UnityHelpers.cs.pp
- Unity.SelfHostWebApiOwin
- lib
- net45
- Unity.SelfHostWebApiOwin.dll
- net45
- content
Files in the content folder will be copied directly into the target project.
Files into the lib will be added as references.
The following 2 files are added to the content. The files have a .pp ending, required by nuget
Startup.cs.pp
using Owin; using System.Web.Http; using Microsoft.Owin.Hosting; using System; using System.Linq; using Microsoft.Practices.Unity; using System.Web.Http.Filters; namespace Unity.SelfHostWebApiOwin { public class Startup { private static readonly IUnityContainer _container = UnityHelpers.GetConfiguredContainer(); // Your startup logic public static void StartServer() { string baseAddress = "http://localhost:8081/"; var startup = _container.Resolve<Startup>(); //options.ServerFactory = "Microsoft.Owin.Host.HttpListener" IDisposable webApplication = WebApp.Start(baseAddress, startup.Configuration); try { Console.WriteLine("Started..."); Console.ReadKey(); } finally { webApplication.Dispose(); } } // This code configures Web API. The Startup class is specified as a type // parameter in the WebApp.Start method. public void Configuration(IAppBuilder appBuilder) { // Configure Web API for self-host. var config = new HttpConfiguration(); // Add Unity DependencyResolver config.DependencyResolver = new UnityDependencyResolver(UnityHelpers.GetConfiguredContainer()); // Add Unity filters provider RegisterFilterProviders(config); //config.Routes.MapHttpRoute( // name: "DefaultApi", // routeTemplate: "api/{controller}/{id}", // defaults: new { id = RouteParameter.Optional } //); // Web API routes config.MapHttpAttributeRoutes(); appBuilder.UseWebApi(config); } private static void RegisterFilterProviders(HttpConfiguration config) { // Add Unity filters provider var providers = config.Services.GetFilterProviders().ToList(); config.Services.Add(typeof(System.Web.Http.Filters.IFilterProvider), new WebApiUnityActionFilterProvider(UnityHelpers.GetConfiguredContainer())); var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider); config.Services.Remove(typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider); } } }
UnityHelpers.cs.pp
using System; using System.Collections.Generic; using System.Reflection; using Microsoft.Practices.Unity; using System.Linq; namespace Unity.SelfHostWebApiOwin { public static class UnityHelpers { #region Unity Container private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => { var container = new UnityContainer(); RegisterTypes(container); return container; }); public static IUnityContainer GetConfiguredContainer() { return container.Value; } #endregion //private static readonly Type[] EmptyTypes = new Type[0]; public static IEnumerable<Type> GetTypesWithCustomAttribute<T>( Assembly[] assemblies) { foreach (var assembly in assemblies) { foreach (Type type in assembly.GetTypes()) { if (type.GetCustomAttributes(typeof(T), true).Length > 0) { yield return type; } } } } public static void RegisterTypes(IUnityContainer container) { // Add your register logic here... // var myAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("your_assembly_Name")).ToArray(); container.RegisterType(typeof(Startup)); // container.RegisterTypes( // UnityHelpers.GetTypesWithCustomAttribute<ContainerControlledAttribute>(myAssemblies), // WithMappings.FromMatchingInterface, // WithName.Default, // WithLifetime.ContainerControlled, // null // ).RegisterTypes( // UnityHelpers.GetTypesWithCustomAttribute<TransientLifetimeAttribute>(myAssemblies), // WithMappings.FromMatchingInterface, // WithName.Default, // WithLifetime.Transient); } } }
Step 5: Create the nuget package in the cmd console: nuget pack
This produces a .nupkg file. This is the file which can be uploaded.
Step 6: Upload to nuget. nuget gallery
Now we are ready to use the nuget package. The next post will be the nuget package documentation/user manual.
Links:
nuget create package help
http://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package