原文: Dependency Injection and Controllers

作者: Steve Smith

翻译: 刘浩杨

校对: 孟帅洋(书缘)

ASP.NET Core MVC 控制器应通过它们的构造器明确的请求它们的依赖关系。在某些情况下,单个控制器的操作可能需要一个服务,在控制器级别上的请求可能没有意义。在这种情况下,你也可以选择将服务作为 action 方法的参数。

章节:

查看或下载示例代码

依赖注入

依赖注入(Dependency injection,DI)是一种如 Dependency Inversion Principle 所示的技术,允许应用程序由松散耦合的模块组成。ASP.NET Core 内置了 dependency injection,这使得应用程序更容易测试和维护。

构造器注入

ASP.NET Core 内置的基于构造器的依赖注入支持扩展到 MVC 控制器。通过只添加一个服务类型作为构造器参数到你的控制器中,ASP.NET Core 将会尝试使用内置的服务容器解析这个类型。服务通常是,但不总是使用接口来定义。例如,如果你的应用程序存在取决于当前时间的业务逻辑,你可以注入一个检索时间的服务(而不是对它硬编码),这将允许你的测试通过一个使用设置时间的实现。

using System;

namespace ControllerDI.Interfaces
{
public interface IDateTime
{
DateTime Now { get; }
}
}

实现这样一个接口,它在运行时使用的系统时钟是微不足道的:

using System;
using ControllerDI.Interfaces; namespace ControllerDI.Services
{
public class SystemDateTime : IDateTime
{
public DateTime Now
{
get { return DateTime.Now; }
}
}
}

有了这些代码,我们可以在我们的控制器中使用这个服务。在这个例子中,我们在 HomeControllerIndex 方法中加入一些根据一天中的时间向用户显示问候的逻辑。

using ControllerDI.Interfaces;
using Microsoft.AspNetCore.Mvc; namespace ControllerDI.Controllers
{
public class HomeController : Controller
{
private readonly IDateTime _dateTime; //手动高亮 public HomeController(IDateTime dateTime) //手动高亮
{
_dateTime = dateTime; //手动高亮
} public IActionResult Index()
{
var serverTime = _dateTime.Now; //手动高亮
if (serverTime.Hour < 12) //手动高亮
{
ViewData["Message"] = "It's morning here - Good Morning!"; //手动高亮
}
else if (serverTime.Hour < 17) //手动高亮
{
ViewData["Message"] = "It's afternoon here - Good Afternoon!"; //手动高亮
}
else //手动高亮
{
ViewData["Message"] = "It's evening here - Good Evening!"; //手动高亮
}
return View(); //手动高亮
}
}
}

如果我们现在运行应用程序,我们将可能遇到一个异常:

An unhandled exception occurred while processing the request.

InvalidOperationException: Unable to resolve service for type 'ControllerDI.Interfaces.IDateTime' while attempting to activate 'ControllerDI.Controllers.HomeController'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)

这个错误发生时,我们没有在我们的 Startup 类的 ConfigureServices 方法中配置服务。要指定请求 IDateTime 时使用 SystemDateTime 的实例来解析,添加下面的清单中高亮的行到你的 ConfigureServices 方法中:

public void ConfigureServices(IServiceCollection services)
{
// Add application services.
services.AddTransient<IDateTime, SystemDateTime>(); //手动高亮
}

注意

这个特殊的服务可以使用任何不同的生命周期选项来实现(TransientScopedSingleton)。参考 dependency injection 来了解每一个作用域选项将如何影响你的服务的行为。

一旦服务被配置,运行应用程序并且导航到首页应该显示预期的基于时间的消息:

提示

参考 Testing Controller Logic 学习如何在控制器中显示请求依赖关系 http://deviq.com/explicit-dependencies-principle 让代码更容易测试。

ASP.NET Core 内置的依赖注入支持用于请求服务的类型只有一个构造器。如果你有多于一个构造器,你可能会得到一个异常描述:

An unhandled exception occurred while processing the request.

InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'ControllerDI.Controllers.HomeController'. There should only be one applicable constructor.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)

