ASP.NET MVC 4 依赖项注入

Web Camp 团队

下载 Web Camp 培训工具包

本动手实验室假设你对 ASP.NET MVC 和 ASP.NET MVC 4 筛选器有基本的了解 如果以前未使用 过 ASP.NET MVC 4 筛选器 ,建议你 ASP.NET MVC 自定义操作筛选器 动手实验室。

注意

所有示例代码和代码片段都包含在 Web Camp 培训工具包中,可从 Microsoft-Web/WebCampTrainingKit 版本获取。 特定于此实验室的项目可在 ASP.NET MVC 4 依赖项注入中使用

面向对象的编程 范例中,对象在具有参与者和使用者的协作模型中协同工作。 自然,此通信模型会生成对象和组件之间的依赖关系,在复杂性增加时变得难以管理。

类依赖项和模型复杂性

类依赖项和模型复杂性

你可能听说过 工厂模式 以及使用服务实现的接口与实现之间的分离,其中客户端对象通常负责服务位置。

依赖关系注入模式是控制反转的特定实现。 控制反转(IoC) 意味着对象不会创建它们依赖的其他对象来执行其工作。 相反,它们从外部源(例如 xml 配置文件)获取所需的对象。

依赖关系注入(DI) 表示,这是在没有对象干预的情况下完成的,通常是由传递构造函数参数和设置属性的框架组件完成的。

依赖关系注入 (DI) 设计模式

在高级别上,依赖关系注入的目标是客户端类(例如 高尔夫球手)需要满足接口(例如 IClub)的内容。 它并不关心具体类型是什么(例如 WoodClub、IronClub、WedgeClubPutterClub),它希望其他人处理这一点(例如一个很好的 球童)。 ASP.NET MVC 中的依赖关系解析程序可以让你在其他位置(例如容器或 俱乐部包)注册依赖项逻辑。

依赖关系注入关系图

依赖关系注入 - 高尔夫类比

使用依赖关系注入模式和控制反转的优点如下:

  • 减少类耦合
  • 增加代码重用
  • 提高代码可维护性
  • 改进应用程序测试

注意

依赖项注入有时与抽象工厂设计模式进行比较,但两种方法之间略有不同。 DI 有一个框架,通过调用工厂和注册的服务来解决依赖项。

了解依赖项注入模式后,你将在整个实验室中了解如何在 MVC 4 ASP.NET 中应用它。 你将开始使用控制器中的依赖关系注入来包含数据库访问服务。 接下来,将依赖项注入应用到 视图 以使用服务并显示信息。 最后,将 DI 扩展到 ASP.NET MVC 4 筛选器,并在解决方案中注入自定义操作筛选器。

在此动手实验室中,你将了解如何:

  • 使用 NuGet 包将 ASP.NET MVC 4 与 Unity 集成,以便进行依赖项注入
  • 在 ASP.NET MVC 控制器中使用依赖关系注入
  • 在 ASP.NET MVC 视图中使用依赖关系注入
  • 在 ASP.NET MVC 操作筛选器中使用依赖关系注入

注意

此实验室使用 Unity.Mvc3 NuGet 包进行依赖项解析,但可以调整任何依赖项注入框架来处理 ASP.NET MVC 4。

先决条件

必须具有以下项才能完成此实验室:

安装

安装代码片段

为方便起见,你将在此实验室中管理的大部分代码都可用作 Visual Studio 代码片段。 若要安装代码片段,请运行 .\Source\Setup\CodeSnippets.vsi 文件。

如果你不熟悉 Visual Studio Code 代码片段,并且想要了解如何使用它们,则可以参考本文档中的附录“附录 B:使用代码片段”。


练习

此动手实验室由以下练习组成:

  1. 练习 1:注入控制器
  2. 练习 2:注入视图
  3. 练习 3:注入筛选器

注意

每个练习都附带一个 End 文件夹,其中包含在完成练习后应获取的结果解决方案。 如果需要完成练习的其他帮助,可以使用此解决方案作为指南。

估计完成此实验室的时间: 30 分钟

练习 1:注入控制器

