65.9K
CodeProject 正在变化。 阅读更多。
Home

在 OpenAccess ORM MVC 项目上使用依赖注入

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2013年12月15日

CPOL

4分钟阅读

viewsIcon

11928

在 OpenAccess ORM MVC 项目上使用依赖注入

引言

你可能正在使用OpenAccess ORM启动一个新项目,并想知道如何实现依赖注入以防止硬编码依赖项并使在运行时更改它们成为可能。这其实并不难,特别是现在有了新的依赖注入框架,你只需要在Nuget上获取它们,将其引用到你的项目中,然后就可以使用了。

我会尽可能简单地解释这一点,我将首先解释我的示例架构,首先定义我使用的不同层。我们还将关注一个名为Departments的数据库表。让我们开始吧。

假设你的架构目前简单地由4层组成,即

  • 领域层(Domain)– 包含你的业务对象的模型。
  • 基础设施层(Infrastructure)– 包含你在数据访问层上添加的抽象层。
  • Web层 – 这是你的表示层。
  • 测试层(Tests)– 我想我不需要解释这个。

01 Overview

对于领域层,我们不需要编码,因为Telerik 为你生成了所有内容,所以让我们直接进入基础设施层。让我们关注4个文件

Repository.cs – 此文件包含你的泛型存储库代码,用于从你的领域提取和/或处理信息

using EmployeesDemo.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;

namespace EmployeesDemo.Infrastructure.Repositories
{
    public abstract class Repository<T> : IDisposable, IRepository<T>
        where T : class
    {
        protected IEntitiesModelUnitOfWork Context
        {
            get;
            private set;
        }

        protected Repository(IEntitiesModelUnitOfWork context)
        {
            this.Context = context;
        }

        public IList GetAll()
        {
            return this.Context.GetAll().ToList();
        }

        public T Find(Expression<Func<T, bool>> predicate)
        {
            return this.Context.GetAll().FirstOrDefault(predicate);
        }

        public void Add(T order)
        {
            this.Context.Add(order);
        }

        public void Remove(T order)
        {
            this.Context.Delete(order);
        }

        public void Dispose()
        {
            this.Context = null;
        }
    }
}

IRepository.cs – 你的Repository.cs的接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;

namespace EmployeesDemo.Infrastructure.Repositories
{
    public interface IRepository<T>
        where T : class
    {
        T Find(Expression<Func<T, bool>> predicate);

        void Add(T order);
        IList GetAll();
        void Remove(T order);
    }
}

DepartmentRepository.cs – 此文件仅包含Department实体的抽象,如果是泛型方法,则应将其放在Repository.cs

using EmployeesDemo.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EmployeesDemo.Infrastructure.Repositories
{
    public class DepartmentRepository : Repository<Department>, IDepartmentRepository
    {
        public DepartmentRepository(IEntitiesModelUnitOfWork context)
            : base(context)
        {
        }

        public Department GetBy(string name)
        {
            return this.Context.GetAll<Department>().FirstOrDefault(x => x.Name == name);
        }
    }
}

IDepartmentRepository.cs – 这是DepartmentRepository的接口。

using EmployeesDemo.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EmployeesDemo.Infrastructure.Repositories
{
    public interface IDepartmentRepository : IRepository<Department>
    {
        Department GetBy(string name);
    }
}

现在让我们进入表示层,首先我们定义一个视图模型,我们最终将在我们的控制器和视图中使用它。

DepartmentsViewModel.cs – 基本上是所有Departments列表的模型。

using EmployeesDemo.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EmployeesDemo.Web.Models
{
    public class DepartmentsViewModel
    {
        public DepartmentsViewModel()
        {
            this.Departments = new List<Department>();
        }
        public IList<Department> Departments { get; set; }
    }
}

DepartmentViewModel.cs – 用于单个Department的模型

using EmployeesDemo.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EmployeesDemo.Web.Models
{
    public class DepartmentViewModel
    {
        public string Name { get; set; }

        public string Description { get; set; }
    }
}

DepartmentService.cs – 现在,这是用于与你的存储库通信的类

