注意:我还不能确定这个问题(这太新了),但我会用50分给出一个很好的答案,并给出100分的好答案(如果可能的话).
我需要将DI合并到我的Web API项目中.我目前有预期的Model和Controller文件夹/类,以及相应的Repository类.
这似乎工作了一段时间,但现在我需要使用DI与控制器,以便我可以将接口类型传递给控制器的构造函数.
我正在努力解决如何实施这个问题;也就是说,如何将DI“extravaganza”整合到我现有的Model / Controller / Repository结构中.我有示例DI代码,但我不知道它应该如何应用于我的项目.
也许有些代码是为了试图明确这一点.我将展示一个我所得到的简单示例,然后是DI代码我想以某种方式合并到它/它.
这是现有的模型/控制器/存储库代码:
模型
public class Department { public int Id { get; set; } public int AccountId { get; set; } public string Name { get; set; } }
CONTROLLER
public class DepartmentsController : ApiController { private readonly IDepartmentRepository _deptsRepository; public DepartmentsController(IDepartmentRepository deptsRepository) { if (deptsRepository == null) { throw new ArgumentNullException("deptsRepository is null"); } _deptsRepository = deptsRepository; } public int GetCountOfDepartmentRecords() { return _deptsRepository.Get(); } public IEnumerable<Department> GetBatchOfDepartmentsByStartingID(int ID,int CountToFetch) { return _deptsRepository.Get(ID,CountToFetch); } public void PostDepartment(int accountid,string name) { _deptsRepository.PostDepartment(accountid,name); } public HttpResponseMessage Post(Department department) { // Based on code 2/3 down http://www.codeproject.com/Articles/344078/ASP-NET-WebAPI-Getting-Started-with-MVC4-and-WebAP?msg=4727042#xx4727042xx department = _deptsRepository.Add(department); var response = Request.CreateResponse<Department>(HttpStatusCode.Created,department); string uri = Url.Route(null,new { id = department.Id }); response.Headers.Location = new Uri(Request.RequestUri,uri); return response; }
REPOSITORY
public class DepartmentRepository : IDepartmentRepository { private readonly List<Department> departments = new List<Department>(); public DepartmentRepository() { using (var conn = new OleDbConnection( @"Provider=Microsoft.ACE.OLEDB.12.0;User ID=BlaBlaBla... { using (var cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT td_department_accounts.dept_no,IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name FROM t_accounts INNER JOIN td_department_accounts ON t_accounts.account_no = td_department_accounts.account_no ORDER BY td_department_accounts.dept_no"; cmd.CommandType = CommandType.Text; conn.Open(); int i = 1; using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader()) { while (oleDbD8aReader != null && oleDbD8aReader.Read()) { int deptNum = oleDbD8aReader.GetInt16(0); string deptName = oleDbD8aReader.GetString(1); Add(new Department { Id = i,AccountId = deptNum,Name,deptName }); i++; } } } } } public int Get() { return departments.Count; } private Department Get(int ID) // called by Delete() { return departments.First(d => d.Id == ID); } public IEnumerable<Department> Get(int ID,int CountToFetch) { return departments.Where(i => i.Id > ID).Take(CountToFetch); } public Department Add(Department dept) { if (dept == null) { throw new ArgumentNullException("Department arg was null"); } // This is called internally,so need to disregard Id vals that already exist if (dept.Id <= 0) { int maxId = departments.Max(d => d.Id); dept.Id = maxId + 1; } if (departments != null) departments.Add(dept); return dept; } public void PostDepartment(int accountid,string name) { int maxId = departments.Max(d => d.Id); Department dept = new Department(); dept.Id = maxId + 1; dept.AccountId = accountid; dept.Name = name; departments.Add(dept); } public void Post(Department department) { int maxId = departments.Max(d => d.Id); department.Id = maxId + 1; departments.Add(department); } public void Put(Department department) { int index = departments.ToList().FindIndex(p => p.Id == department.Id); departments[index] = department; } public void Put(int id,Department department) { int index = departments.ToList().FindIndex(p => p.Id == id); departments[index] = department; } public void Delete(int id) { Department dept = Get(id); departments.Remove(dept); }
现在这里是我想要合并的DI代码
DIInstallers文件夹中的类:
IDepartmentProvider.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace HandheldServer.DIInstallers { public interface IDepartmentProvider { // These are the methods that are in the sample example IAuthProvider interface; I don't know what I need yet,though... //bool Authenticate(string username,string password,bool createPersistentCookie); //void SignOut(); } }
DepartmentProvider.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace HandheldServer.DIInstallers { public class DepartmentProvider : IDepartmentProvider { // TODO: Implement methods in IDepartmentProvider,once they have been added } }
DepartmentProviderInstaller.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Castle.MicroKernel.Registration; using Castle.MicroKernel.SubSystems.Configuration; using Castle.Windsor; namespace HandheldServer.DIInstallers { public class DepartmentProviderInstaller : IWindsorInstaller { public void Install(IWindsorContainer container,IConfigurationStore store) { container.Register(Classes.FromThisAssembly() .BasedOn(typeof(IDepartmentProvider)) .WithServiceAllInterfaces()); // If I declare/implement more interface types (other than IDepartmentProvider),I assume there would be another container.Register() call for each of them? } } }
DIPlumbing文件夹中的类:
WindsorCompositionRoot.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Castle.Windsor; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; namespace HandheldServer.DIPlumbing { public class WindsorCompositionRoot : IHttpControllerActivator { private readonly IWindsorContainer container; public WindsorCompositionRoot(IWindsorContainer container) { this.container = container; } public IHttpController Create( HttpRequestMessage request,HttpControllerDescriptor controllerDescriptor,Type controllerType) { var controller = (IHttpController)this.container.Resolve(controllerType); request.RegisterForDispose( new Release( () => this.container.Release(controller))); return controller; } private class Release : IDisposable { private readonly Action release; public Release(Action release) { this.release = release; } public void Dispose() { this.release(); } } } }
WindsorControllerFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using Castle.MicroKernel; namespace HandheldServer.DIPlumbing { public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKernel kernel; public WindsorControllerFactory(IKernel kernel) { this.kernel = kernel; } public override void ReleaseController(IController controller) { kernel.ReleaseComponent(controller); } protected override IController GetControllerInstance(RequestContext requestContext,Type controllerType) { if (controllerType == null) { throw new HttpException(404,string.Format("The controller for path '{0}' could not be found.",requestContext.HttpContext.Request.Path)); } return (IController)kernel.Resolve(controllerType); } } }
Global.asax.cs文件
using System; using System.Reflection; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using Castle.Windsor; using Castle.Windsor.Installer; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security; using System.Web.Http.Dispatcher; using HandheldServer.DIPlumbing; namespace HandheldServer { public class WebApiApplication : System.Web.HttpApplication { private static IWindsorContainer container; protected void Application_Start() { BootstrapContainer(); AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } // Code that runs when an unhandled error occurs void Application_Error(object sender,EventArgs e) { // Get the exception object. Exception exc = Server.GetLastError(); log.Error(exc.Message); // Clear the error from the server Server.ClearError(); } private static void BootstrapContainer() { container = new WindsorContainer().Install(FromAssembly.This()); var controllerFactory = new WindsorControllerFactory(container.Kernel); ControllerBuilder.Current.SetControllerFactory(controllerFactory); GlobalConfiguration.Configuration.Services.Replace( typeof(IHttpControllerActivator),new WindsorCompositionRoot(container)); } protected void Application_End() { container.Dispose(); } } }
所以,我认为我基本上已经得到了我需要的代码,但是如何将DI代码折叠到我之前的(模型/控制器/存储库)代码中是我难以理解的部分.