在本练习中,你将了解如何使用 NuGet 包集成 Unity,在 ASP.NET MVC 控制器中使用依赖关系注入。 因此,你将将服务包含在 MvcMusicStore 控制器中,以便将逻辑与数据访问分开。 服务将在控制器构造函数中创建一个新的依赖项,该构造函数将在 Unity 的帮助下使用依赖关系注入来解决。

此方法将演示如何生成不太耦合的应用程序,这些应用程序更灵活、更易于维护和测试。 还将了解如何将 ASP.NET MVC 与 Unity 集成。

关于 StoreManager 服务

开始解决方案中提供的 MVC Music Store 现在包含一项服务,用于管理名为 StoreService 的应用商店控制器数据。 下面将找到 Microsoft Store Service 实现。 请注意,所有方法都返回 Model 实体。

namespace MvcMusicStore.Controllers
{    
    using System.Web.Mvc;
    using MvcMusicStore.Filters;
    using MvcMusicStore.Services;

    [MyNewCustomActionFilter(Order = 1)]
    [CustomActionFilter(Order = 2)]
    public class StoreController : Controller
    {
        private IStoreService service;

        public StoreController(IStoreService service)
        {
            this.service = service;
        }

        // GET: /Store/
        public ActionResult Details(int id)
        {
            var album = this.service.GetAlbum(id);
            if (album == null)
            {
                return this.HttpNotFound();
            }

            return this.View(album);
        }

        public ActionResult Browse(string genre)
        {
            // Retrieve Genre and its Associated Albums from database
            var genreModel = this.service.GetGenreByName(genre);

            return this.View(genreModel);
        }

        public ActionResult Index()
        {
            var genres = this.service.GetGenres();

            return this.View(genres);
        }

        // GET: /Store/GenreMenu
        public ActionResult GenreMenu()
        {
            var genres = this.service.GetGenres();

            return this.PartialView(genres);
        }
    }
}

开始解决方案中的 StoreController 现在使用 StoreService。 所有数据引用都已从 StoreController 中删除,现在可以修改当前数据访问提供程序,而无需更改任何使用 StoreService 的方法。

下面将发现 StoreController 实现在类构造函数中具有 StoreService 的依赖项。

注意

本练习中引入的依赖项与 控制 反转(IoC)相关。

StoreController 类构造函数接收 IStoreService 类型参数,这对于从类内部执行服务调用至关重要。 但是, StoreController 不实现任何控制器必须使用 ASP.NET MVC 的默认构造函数(无参数)。

若要解析依赖项,控制器必须由抽象工厂创建(返回指定类型的任何对象的类)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcMusicStore.ViewModels;
using MvcMusicStore.Models;
using MvcMusicStore.Services;

namespace MvcMusicStore.Controllers
{
    public class StoreController : Controller
    {
        private IStoreService service;

        public StoreController(IStoreService service)
        {
            this.service = service;
        }

        //
        // GET: /Store/
        public ActionResult Index()
        {
            // Create list of genres
            var genres = this.service.GetGenreNames();

            // Create your view model
            var viewModel = new StoreIndexViewModel
            {
                Genres = genres.ToList(),
                NumberOfGenres = genres.Count()
            };

            return View(viewModel);
        }

        //
        // GET: /Store/Browse?genre=Disco
        public ActionResult Browse(string genre)
        {
            var genreModel = this.service.GetGenreByName(genre);

            var viewModel = new StoreBrowseViewModel()
            {
                Genre = genreModel,
                Albums = genreModel.Albums.ToList()
            };

            return View(viewModel);
        }

        //
        // GET: /Store/Details/5
        public ActionResult Details(int id)
        {
            var album = this.service.GetAlbum(id);

            return View(album);
        }
    }
}

注意

类尝试创建 StoreController 而不发送服务对象时会收到错误,因为未声明无参数构造函数。

任务 1 - 运行应用程序

在此任务中,将运行 Begin 应用程序,其中包括服务到存储控制器中,该控制器将数据访问与应用程序逻辑分开。