作为错误消息状态,你可以纠正只有一个构造器的问题。你也可以参考 replace the default dependency injection support with a third party implementation 支持多个构造器。

Action 注入和 FromServices

有时候在你的控制器中你不需要为超过一个 Action 使用的服务。在这种情况下,将服务作为 Action 方法的一个参数是有意义的。这是通过使用特性 [FromServices] 标记参数实现,如下所示:

public IActionResult About([FromServices] IDateTime dateTime)   //手动高亮
{
ViewData["Message"] = "Currently on the server the time is " + dateTime.Now; return View();
}

从控制器访问设置

在控制器中访问应用程序设置或配置设置是一个常见的模式。此访问应当使用在 configuration 所描述的访问模式。你通常不应该从你的控制器中使用依赖注入直接请求设置。更好的方式是请求 IOptions<T> 实例, T 是你需要的配置类型。

要使用选项模式,你需要创建一个表示选项的类型,如:

namespace ControllerDI.Model
{
public class SampleWebSettings
{
public string Title { get; set; }
public int Updates { get; set; }
}
}

然后你需要配置应用程序使用选项模型,在 ConfigureServices 中添加你的配置类到服务集合中:

public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder() //手动高亮
.SetBasePath(env.ContentRootPath) //手动高亮
.AddJsonFile("samplewebsettings.json"); //手动高亮
Configuration = builder.Build(); //手动高亮
} public IConfigurationRoot Configuration { get; set; } //手动高亮 // This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
// Required to use the Options<T> pattern
services.AddOptions(); //手动高亮 // Add settings from configuration
services.Configure<SampleWebSettings>(Configuration); //手动高亮 // Uncomment to add settings from code
//services.Configure<SampleWebSettings>(settings =>
//{
// settings.Updates = 17;
//}); services.AddMvc(); // Add application services.
services.AddTransient<IDateTime, SystemDateTime>();
}

注意

在上面的清单中,我们配置应用程序程序从一个 JSON 格式的文件中读取设置。你也可以完全在代码中配置设置,像上面的代码中所显示的。参考 configuration 更多的配置选项。

一旦你指定了一个强类型的配置对象(在这个例子中,SampleWebSettings),并且添加到服务集合中,你可以从任何控制器或 Action 方法中请求 IOptions<T> 的实例(在这个例子中, IOptions<SampleWebSettings>)。下面的代码演示了如何从控制器中请求设置。

    public class SettingsController : Controller
{
private readonly SampleWebSettings _settings; //手动高亮 public SettingsController(IOptions<SampleWebSettings> settingsOptions) //手动高亮
{
_settings = settingsOptions.Value; //手动高亮
} public IActionResult Index()
{
ViewData["Title"] = _settings.Title;
ViewData["Updates"] = _settings.Updates;
return View();
}
}

遵循选项模式允许设置和配置互相分离,确保控制器遵循 separation of concerns ,因为它不需要知道如何或者在哪里找到设置信息。由于没有 static cling 或在控制器中直接实例化设置类,这也使得控制器更容易单元测试

返回目录

