Asp.net MVC系列教程4——Spring IOC、DI

作者 Guanghui Wang 日期 2017-02-16

简述

本文转自http://yuangang.cnblogs.com并加以整理。 本文用到了Spring的IOC和DI、接口的使用、实现

索引

Asp.net MVC项目系列教程

项目开始

一、IOC和DI

  • Ioc:Inversion of Control,即“控制反转”,是一种设计思想。
  • 传统的设计思想是在对象内部直接控制,而IOC是将设计好的对象交给容器控制。

    打个比方:我们租房子,在我们和房主之间插入了一个中间人(房介),我们只需要跟房介提出我们的要求,比如房子要三室一厅、卧室向阳、房东是女的等,房介就会按照我们的要求提供房产信息。我们满意就入住,如果我们不满意(抛出异常),房介就会帮我们做后续处理。整个过程不再是由我们控制,而是由房介这么一个容器去控制。所有的类都会在spring容器中登记,告诉spring你是谁,你需要什么,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

  • DI: IOC的一个重点是在系统运行中,动态地向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

    比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? 有一个重要特征是反射reflection,它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

二、用户管理的接口和实现

  1. 首先在Service类库下面创建两个文件夹 IService(存放接口)、ServiceImp(实现类),并且在这两个文件夹下面再分别建两个文件夹ComManage和SysManage,用于区分管理我们的接口和实现类。

  2. 我们创建系统管理用户SYS_USER的接口:右击IService/SysManage→添加→新建项→接口,IUserManage.cs。SysManage只是我们为了区分管理我们的接口文件,我们修改一下命名空间,让他们统一在Service.IService空间下,并且继承基础数据操作接口IRepository。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    namespace Service.IService
    {
    public interface IUserManage : IRepository<Domain.SYS_USER>
    {
    /// <summary>
    /// 管理用户登录验证,并返回用户信息与权限集合
    /// </summary>
    /// <param name="username">用户账号</param>
    /// <param name="password">用户密码</param>
    /// <returns></returns>
    Domain.SYS_USER UserLogin(string useraccount, string password);
    /// <summary>
    /// 是否超级管理员
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns></returns>
    bool IsAdmin(int userId);
    /// <summary>
    /// 根据用户ID获取用户名,不存在返回空
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns></returns>
    string GetUserName(int userId);
    }
    }
  3. 创建用户接口的实现类:右击ServiceImp/SysManage→添加→类UserManage.cs。同样,我们修改一下命名空间,让他们统一在Service.ServiceImp空间下,并且继承基础数据操作类RepositoryBase和他的接口IUserManage.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    using Service.IService;
    using System.Linq;

    namespace Service.ServiceImp
    {
    public class UserManage : RepositoryBase<Domain.SYS_USER>, IUserManage
    {
    /// <summary>
    /// 管理用户登录验证
    /// </summary>
    /// <param name="userAccount">用户名</param>
    /// <param name="password">加密密码(AES)</param>
    /// <returns></returns>
    public Domain.SYS_USER UserLogin(string userAccount, string password)
    {
    var entity = this.Get(p => p.ACCOUNT == userAccount);

    //因为我们用的是AES的动态加密算法,也就是没有统一的密钥,那么两次同样字符串的加密结果是不一样的,所以这里要通过解密来匹配
    //而不能通过再次加密输入的密码来匹配
    if (entity != null && new Common.CryptHelper.AESCrypt().Decrypt(entity.PASSWORD) == password)
    {
    return entity;
    }
    return null;
    }

    /// <summary>
    /// 是否超级管理员
    /// </summary>
    public bool IsAdmin(int userId)
    {
    //这里我们还没有做用户角色 所以先返回个True,后面我们做角色的时候再回来修改
    return true;
    }

    /// <summary>
    /// 根据用户ID获取用户名
    /// </summary>
    /// <param name="Id">用户ID</param>
    /// <returns></returns>
    public string GetUserName(int Id)
    {
    var query = this.LoadAll(c => c.ID == Id);
    if (query == null || !query.Any())
    {
    return "";
    }
    return query.First().NAME;
    }
    }
    }

三、添加引用并配置spring启动

  1. 在Webpage项目中使用nuget添加spring.web.mvc5,会在项目引用中添加Spring.Core, Spring.Web, Spring.Web.Mvc5, Common.Logging, Common.Logging.Core
  2. 修改Global.asax的MvcApplication类继承于Spring.Web.Mvc.SpringMvcApplication

四、Spring配置

  1. 在Service类库下面新建一个文件夹Config用于存放注入文件,在Config文件夹下面新建两个XML文件ComService.xml和Service.xml

  2. 我们把这两个文件属性的生成操作修改为嵌入的资源:分别右击这两个XML文件→属性→生成操作→嵌入的资源。这样在编译生成时会把文件放在bin目录中。

  3. 移步操作WebPage,新建文件夹Config,新建3个XML文件并更改文件属性的生成操作修改为嵌入的资源(同上):

    • ComControllers.xml:后台管理Com控制器
    • Controllers.xml:后台管理Sys控制器
    • IndexControllers.xml:网站前台控制器

      note1: 如果忘记潜入资源,会报错:

      note2: 注意以上xml文件至少写上

      1
      2
      3
      <?xml version="1.0" encoding="utf-8" ?>
      <objects xmlns="http://www.springframework.net">
      </objects>

      如果只有<?xml version="1.0" encoding="utf-8" ?>可能报错:

  4. 修改一下WebPage的Web.Config,声明一下Spring容器和配置指向,注意他们的位置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <sectionGroup name="spring">
    <!--Spring声明容器-->
    <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc5" />
    <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
    </configSections>
    <!--Spring配置指向-->
    <spring>
    <context>
    <!--WebPage-->
    <resource uri="assembly://WebPage/WebPage.Config/IndexControllers.xml" />
    <resource uri="assembly://WebPage/WebPage.Config/Controllers.xml" />
    <resource uri="assembly://WebPage/WebPage.Config/ComControllers.xml" />
    <!--Service-->
    <resource uri="assembly://Service/Service.Config/Service.xml" />
    <resource uri="assembly://Service/Service.Config/ComService.xml" />
    </context>
    </spring>
    <!--Spring配置指向 end-->

五、Spring容器的配置注入

Service类库Config/service.xml: 因为我们创建的用户表是管理员表,所以把这个配置放到Service.xml里

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<description>Spring注入Service,容器指向本层层封装的接口,舍弃Dao层,减少代码量</description>
<!--系统管理begin-->
<!--用户管理-->
<object id="Service.User" type="Service.ServiceImp.UserManage,Service" singleton="false">
</object>
<!--系统管理end-->
</objects>