运行应用程序时,将收到异常,因为控制器服务默认未作为参数传递:

  1. 打开 Source\Ex01-Injecting Controller\Begin 中的 Begin 解决方案。

    1. 在继续之前,需要下载一些缺少的 NuGet 包。 为此,请单击“项目”菜单,然后选择“管理 NuGet 包”。

    2. 在“管理 NuGet 包”对话框中,单击“还原以下载缺少的包。

    3. 最后,通过单击“生成 | 生成解决方案”生成解决方案来生成解决方案。

      注意

      使用 NuGet 的优点之一是无需交付项目中的所有库,从而减少项目大小。 借助 NuGet Power Tools,通过在 Packages.config 文件中指定包版本,可以在首次运行项目时下载所有必需的库。 因此,在从此实验室打开现有解决方案后,必须运行这些步骤。

  2. Ctrl + F5 在不调试的情况下运行应用程序。 将收到错误消息“没有为此对象定义无参数构造函数”:

    运行 ASP.NET MVC Begin 应用程序时出错

    运行 ASP.NET MVC Begin 应用程序时出错

  3. 关闭浏览器。

在以下步骤中,你将使用音乐应用商店解决方案来注入此控制器所需的依赖项。

任务 2 - 将 Unity 包括在 MvcMusicStore 解决方案中

在此任务中,你将将 Unity.Mvc3 NuGet 包包含在解决方案中。

注意

Unity.Mvc3 包专为 ASP.NET MVC 3 而设计,但它与 ASP.NET MVC 4 完全兼容。

Unity 是一个轻型可扩展依赖项注入容器,支持实例和类型截获的可选支持。 它是用于任何类型的 .NET 应用程序的常规用途容器。 它提供依赖项注入机制中找到的所有常见功能,包括:对象创建、在运行时指定依赖项和灵活性来抽象要求,方法是将组件配置推迟到容器。

  1. MvcMusicStore 项目中安装 Unity.Mvc3 NuGet 包。 为此,请从“查看 | 其他 Windows”打开程序包管理器控制台

  2. 运行以下命令。

    PMC

    Install-Package Unity.Mvc3
    

    安装 Unity.Mvc3 NuGet 包

    安装 Unity.Mvc3 NuGet 包

  3. 安装 Unity.Mvc3 包后,浏览自动添加的文件和文件夹以简化 Unity 配置。

    已安装的 Unity.Mvc3 包

    已安装的 Unity.Mvc3 包

任务 3 - 在 Global.asax.cs Application_Start 中注册 Unity

在此任务中,你将更新位于 Global.asax.cs 中的 Application_Start 方法以调用 Unity Bootstrapper 初始值设定项,然后更新注册用于依赖关系注入服务和控制器的 Bootstrapper 文件。

  1. 现在,你将挂钩 Bootstrapper,它是初始化 Unity 容器和依赖项解析程序的文件。 为此,请打开Global.asax.cs并在 Application_Start 方法中添加以下突出显示的代码。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex01 - 初始化 Unity

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
    
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    
        Bootstrapper.Initialise();
    
        AppConfig.Configure();
    }
    
  2. 打开 Bootstrapper.cs 文件。

  3. 包括以下命名空间: MvcMusicStore.ServicesMusicStore.Controllers

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex01 - 引导程序添加命名空间

    using System.Web.Mvc;
    using Microsoft.Practices.Unity;
    using Unity.Mvc3;
    using MvcMusicStore.Services;
    using MvcMusicStore.Controllers;
    
  4. 将 BuildUnityContainer 方法的内容替换为注册 Store Controller 和 Store Service 的以下代码。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex01 - 注册存储控制器和服务

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
    
        container.RegisterType<IStoreService, StoreService>();
        container.RegisterType<IController, StoreController>("Store");
    
        return container;
    }
    

任务 4 - 运行应用程序

在此任务中,你将运行应用程序,以验证它现在可以在包括 Unity 之后加载它。

  1. F5 运行应用程序,应用程序现在应加载而不显示任何错误消息。

    使用依赖关系注入运行应用程序

    使用依赖关系注入运行应用程序

  2. 浏览到 /Store。 这将调用现在使用 Unity 创建的 StoreController

    MVC 音乐商店

    MVC 音乐商店

  3. 关闭浏览器。