ASP.NET Core 中文文档 第四章 MVC(4.4)依赖注入和控制器的更多相关文章

  1. ASP.NET Core 中文文档 第四章 MVC(4.5)测试控制器逻辑

    原文: Testing Controller Logic 作者: Steve Smith 翻译: 姚阿勇(Dr.Yao) 校对: 高嵩(Jack) ASP.NET MVC 应用程序的控制器应当小巧并专 ...

  2. ASP.NET Core 中文文档 第四章 MVC(4.2)控制器操作的路由

    原文:Routing to Controller Actions 作者:Ryan Nowak.Rick Anderson 翻译:娄宇(Lyrics) 校对:何镇汐.姚阿勇(Dr.Yao) ASP.NE ...

  3. ASP.NET Core 中文文档 第四章 MVC(3.6.1 )Tag Helpers 介绍

    原文:Introduction to Tag Helpers 作者:Rick Anderson 翻译:刘浩杨 校对:高嵩(Jack) 什么是 Tag Helpers? Tag Helpers 提供了什 ...

  4. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

  5. ASP.NET Core 中文文档 第四章 MVC(4.6)Areas(区域)

    原文:Areas 作者:Dhananjay Kumar 和 Rick Anderson 翻译:耿晓亮(Blue) 校对:许登洋(Seay) Areas 是 ASP.NET MVC 用来将相关功能组织成 ...

  6. ASP.NET Core 中文文档 第四章 MVC(4.1)Controllers, Actions 和 Action Results

    原文:Controllers, Actions, and Action Results 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:许登洋(Seay) Action 和 acti ...

  7. ASP.NET Core 中文文档 第四章 MVC(3.9)视图组件

    作者: Rick Anderson 翻译: 娄宇(Lyrics) 校对: 高嵩 章节: 介绍视图组件 创建视图组件 调用视图组件 演练:创建一个简单的视图组件 附加的资源 查看或下载示例代码 介绍视图 ...

  8. ASP.NET Core 中文文档 第四章 MVC(3.7 )局部视图(partial)

    原文:Partial Views 作者:Steve Smith 翻译:张海龙(jiechen).刘怡(AlexLEWIS) 校对:许登洋(Seay).何镇汐.魏美娟(初见) ASP.NET Core ...

  9. ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览

    原文:Overview of ASP.NET Core MVC 作者:Steve Smith 翻译:张海龙(jiechen) 校对:高嵩 ASP.NET Core MVC 是使用模型-视图-控制器(M ...

随机推荐

  1. 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验

    运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...

  2. Ajax 概念 分析 举例

    Ajax是结合了访问数据库,数据访问,Jquery 可以做页面局部刷新或者说是页面不刷新,我可以让页面不刷新,仅仅是数据的刷新,没有频繁的刷页面,是现在比较常用的一种方式做页面那么它是怎么实现页面无刷 ...

  3. 解决PHP-问题:Class 'SimpleXMLElement' not found in

    1.问题 在ubuntu 16.10中,学习PHP,学习到PHP如何生成XML文件时候,碰到了这个问题: PHP Fatal error: Class 'ClassName\SimpleXMLElem ...

  4. Python标准模块--Unicode

    1 模块简介 Python 3中最大的变化之一就是删除了Unicode类型.在Python 2中,有str类型和unicode类型,例如, Python 2.7.6 (default, Oct 26 ...

  5. JS实现页面进入、返回定位到具体位置

    最为一个刚入职不久的小白...慢慢磨练吧... JS实现页面返回定位到具体位置 其实浏览器也自带了返回的功能,也就是说,自带了返回定位的功能.正常的跳转,返回确实可以定位,但是有些特殊场景就不适用了. ...

  6. AI人工智能系列随笔:syntaxnet 初探(1)

    人工智能是 最近的一个比较火的名词,相信大家对于阿尔法狗都不陌生吧?其实我对人工智能以前也是非常抵触的,因为我认为机器人会取代人类,成为地球乃至宇宙的霸主,但是人工智能带给我的这种冲击,我个人感觉是欲 ...

  7. 【开发软件】 在Mac下配置php开发环境:Apache+php+MySql

    本文地址 原文地址   本文提纲: 1. 启动Apache 2. 运行PHP 3. 配置Mysql 4. 使用PHPMyAdmin 5. 附录   有问题请先 看最后的附录   摘要: 系统OS X ...

  8. 5.2 Array类型的方法汇总

    所有对象都具有toString(),toLocaleString(),valueOf()方法. 1.数组转化为字符串 toString(),toLocaleString() ,数组调用这些方法,则返回 ...

  9. atitit.attilax的软件 架构 理念.docx

    atitit.attilax的软件 架构 理念.docx 1. 预先规划.1 2. 全体系化1 3. 跨平台2 4. 跨语言2 5. Dsl化2 5.1. 界面ui h5化2 6. 跨架构化2 7. ...

  10. git多账号登录问题

    作者:白狼 出处:http://www.manks.top/git-multiply-accounts.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文 ...