[翻译]自托管WebApi使用OWIN和Unity

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[翻译]自托管WebApi使用OWIN和Unity相关的知识,希望对你有一定的参考价值。

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/


以上是关于[翻译]自托管WebApi使用OWIN和Unity的主要内容,如果未能解决你的问题,请参考以下文章

如何在本地服务结构集群中部署和访问来宾可执行文件(ASP.NET OWIN 自托管 webapi 应用程序)

在 DELETE 上不允许使用 Owin 自托管 Web API 405 方法

asp.net web api 自托管 / owin / katana

在使用 Owin 自托管的 Web API 中获取远程主机 IP

具有 OWIN 自托管的 Web API 无类型 OData 服务返回 406 Not Acceptable

OWIN 托管的 web api:使用 windows 身份验证并允许匿名访问