在以下练习中,你将了解如何扩展依赖关系注入范围,使其在 ASP.NET MVC 视图和操作筛选器中使用。

练习 2:注入视图

在本练习中,你将了解如何在视图中使用依赖项注入,以及用于 Unity 集成的 ASP.NET MVC 4 的新功能。 为此,你将在应用商店浏览视图中调用自定义服务,该服务将显示一条消息和下图。

然后,将项目与 Unity 集成,并创建自定义依赖项解析程序来注入依赖项。

任务 1 - 创建使用服务的视图

在此任务中,你将创建一个视图,该视图执行服务调用以生成新的依赖项。 该服务由此解决方案中包含的简单消息传送服务组成。

  1. 打开 Source\Ex02-Injecting View\Begin 文件夹中的 Begin 解决方案。 否则,可以继续使用 通过完成上一练习获得的 End 解决方案。

    1. 如果打开提供的 Begin 解决方案,则需要先下载一些缺少的 NuGet 包,然后再继续。 为此,请单击“项目”菜单,然后选择“管理 NuGet 包”。

    2. 在“管理 NuGet 包”对话框中,单击“还原以下载缺少的包。

    3. 最后,通过单击“生成 | 生成解决方案”生成解决方案来生成解决方案。

      注意

      使用 NuGet 的优点之一是无需交付项目中的所有库,从而减少项目大小。 借助 NuGet Power Tools,通过在 Packages.config 文件中指定包版本,可以在首次运行项目时下载所有必需的库。 因此,在从此实验室打开现有解决方案后,必须运行这些步骤。

      有关详细信息,请参阅本文: https://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages

  2. 在 /Services 的“源 \Assets”文件夹中包括MessageService.csIMessageService.cs 为此,请 右键单击“服务 ”文件夹,然后选择“ 添加现有项”。 浏览到文件的位置并包含这些文件。

    添加消息服务和服务接口

    添加消息服务和服务接口

    注意

    IMessageService 接口定义由 MessageService 类实现的两个属性。 这些属性 -MessageImageUrl- 存储要显示的图像的消息和 URL。

  3. 在项目的根文件夹中创建文件夹 /Pages,然后从 Source\Assets 添加现有类MyBasePage.cs。 要继承的基页具有以下结构。

    Pages 文件夹

    namespace MvcMusicStore.Pages
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Web;
        using Microsoft.Practices.Unity;
        using MvcMusicStore.Models;
        using MvcMusicStore.Services;
    
        public class MyBasePage : System.Web.Mvc.WebViewPage<Genre>
        {
            [Dependency]
            public IMessageService MessageService { get; set; }
    
            public override void 
    
            Execute()
            {
            }
        }
    }
    
  4. /Views/Store 文件夹中打开 Browse.cshtml 视图,并将其从MyBasePage.cs继承。

    @inherits MvcMusicStore.Pages.MyBasePage
    @{
         ViewBag.Title = "Browse Albums";
    }
    
  5. “浏览”视图中,添加对 MessageService调用以显示服务检索的图像和消息。 (C#)

    @inherits MvcMusicStore.Pages.MyBasePage    
    @{
        Viewbag.Title = "Browse Albums";
    }
    <div>
        @this.MessageService.Message
        <br />
        <img alt="@this.MessageService.Message" src="@this.MessageService.ImageUrl" />
    </div>
    ...
    

任务 2 - 包括自定义依赖项解析程序和自定义视图页面激活器

在上一个任务中,你在视图中注入了一个新的依赖项,以在视图中执行服务调用。 现在,你将通过实现 ASP.NET MVC 依赖关系注入接口 IViewPageActivatorIDependencyResolver 来解决该依赖项。 你将在解决方案中包含 IDependencyResolver实现,该实现将使用 Unity 来处理服务检索。 然后,你将包含 IViewPageActivator 接口的另一个自定义实现,该接口将解决视图的创建问题。

注意

由于 ASP.NET MVC 3,依赖项注入的实现简化了用于注册服务的接口。 IDependencyResolverIViewPageActivator 是依赖项注入的 ASP.NET MVC 3 功能的一部分。

- IDependencyResolver 接口替换以前的 IMvcServiceLocator。 IDependencyResolver 的实现者必须返回服务或服务集合的实例。

public interface IDependencyResolver {
    object GetService(Type serviceType);
    IEnumerable<object> GetServices(Type serviceType);
}

- IViewPageActivator 接口提供更精细的控制,可更精细地控制如何通过依赖项注入实例化视图页。 实现 IViewPageActivator 接口的类可以使用上下文信息创建视图实例。

public interface IViewPageActivator {
    object Create(ControllerContext controllerContext, Type type);
}
  1. 在项目的根文件夹中创建 /Factories 文件夹。

  2. 解决方案的CustomViewPageActivator.cs/Sources/Assets/ 添加到 Factories 文件夹。 为此,请 右键单击 /Factories 文件夹,选择“ 添加” |现有项 ,然后选择 CustomViewPageActivator.cs。 此类实现 IViewPageActivator 接口来保存 Unity 容器。

    namespace MvcMusicStore.Factories
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Web;
        using System.Web.Mvc;
        using Microsoft.Practices.Unity;
    
        public class CustomViewPageActivator : IViewPageActivator
        {
            private IUnityContainer container;
    
            public CustomViewPageActivator(IUnityContainer container)
            {
                this.container = container;
            }
    
            public object Create(ControllerContext controllerContext, Type type)
            {
                return this.container.Resolve(type);
            }
        }
    }
    

    注意

    CustomViewPageActivator 负责使用 Unity 容器管理视图的创建。

  3. UnityDependencyResolver.cs文件从 /Sources/Assets 添加到 /Factories 文件夹。 为此,请 右键单击 /Factories 文件夹,选择“ 添加” |现有项 ,然后选择 UnityDependencyResolver.cs 文件。

    namespace MvcMusicStore.Factories
    {
         using System;
         using System.Collections.Generic;
         using System.Linq;
         using System.Web;
         using System.Web.Mvc;
         using Microsoft.Practices.Unity;
    
         public class UnityDependencyResolver : IDependencyResolver
         {
              private IUnityContainer container;
    
              private IDependencyResolver resolver;
    
              public UnityDependencyResolver(IUnityContainer container, IDependencyResolver resolver)
              {
                    this.container = container;
                    this.resolver = resolver;
              }
    
              public object GetService(Type serviceType)
              {
                    try
                    {
                         return this.container.Resolve(serviceType);
                    }
                    catch
                    {
                         return this.resolver.GetService(serviceType);
                    }
              }
    
              public IEnumerable<object> GetServices(Type serviceType)
              {
                    try
                    {
                         return this.container.ResolveAll(serviceType);
                    }
                    catch
                    {
                         return this.resolver.GetServices(serviceType);
                    }
              }
         }
    }
    

    注意

    UnityDependencyResolver 类是 Unity 的自定义 DependencyResolver。 在 Unity 容器中找不到服务时,将调用基本解析程序。

