نکته 1: برای پیاده سازی این مثالها، Castle Windsor به عنوان IOC Container انتخاب شده است. بدیهی است میتوانید از Ioc Container مورد نظر خود نیز بهره ببرید.
نکته 2: میتوانید از مقاله [هاست سرویسهای Web Api با استفاده از OWIN و TopShelf] جهت هاست سرویسهای web Api خود استفاده نمایید.
روش اول
در این روش، قدم اول، ساخت یک کلاس و پیاده سازی اینترفیس IDependencyResolver میباشد؛ به صورت زیر:
public class ApiDependencyResolver : IDependencyResolver { public ApiDependencyResolver(IWindsorContainer container) { Container = container; } public IWindsorContainer Container { get; private set; } public object GetService(Type serviceType) { try { return Container.Kernel.HasComponent(serviceType) ? Container.Resolve(serviceType) : null; } catch (Kernel.ComponentNotFoundException) { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return Container.ResolveAll(serviceType).Cast<object>(); } catch (Kernel.ComponentNotFoundException) { return Enumerable.Empty<object>(); } } public IDependencyScope BeginScope() { return new SharedDependencyResolver(Container); } public void Dispose() { Container.Dispose(); } }
کاربرد متد BeginScope چیست؟
کنترلرها به صورت (Per Request) بر اساس هر درخواست وهله سازی خواهند شد. جهت مدیریت چرخهی عمر کنترلرها و منابع در اختیار آنها، از متد BeginScope استفاده میشود. به این صورت که نمونهی اصلی DependencyResolver در هنگام شروع برنامه به GlobalConfiguration پروژه Attach خواهد شد. سپس به ازای هر درخواست، جهت وهله سازی Controllerها، متد GetService از محدوده داخلی (منظور فراخوانی متد BeginScope است) باعث ایجاد نمونه و بعد از اتمام فرآیند، متد Dispose باعث آزاد سازی منابع موجود خواهد شد.
پیاده سازی متد BeginScope وابسته به IocContainer مورد استفاده شما است. در این جا کلاس SharedDependencyResolver را به صورت زیر پیاده سازی کردم:
public class SharedDependencyResolver : IDependencyScope { public SharedDependencyResolver(IWindsorContainer container) { Container = container; Scope = Container.BeginScope(); } public IWindsorContainer Container { get; private set; } public IDisposable Scope { get; private set; } public object GetService(Type serviceType) { try { return Container.Kernel.HasComponent(serviceType) ? Container.Resolve(serviceType) : null; } catch (ComponentNotFoundException) { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return Container.ResolveAll(serviceType).Cast<object>(); } catch (ComponentNotFoundException) { return null; } } public void Dispose() { Scope.Dispose(); } }
public IDependencyScope BeginScope() { var child = container.CreateChildContainer(); return new ApiDependencyResolver(child); }
public class KernelInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient()); container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true)); } }
در پایان در کلاس Startup نیز کافیست مراحل زیر را انجام دهید:
»ابتدا Installer نوشته شده را به WindsorContainer معرفی نمایید.
»DependencyResolver نوشته شده را به HttpConfiguration معرفی کنید.
»عملیات Routing مورد نظر را ایجاد و سپس config مورد نظر را در اختیار appBuilder قرار دهید.
public class Startup { public void Configuration( IAppBuilder appBuilder ) { var container = new WindsorContainer(); container.Install(new KernelInstaller()); var config = new HttpConfiguration { DependencyResolver = new ApiDependencyResolver(container) }; config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "Default" , routeTemplate: "{controller}/{action}/{name}" , defaults: new { name = RouteParameter.Optional } ); config.EnsureInitialized(); appBuilder.UseWebApi( config ); } }