using EmployeesDemo.Web.Models;
using EmployeesDemo.Infrastructure.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EmployeesDemo.Web.Services
{
    public class DepartmentService
    {
        private readonly IDepartmentRepository departmentRepository;
        public DepartmentService(
            IDepartmentRepository departmentRepository)
        {
            this.departmentRepository = departmentRepository;
        }

        public DepartmentsViewModel GetAll()
        {
            return new DepartmentsViewModel
            {
                Departments = departmentRepository.GetAll().ToList()
            };
        }

        public DepartmentViewModel GetBy(string name)
        {
            var department = departmentRepository.GetBy(name);
            return new DepartmentViewModel
            {
                Name = department.Name
            };
        }
    }
}

HomeController.cs – 此控制器控制主页视图,在这里我们将使用我们需要的服务,在这种情况下是Department服务。创建构造函数后,我们现在可以在代码中使用这些服务了。

using EmployeesDemo.Web.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EmployeesDemo.Web.Controllers
{
    public class HomeController : Controller
    {
        public DepartmentService departmentService;

        public HomeController(
            DepartmentService departmentService)
        {
            this.departmentService = departmentService;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            var technologyDepartment = departmentService.GetBy("Technology");
            var allDepartment = departmentService.GetAll();

            return View();
        }
    }
}

但是不要运行它,虽然它可以无错误地编译,但在运行时你会收到此错误。

'/' 应用程序中的服务器错误。


为此对象未定义无参数构造函数。

说明:在执行当前 Web 请求期间发生未经处理的异常。请查看堆栈跟踪,了解有关错误以及其在代码中源自何处的更多信息。

异常详细信息:System.MissingMethodException:为此对象未定义无参数构造函数。

源错误

在执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪识别有关异常的来源和位置的信息。

为什么???这是因为默认情况下,ASP.NET MVC 要求控制器具有一个public无参数构造函数,从而创建控制器的实例。因此,在我们的示例中,我们的构造函数需要DepartmentService实例,我们需要一些东西将此实例传递给我们的控制器。现在你需要依赖注入框架,你可以选择很多选项,例如UnityCastle.WindsorAutofacStructureMap等。我之前使用过Castle.Windsor,并且对此没有任何抱怨,但现在让我们使用Ninject

现在要做到这一点,首先你需要在nuget中下载它。只需搜索Ninject并安装Ninject.MVC3即可,我之所以这么说,是因为这更容易,因为它的依赖项是另外两个,所以它也会自动安装它们。

02 Add Ninject

安装完成后,我们需要创建一个NinjectModule并让ninject为你粘合在一起。我所做的是创建一个名为IoC的文件夹,在这个文件夹中,我们创建一个名为ControllerModule的类。

07 IoC

现在让我们进行绑定

using EmployeesDemo.Domain;
using EmployeesDemo.Infrastructure.Repositories;
using EmployeesDemo.Web.Services;
using Ninject.Modules;
using Ninject.Web.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EmployeesDemo.Web.IoC
{
    public class ControllerModule : NinjectModule
    {
        public override void Load()
        {
            this.Bind<IEntitiesModelUnitOfWork>().To<EntitiesModel>()
                .InRequestScope()
                .WithConstructorArgument
                ("connectionId", "TestingDatabaseConnection");

            this.Bind<IDepartmentRepository>().To<DepartmentRepository>()
                .InRequestScope();

            this.Bind<DepartmentService>().To<DepartmentService>()
                .InRequestScope();
        }
    }
}

现在,我们完成了绑定。让我们修改我们的Global.asax,以便所有内容都在ApplicationStart注册。首先让我们继承NinjectHttpApplication并替换默认的HttpApplication

04 Inherit NinjectHttpApplication

接下来替换……

void Application_Start()

为……

override void OnApplicationStarted()

然后调用……

base.OnApplicationStarted();

我们还需要重写NinjectHttpApplicationCreateKernel方法

protected override IKernel CreateKernel()
{
    IKernel kernel = new StandardKernel();
    kernel.Load(Assembly.GetExecutingAssembly());

    return kernel;
}

05 Overrides

最后,由于我们在Global.asax中创建了它,因此我们不需要在App_Start文件夹中创建的名为NinjectWebCommon.cs的ninject生成的代码,因此请删除它们。

03 Ninject Generated

现在你可以开始了。运行你的应用程序,然后查看结果。

06 Results

归档于:架构CodeProject编程标签:ASP.NET MVCC#依赖注入依赖注入框架MVCninject

© . All rights reserved.