在以下任务中,将注册这两个实现,让模型知道服务和视图的位置。

任务 3 - 在 Unity 容器中注册依赖项注入

在此任务中,你将将所有上述所有内容放在一起,使依赖关系注入正常工作。

到目前为止,解决方案具有以下元素:

  • MyBaseClass 继承并使用 MessageService浏览视图。
  • 为服务接口声明了依赖项注入的中间类 -MyBaseClass
  • 服务 - MessageService 及其接口 IMessageService
  • Unity 的自定义依赖项解析程序 - UnityDependencyResolver - 处理服务检索。
  • 用于创建页面的视图页面激活器 - CustomViewPageActivator

若要注入 浏览 视图,现在将在 Unity 容器中注册自定义依赖项解析程序。

  1. 打开 Bootstrapper.cs 文件。

  2. 将 MessageService实例注册到 Unity 容器中以初始化服务:

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex02 - 注册消息服务

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
    
        container.RegisterType<IStoreService, StoreService>();
        container.RegisterType<IController, StoreController>("Store");
    
        container.RegisterInstance<IMessageService>(new MessageService
        {
            Message = "You are welcome to our Web Camps Training Kit!",
            ImageUrl = "/Content/Images/webcamps.png"
        });
        //...
    }
    
  3. 添加对 MvcMusicStore.Factories 命名空间的 引用。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex02 - 工厂命名空间

    using System.Web.Mvc; 
    using Microsoft.Practices.Unity; 
    using Unity.Mvc3; 
    using MvcMusicStore.Services; 
    using MvcMusicStore.Controllers; 
    using MvcMusicStore.Factories;
    
  4. 将 CustomViewPageActivator 注册 为 Unity 容器中的视图页激活器

    (代码片段 - ASP.NET 依赖关系注入实验室 - Ex02 - 注册 CustomViewPageActivator

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
    
        container.RegisterType<IStoreService, StoreService>();
        container.RegisterType<IController, StoreController>("Store");
    
        container.RegisterInstance<IMessageService>(new MessageService
        {
            Message = "You are welcome to our Web Camps Training Kit!",
            ImageUrl = "/Content/Images/webcamps.png"
        });
    
        container.RegisterType<IViewPageActivator, CustomViewPageActivator>(new InjectionConstructor(container));
    
        return container;
    }
    
  5. 将 ASP.NET MVC 4 默认依赖项解析程序替换为 UnityDependencyResolver 实例。 为此,请将 Initialize 方法内容替换为以下代码:

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex02 - 更新依赖项解析程序

    public static void Initialise()
    {
        var container = BuildUnityContainer();
    
        DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(container));
    
        IDependencyResolver resolver = DependencyResolver.Current;
    
        IDependencyResolver newResolver = new Factories.UnityDependencyResolver(container, resolver);
    
        DependencyResolver.SetResolver(newResolver);
    }
    

    注意

    ASP.NET MVC 提供默认依赖项解析程序类。 若要将自定义依赖项解析程序用作我们为 unity 创建的解析程序,必须替换此解析程序。

