OWIN托管的WebApi应用程序使用Unity,要比标准的WebApi应用程序使用Unity复杂一点点.
这篇博客展示怎样把ASP.NET Web API寄宿到一个控制台应用程序,使用OWIN自托管WebApi框架和Unity的Ioc.
需要实现下面的步骤:
1.把OWIN.Hosting和Unity的程序集添加到解决方案.
2.Unity的registrations和startup逻辑是必须的.
3.Unity的解析器需要添加到OWIN startup 的上下文.
4.释放资源的逻辑必须实现.
使用下面的nuget包,添加OWIN.Hosting:
http://www.nuget.org/packages/Microsoft.AspNet.WebApi.OwinSelfHost/
Install-Package Microsoft.AspNet.WebApi.OwinSelfHost -Pre
使用nuget管理器添加Unity(注意不是Unity.WebApi,下面有解释)
一个能被Console应用程序或Windows Service调用的开始方法是必须要具备的.这个方法决定了使用Unity创建实例.这个方法也定义了服务的url和使用OWIN配置方法开始这个服务.
1 using Owin; 2 using System.Web.Http; 3 using Microsoft.Owin.Hosting; 4 using System; 5 using System.Net.Http; 6 using Microsoft.Practices.Unity; 7 8 namespace SelfHostWebApiOwin 9 { 10 public class Startup 11 { 12 private static readonly IUnityContainer _container = UnityHelpers.GetConfiguredContainer(); 13 14 public static void StartServer() 15 { 16 string baseAddress = "http://localhost:8081/"; 17 var startup = _container.Resolve<Startup>(); 18 IDisposable webApplication = WebApp.Start(baseAddress, startup.Configuration); 19 20 try 21 { 22 Console.WriteLine("Started..."); 23 24 Console.ReadKey(); 25 } 26 finally 27 { 28 webApplication.Dispose(); 29 } 30 } 31 } 32 }
Configuration(IAppBuilder appBuilder)提供我们服务所有必须的信息.这里可以添加authorization, filters, http logging,和其他的OWIN客户端
1 public void Configuration(IAppBuilder appBuilder) 2 { 3 // Configure Web API for self-host. 4 HttpConfiguration config = new HttpConfiguration(); 5 config.DependencyResolver = new UnityDependencyResolver( 6 SelfHostWebApiOwin.UnityHelpers.GetConfiguredContainer()); 7 8 config.Routes.MapHttpRoute( 9 name: "DefaultApi", 10 routeTemplate: "api/{controller}/{id}", 11 defaults: new { id = RouteParameter.Optional } 12 ); 13 14 appBuilder.UseWebApi(config); 15 }
在这个方法里,HttpConfiguration.DependencyResolver设置了一个UnityDependencyResolver实例.WebApi controllers使用构造函数注入必须要这么做.UnityDependencyResolver类完全相当于Unity.WebApi.UnityDependencyResolver类,我们不使用Unity.WebApi,因为这是一个自托管的OWIN应用程序.
http://unity.codeplex.com/SourceControl/latest#Unity/Unity.WebApi/Src/UnityDependencyResolver.cs
UnityDependencyResolver : IDependencyResolver
Unity的注册必须被定义.他被定义在了UnityHelper类.按照注册惯例注册实例.属性用来使用每个接口,类的生命周期注册类型可以更舒适的被定义,没有必要配置地狱.
1 using System; 2 using System.Collections.Generic; 3 using System.Reflection; 4 using Microsoft.Practices.Unity; 5 using System.Linq; 6 using SelfHostWebApiOwin.Business.Attributes; 7 using SelfHostWebApiOwin; 8 9 namespace SelfHostWebApiOwin 10 { 11 public static class UnityHelpers 12 { 13 #region Unity Container 14 private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => 15 { 16 var container = new UnityContainer(); 17 RegisterTypes(container); 18 return container; 19 }); 20 21 public static IUnityContainer GetConfiguredContainer() 22 { 23 return container.Value; 24 } 25 #endregion 26 27 //private static readonly Type[] EmptyTypes = new Type[0]; 28 29 public static IEnumerable<Type> GetTypesWithCustomAttribute<T>( Assembly[] assemblies) 30 { 31 foreach (var assembly in assemblies) 32 { 33 foreach (Type type in assembly.GetTypes()) 34 { 35 if (type.GetCustomAttributes(typeof(T), true).Length > 0) 36 { 37 yield return type; 38 } 39 } 40 } 41 } 42 43 public static void RegisterTypes(IUnityContainer container) 44 { 45 var myAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("SelfHostWebApiOwin")).ToArray(); 46 47 container.RegisterType(typeof(Startup)); 48 49 container.RegisterTypes( 50 UnityHelpers.GetTypesWithCustomAttribute<UnityIoCContainerControlledAttribute>(myAssemblies), 51 WithMappings.FromMatchingInterface, 52 WithName.Default, 53 WithLifetime.ContainerControlled, 54 null 55 ).RegisterTypes( 56 UnityHelpers.GetTypesWithCustomAttribute<UnityIoCTransientLifetimeAttribute>(myAssemblies), 57 WithMappings.FromMatchingInterface, 58 WithName.Default, 59 WithLifetime.Transient); 60 61 } 62 63 } 64 }
这有一个attribute的小例子.
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace SelfHostWebApiOwin.Business.Attributes 7 { 8 [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)] 9 public class UnityIoCTransientLifetimeAttribute : System.Attribute 10 { 11 public double version; 12 13 public UnityIoCTransientLifetimeAttribute() 14 { 15 version = 1.0; 16 } 17 } 18 }
现在可以创建业务逻辑层.在这层我只使用构造函数注入.这些类是松耦合的并且容易被测试.
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using SelfHostWebApiOwin.Business.Logging; 6 using SelfHostWebApiOwin.Business.Attributes; 7 8 namespace SelfHostWebApiOwin.Business 9 { 10 [UnityIoCTransientLifetimeAttribute] 11 public class BusinessClass : IBusinessClass 12 { 13 private IUnitOfWorkExample _unitOfWorkExample; 14 15 public BusinessClass(IUnitOfWorkExample unitOfWorkExample) 16 { 17 _unitOfWorkExample = unitOfWorkExample; 18 UnityEventLogger.Log.CreateUnityMessage("BusinessClass"); 19 } 20 21 private bool _disposed = false; 22 23 public string Hello() 24 { 25 return _unitOfWorkExample.HelloFromUnitOfWorkExample(); 26 } 27 28 public void Dispose() 29 { 30 _unitOfWorkExample.Dispose(); 31 UnityEventLogger.Log.DisposeUnityMessage("BusinessClass"); 32 if (!_disposed) 33 { 34 _disposed = true; 35 } 36 } 37 } 38 }
现在这些类可以使用构造函数注入到Controllers.
1 public class ValuesController : ApiController 2 { 3 private readonly IBusinessClass _businessClass; 4 private readonly IBusinessClass2 _businessClass2; 5 public ValuesController(IBusinessClass businessClass, IBusinessClass2 businessClass2) 6 { 7 _businessClass = businessClass; 8 _businessClass2 = businessClass2; 9 }
当这个示例应用程序启动的时候,fiddler可以用来连接这个api.从结果我们可以看到业务逻辑的方法被使用了并且应用程序方法被定义了.
Code: https://github.com/damienbod/SelfHostWebApiWithOwinAndUnity
错失了什么:
-我们没有实现适当的释放逻辑.We could do this by implementing a new LifeTime Manager (per request as implemented in Unity.MVC) with a dispose.(这句话实在不知道怎么翻译 算了)
-我们可以创建一个filter供应者.Unity.MVC也提供了一个好例子.
-我们可以使用所有里面的这些创建一个nuget包Unity.SelfHostWebApi
原文链接:https://damienbod.com/2013/10/01/self-host-webapi-with-owin-and-unity/