任务 4 - 运行应用程序

在此任务中,你将运行应用程序来验证 Store Browser 是否使用服务并显示检索的图像和消息:

  1. F5 运行该应用程序。

  2. 单击“流派”菜单中的“岩石,查看 MessageService 如何注入视图并加载欢迎消息和图像。 在此示例中,我们进入“Rock”:

    MVC 音乐商店 - 查看注入

    MVC 音乐商店 - 查看注入

  3. 关闭浏览器。

练习 3:注入操作筛选器

在以前的动手实验室 自定义操作筛选器 中,你已使用筛选器自定义和注入。 在本练习中,你将了解如何使用 Unity 容器通过依赖关系注入来注入筛选器。 为此,你将添加到音乐应用商店解决方案,这是一个自定义操作筛选器,用于跟踪网站的活动。

任务 1 - 在解决方案中包含跟踪筛选器

在此任务中,你将在音乐应用商店中包含用于跟踪事件的自定义操作筛选器。 由于自定义操作筛选器概念已在上一实验室“自定义操作筛选器”中处理,因此只需从本实验室的 Assets 文件夹中包括筛选器类,然后为 Unity 创建筛选器提供程序:

  1. 打开 Source\Ex03 - 注入操作筛选器\Begin 文件夹中的 Begin 解决方案。 否则,可以继续使用 通过完成上一练习获得的 End 解决方案。

    1. 如果打开提供的 Begin 解决方案,则需要先下载一些缺少的 NuGet 包,然后再继续。 为此,请单击“项目”菜单,然后选择“管理 NuGet 包”。

    2. 在“管理 NuGet 包”对话框中,单击“还原以下载缺少的包。

    3. 最后,通过单击“生成 | 生成解决方案”生成解决方案来生成解决方案。

      注意

      使用 NuGet 的优点之一是无需交付项目中的所有库,从而减少项目大小。 借助 NuGet Power Tools,通过在 Packages.config 文件中指定包版本,可以在首次运行项目时下载所有必需的库。 因此,在从此实验室打开现有解决方案后,必须运行这些步骤。

      有关详细信息,请参阅本文: https://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages

  2. TraceActionFilter.cs文件从 /Sources/Assets 添加到 /Filters 文件夹。

    namespace MvcMusicStore.Filters
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Web;
        using System.Web.Mvc;
    
        public class TraceActionFilter : IActionFilter
        {
            public void OnActionExecuted(ActionExecutedContext filterContext)
            {
                filterContext.HttpContext.Trace.Write("OnActionExecuted");
                filterContext.HttpContext.Trace.Write("Action " + filterContext.ActionDescriptor.ActionName);
                filterContext.HttpContext.Trace.Write("Controller " + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);
            }
    
            public void OnActionExecuting(ActionExecutingContext filterContext)
            {
                filterContext.HttpContext.Trace.Write("OnActionExecuting");
                filterContext.HttpContext.Trace.Write("Action " + filterContext.ActionDescriptor.ActionName);
                filterContext.HttpContext.Trace.Write("Controller " + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);
            }
        }
    }
    

    注意

    此自定义操作筛选器执行 ASP.NET 跟踪。 可以检查“ASP.NET MVC 4 本地和动态操作筛选器”实验室以获取更多参考。

  3. 将空类 FilterProvider.cs 添加到文件夹 /Filters 中的项目。

  4. FilterProvider.cs 中添加 System.Web.MvcMicrosoft.Practices.Unity 命名空间

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex03 - 筛选器提供程序添加命名空间

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using Microsoft.Practices.Unity;
    
    namespace MvcMusicStore.Filters
    {
         public class FilterProvider
         {
         }
    }
    
  5. 使类继承自 IFilterProvider 接口。

    namespace MvcMusicStore.Filters
    {
        public class FilterProvider : IFilterProvider
        {
        }
    }
    
  6. FilterProvider 类中添加 IUnityContainer 属性,然后创建类构造函数来分配容器。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex03 - 筛选器提供程序构造函数

    public class FilterProvider : IFilterProvider
    {
        private IUnityContainer container;
    
        public FilterProvider(IUnityContainer container)
        {
            this.container = container;
        }
    }
    

    注意

    筛选器提供程序类构造函数未在内部创建新对象。 容器作为参数传递,依赖项由 Unity 解决。

  7. 在 FilterProvider 类中,从 IFilterProvider 接口实现 GetFilters 方法

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex03 - 筛选器提供程序 GetFilters

    public class FilterProvider : IFilterProvider
    {
        private IUnityContainer container;
    
        public FilterProvider(IUnityContainer container)
        {
            this.container = container;
        }
    
        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            foreach (IActionFilter actionFilter in this.container.ResolveAll<IActionFilter>())
            {
                yield return new Filter(actionFilter, FilterScope.First, null);
            }
        }
    }
    

任务 2 - 注册和启用筛选器

在此任务中,你将启用站点跟踪。 为此,将在 Bootstrapper.cs BuildUnityContainer 方法中注册筛选器以开始跟踪:

  1. 打开 位于项目根目录中的 Web.config ,并在 System.Web 组中启用跟踪跟踪。

    <system.web>
        <trace enabled="true"/>
        <compilation debug="true" targetFramework="4.5">
    
  2. 在项目根目录中打开 Bootstrapper.cs

  3. 添加对 MvcMusicStore.Filters 命名空间的引用。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex03 - 引导程序添加命名空间

    using System.Web.Mvc;
    using Microsoft.Practices.Unity;
    using Unity.Mvc3;
    using MvcMusicStore.Services;
    using MvcMusicStore.Controllers;
    using MvcMusicStore.Factories;
    using MvcMusicStore.Filters;
    
  4. 选择 BuildUnityContainer 方法并在 Unity 容器中注册筛选器。 必须注册筛选器提供程序以及操作筛选器。

    (代码片段 - ASP.NET 依赖项注入实验室 - Ex03 - 注册 FilterProvider 和 ActionFilter

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
    
        //...
    
        container.RegisterInstance<IFilterProvider>("FilterProvider", new FilterProvider(container));
        container.RegisterInstance<IActionFilter>("LogActionFilter", new TraceActionFilter());
    
        return container;
    }
    

任务 3 - 运行应用程序

在此任务中,你将运行应用程序并测试自定义操作筛选器是否跟踪活动:

  1. F5 运行该应用程序。

  2. 单击“ 流派”菜单中的“摇滚 ”。 如果需要,可以浏览到更多流派。

    Music 商店

    Music 商店

  3. 浏览到 /Trace.axd 以查看“应用程序跟踪”页,然后单击“ 查看详细信息”。

    应用程序跟踪日志

    应用程序跟踪日志

    应用程序跟踪 - 请求详细信息

    应用程序跟踪 - 请求详细信息

  4. 关闭浏览器。


总结

通过完成此动手实验室,你已了解如何在 ASP.NET MVC 4 中使用依赖项注入,方法是使用 NuGet 包集成 Unity。 为此,已在控制器、视图和操作筛选器中使用了依赖关系注入。

介绍了以下概念:

  • ASP.NET MVC 4 依赖关系注入功能
  • 使用 Unity.Mvc3 NuGet 包的 Unity 集成
  • 控制器中的依赖关系注入
  • 视图中的依赖关系注入
  • 操作筛选器的依赖项注入

附录 A:安装 Visual Studio Express 2012 for Web

可以使用 Microsoft Web 平台安装程序 安装 Microsoft Visual Studio Express 2012 for Web 或其他“Express”版本。 以下说明指导你完成使用 Microsoft Web 平台安装程序 安装 Visual Studio Express 2012 for Web 所需的步骤。

  1. 转到 /iis/extensions/introduction-to-iis-express/iis-express-overview?linkid=9810169。 或者,如果已安装 Web 平台安装程序,可以打开它并搜索产品“Visual Studio Express 2012 for Web with Windows Azure SDK”。

  2. 单击“立即安装”。 如果没有 Web 平台安装程序 ,将重定向以先下载并安装它。

  3. Web 平台安装程序打开后,单击“安装以启动安装程序。

    安装 Visual Studio Express

    安装 Visual Studio Express

  4. 阅读所有产品的许可证和条款,然后单击“我接受继续。

    接受许可条款

    接受许可条款

  5. 等待下载和安装过程完成。

    安装进度

    安装进度

  6. 安装完成后,单击“ 完成”。

    安装已完成

    安装已完成

  7. 单击“退出关闭 Web 平台安装程序。

  8. 若要打开 Visual Studio Express for Web,请转到“开始”屏幕并开始编写“VS Express”,然后单击 VS Express for Web 磁贴。

    VS Express for Web 磁贴

    VS Express for Web 磁贴

附录 B:使用代码片段

使用代码片段时,只需用手指提示即可获取所有代码。 实验室文档将准确告诉你何时可以使用它们,如下图所示。

使用 Visual Studio 代码片段将代码插入项目中

使用 Visual Studio 代码片段将代码插入项目中

使用键盘添加代码片段(仅限 C#)

  1. 将光标置于要插入代码的位置。
  2. 开始键入代码段名称(不含空格或连字符)。
  3. 观看 IntelliSense 显示匹配的代码段名称。
  4. 选择正确的代码段(或在选择整个代码段名称之前继续键入)。
  5. 按 Tab 键两次在光标位置插入代码片段。

开始键入代码段名称

开始键入代码段名称

按 Tab 选择突出显示的代码片段

按 Tab 选择突出显示的代码片段

再次按 Tab,代码片段将展开

再次按 Tab,代码片段将展开

使用鼠标(C#、Visual Basic 和 XML) 1 添加代码片段。 右键单击要插入代码片段的位置。

  1. 选择“ 插入代码段 ”, 然后选择“我的代码片段”。
  2. 通过单击相关代码片段从列表中选择相关代码片段。

右键单击要插入代码片段的位置,然后选择“插入代码段”

右键单击要插入代码片段的位置,然后选择“插入代码段”

通过单击相关代码片段从列表中选择相关代码片段

通过单击相关代码片段从列表中选择相关代码片段