首页 > 学院 > 开发设计 > 正文

【中英对照】【EntLib6】【Unity】实验1:使用一个Unity容器

2019-11-14 16:28:28
字体:
来源:转载
供稿:网友

Lab 1: Using a Unity Container

实验1:使用一个Unity容器

Estimated time to complete this lab: 15 minutes

估计完成时间:15分钟

Introduction

介绍

In this lab, you will PRactice using a Unity container to create application objects and wire them together. You will update a simple stocks ticker application to replace calls to constructors and property setters with requests to a properly configured Unity container.

在这个实验中,你将练习使用一个Unity容起来创建应用对象并将他们连贯在一起。你将更新一个简单的股票收录机应用,替换对构造函数的调用和属性的设置器,这需要恰当的配置Unity容器。

To begin this lab, open the StocksTicker.sln file located in the /Lab01/begin/StocksTicker folder.

要开始这个实验,打开位于/Lab01/begin/StocksTicker 文件夹下的StocksTicker.sln文件。

Running the Application

运行这个应用

Start by launching the application. To launch the application, on the Visual Studio Debug menu click Start Without Debugging or press Ctrl-F5. This opens a form and a console window. The console window opens to display the messages logged to the console while the application runs.

通过启动应用来开始。要运行应用,打开VS的调试菜单,单击菜单项 开始执行(不调试),或按下Ctrl-F5。这样就会打开一个Form窗体和一个控制台窗口。在应用运行期间控制台窗口会一直打开,并显示日志消息到控制台。

On the application form, you can enter stock quote symbols, consisting of only letters, and subscribe to them by clicking the Subscribe button. When the Refresh check box is selected, the form displays the latest information about each of the subscribed stock symbols. The form will Flash each time an update for a stock symbol is received. The following figure illustrates a sample stocks ticker application.

在应用的Form窗体中,你可以输入股票报价符号,仅由字母组成,然后通过单击 订阅(subscribe) 按钮订阅他们。当刷新(Refresh)复选框被选中,窗体将会显示每个股票的最新信息。窗体每收到一个股票的更新信息就会刷新显示。下图示例了一个简单的股票收录机应用。

By default, the console is used to log information about the retrieval of updated quotes. The ui.log file (located in the StocksTicker/bin/Debug folder) contains information about the Operations performed by the user interface (UI). After you close the application, you can review the contents of the log file.

在默认情况下,控制台用来显示接收到的更新的信息。而ui.log文件(位于StocksTicker/bin/Debug文件夹)包含关于在UI的的操作的记录。在你关闭应用之后,你可以重新查看日志文件里的内容。

Reviewing the Application

审视这个应用

The application is built by using the Model-View-Presenter (MVP) pattern. For information about the MVP pattern, see Separated Presentation on MSDN. The following figureError! Reference source not found. shows the classes involved in the application and their relationships.

这个应用使用了MVP模式来创建。关于MVP模式,可以见MSDN上的Separated Presentation。下图展示了应用涉及到的类和他们之间的关系。

The StocksTickerForm class implements the user interface, and the IStockQuoteService interface defines a service for retrieving current stock quotes, the RandomStockQuoteService is the concrete implementation of IStockQuoteService that is used in these labs. The ILogger interface and its implementations are used to log messages about the operation of the application. Finally, the StocksTickerPresenter class plays the presenter role.

 

StocksTickerForm类实现了UI,IStockQuoteService接口定义了一个获取当前股票符号的服务,在本实验中使用的RandomStockQuoteService类具体实现了IStockQuoteService接口。ILogger接口和他的实现类被用来记录关于应用的操作的日志消息。最后,StocksTickerPresenter扮演了presenter的角色。

 

All classes in the solution, including the presenter class, have constructors that take all of the required collaborators as parameters and properties where optional collaborators can be set. In the presenter's case, the required collaborators are its view and the service used to poll for updates, and logger is an optional collaborator.

解决方案中的所有类,包括presenter类,都有构造函数,包含了所有必需的构造信息作为参数,可选的构造者作为属性也是可以设置的。在presenter的情况下,必需的构造者是他的view和用来得到更新的服务,而日志器是可选构造者。

 

The static Program.Main() method creates all the involved objects in order and connects them together before launching the user interface (UI). The purpose of this lab is to replace the explicit creation of these objects with the use of a Unity container.

静态的Program.Main()方法创建了所有需要涉及的对象并在启动UI之前将它们连接在一起。这个实验的目的是通过对一个Unity 容器的使用来替换这些对象的显式创建。

 

Task 1: Using a Container

任务1:使用一个容器

In this task, the application's startup code will be updated to use a Unity container to create and connect the application's objects. This will replace the use of explicit calls to the classes' constructors and property setters.

在这个任务中,应用的启动代码将会被更新,使用一个Unity容器来创建和连接应用的对象。这将会替换对显式调用类的构造函数和属性的设置器的使用。

Adding References to the Required Assemblies

添加所需要的程序集

 

  1. In Solution Explorer, select the StocksTicker project, and then click Manage NuGet Packages on the Project menu.
  2. Select the "Online" option to view NuGet Packages available online.
  3. Search for EntLib6 in the search bar. Select Unity and click install.

 

  1. 在解决方案资源管理器中,选择StocksTicker项目,然后在项目菜单中单击管理NuGet程序包…项。
  2. 选择"联机"选项来查看所有在线能获取的NuGet包。
  3. 在搜索栏搜索EntLib6。选择Unity然后单击安装

  1. Click Accept on the License Acceptance window that pops up.
  1. 在弹出的许可证接受窗口中单击"接受"按钮。

 

Update the Startup Code to Use a Container

更新启动代码来使用一个容器

To update the startup code to use a container

要更新启动代码来使用一个容器

  1. Open the Program.cs file.
  2. Add a using directive for the Unity namespace.

    using Microsoft.Practices.Unity;

  3. 打开Program.cs文件。
  4. 添加一个指向Unity的命名空间引用。

    using Microsoft.Practices.Unity;

  5. Replace the creation of the instances (view, presenter, service, loggers) with a Resolve request to a new UnityContainer for the StocksTickerPresenter, as shown in the following highlighted code.
  6. 使用新的UnityContainer的Resolve方法替代实例(view, presenter, service, loggers)的创建,如下高亮的代码所示。

Unity containers implement the IDisposable interface. This enables the new code to take advantage of the using statement to dispose the new container. Lab 2 elaborates on the result of disposing a container.

Unity容器实现了IDisposable接口。这就允许新的代码使用using语法的优势来销毁创建的容器。实验2详细说明了销毁一个容器的过程和结果。

  1. Debug the application. To do this, click Start Debugging on the Visual Studio Debug menu or Press F5. The debugger will break with an unhandled ResolutionFailedException. This indicates that the attempt to resolve the StocksTickerPresenter has failed.
  2. 调试应用,单击 调试 菜单的开始调试项或按下F5键。调试器将会被一个未处理的ResolutionFailedException异常中断。这表示尝试确定StocksTickerPresenter失败了。

Although the container requires additional configuration to resolve the requested presenter, the messages for the ResolutionFailedException and its chain of InnerExceptions reveal some interesting details:

尽管容器需要进一步配置来确定需要的presenter,异常ResolutionFailedException和他的InnerExceptions消息揭示了一些有趣的细节:

  • The request to resolve the presenter is identified with the build key type = "StocksTicker.UI.StocksTickerPresenter", name = "(none)". In this case no name has been provided.
  • 确定presenter的需求被建立Key type = "StocksTicker.UI.StocksTickerPresenter", name = "(none)"标识。在这里,没有名字被提供。
  • The error occurred while resolving an object.
  • 错误发生在确定一个对象的时候。
  • The container determined that the constructor for StocksTickerPresenter with the signature (IStocksTickerView view, IStockQuoteService stockQuoteService) should be used to create the object, by using the autowiring rules.
  • 容器在使用默认的 autowiring规则的时候,确定StocksTickerPresenter的构造函数包含签名:(IStocksTickerView view, IStockQuoteService stockQuoteService)将被用来创建对象。
  • The root cause of the failure was the inability to build an instance of the IStocksTickerView interface to be the value for the view parameter in the chosen StocksTickerPresenter constructor. This problem is indicated by the InvalidOperationException
  • 导致这个失败的根本原因是在选择的构造函数中需要一个view作为其参数,而这个IStocksTickerView接口的对象无法创建。这个问题被InvalidOperationException异常指示出来的。

For information about Unity's autowiring rules, see the topic "Annotating Objects for Constructor Injection" in the Unity 3 documentation.

关于Unity的autowiring规则的信息,请看Unity 3 文档的Annotating Objects for Constructor Injection主题

  1. Add the required type mappings by using the RegisterType method, as shown in the following highlighted code .This will enable the container to resolve the required objects.
  2. 通过使用RegisterType方法来添加必要类型映射,如下面所示的高亮代码。这将允许容器确定所需的对象。

Using the RegisterType method is primarily how you will set up a container. In addition to mapping abstract types to concrete ones as described in this step, you can use the RegisterType method to override the default injection rules and specify lifetime managers. The next exercises will show additional uses of the RegisterType method. For details about mapping types see the topic "Registering Types and Type Mappings" in the Unity 3 documentation.

使用RegisterType方法是你设置一个容器主要的内容。在这个步骤中描述了映射抽象类型到具体的类型,除此之位,你可以使用RegisterType方法来重载默认的注入规则和明确指定生命周期管理器。在下一个练习中将会展示RegisterType方法的额外用法。关于映射类型的更多详细信息,请柬Unity 3 文档的Registering Types and Type Mappings主题。

Running the Application

运行这个应用

Launch the application and use it. The application behaves as it did before the changes, except that no logging will be available in the console or the ui.log file.

运行应用并使用它。这个应用表现的跟修改前一样,除了没有日志信息出现在控制台窗口中和ui.log文件中。

Task 2: Using Attributes to Control Injection

任务2:使用特性来控制注入

Attributes can be used to override the default injection rules. In some cases, attributes are used to opt-in for injection on members ignored by the default rules. In other cases, attributes must be used to override the default rules or disambiguate cases where the rules cannot be used.

特性可以用来重载默认的注入规则。在某些情况下,特性被用来为成员选择注入,以忽略默认规则。在另一些情况下,特性必须用来重载默认规则,或在不能使用规则的情况下消除歧义。

 

Using Attributes to Enable Property Injection

使用特性来启用属性注入

It is very common to have the container set properties, in addition to passing in dependencies by using constructor arguments.

在通过构造函数参数来传递依赖项的方法之外,使用容器来设置属性也是非常通用的。

To set up injection for the Logger property on the RandomStockQuoteService class

在RandomStockQuoteService类为logger属性设置注入

  1. Open the StockQuoteServices/RandomStockQuoteService.cs file.
  2. Add a using directive for the Unity namespace.

 

  1. 打开StockQuoteServices/RandomStockQuoteService.cs文件。
  2. 添加一个指向Unity的命名空间引用。

    using Microsoft.Practices.Unity;

    1. Add the Dependency attribute to the Logger property, as shown in the following highlighted code.
  3. 添加Dependency特性到Logger属性上,如下所示高亮代码。

Adding a Type Registration to Resolve the ILogger Interface

添加一个类型注册器来确定ILogger接口

Because the container must now resolve the ILogger interface, a mapping from the interface to a concrete type must be added to the container. In this example, the interface will be mapped to the ConsoleLogger class in order to match the code originally used to wire-up the objects.

因为容器现在必需确定ILogger接口,一个指向接口的确定类型映射必需添加到容器中。在这个示例中,这个接口将被映射到ConsoleLogger类,以匹配原来的连接对象的代码。

To add a type registration to resolve the ILogger interface

添加一个类型注册器来确定ILogger接口

  1. Open the Program.csfile.
  2. Use the RegisterType method to map the ILogger interface to the ConsoleLogger class, as shown in the following highlighted code.
  1. 打开Program.cs 文件。
  2. 使用RegisterType方法来映射ILogger接口到ConsoleLogger类,如下所示高亮代码。

Running the Application

运行这个应用

Launch and use the application. Operations performed by the service are logged to the console, but UI operations are not logged to the console because the Logger property on the presenter class is still not injected.

运行并使用应用。服务的操作被记录到控制台,但是UI的操作没有被记录到控制台因为presenter里面的Logger属性还没有设置注入。

 

Setting Up Injection for the Logger Property on the StocksTickerPresenter Class

在StocksTickerPresenter类上设置Logger属性的注入

To inject the Logger property on the presenter class, this lab uses the same Dependency attribute. However, because a different logger instance is to be injected, you need a way to differentiate the loggers. The Unity container lets you register the same type multiple times, and give each registration a different name. When that dependency is resolved, the name can be used to specify exactly which instance you want. In this lab, you will use different names so that you can tell the difference between the logger objects.

要在presenter类上注入Logger属性,这个实验使用的是相同的Dependency特性。但是,因为不同的logger实例要被注入,你需要一种方式来区分Loggers。Unity容器允许你注册同一个类型多次,并给每个注册设置不同的名字。当依赖项被确定的时候,名称可以用来精确的指定哪个实例是你需要的。在这个实验中,你将使用不同的名字这样你就可以说明两个logger对象的不同了。

To set up injection for the Logger property on the StocksTickerPresenter class

在StocksTickerPresenter类上设置Logger属性的注入

  1. Open the UI/ StocksTickerPresenter.cs file.
  2. Add a using directive for the Unity namespace.
  1. 打开UI/ StocksTickerPresenter.cs文件。
  2. 添加一个指向Unity的命名空间引用。

    using Microsoft.Practices.Unity;

    1. Add the Dependency attribute to the Logger property using "UI" for the name, as shown in the following highlighted code.
  3. 在Logger属性上使用UI这个名字添加Dependency特性,如下高亮代码所示。

Adding a Type Registration to Resolve the ILogger Interface with the "UI" Name

使用"UI"这个名字来添加一个类型注册,以确定ILogger接口

To add a type registration to resolve the ILogger interface with the "UI" name

使用"UI"这个名字来添加一个类型注册,以确定ILogger接口

  1. Open the Program.cs file.
  2. Use the RegisterType method to map the ILogger interface to the TraceSourceLogger class with the "UI" name, as shown in the following highlighted code.
  1. 打开Program.cs 文件。
  2. 使用RegisterType方法来映射ILogger接口到TraceSourceLogger类,使用"UI"为名称,如下所示高亮代码。

Debugging the Application

调试这个应用

Launch the application. The debugger should break with an unhandled exception that indicates a new failure while trying to resolve the Logger property on the presenter to an instance of TraceSourceLogger. Examining the chain of InnerExceptions shows that the root cause of the failure is indicated with an InvalidOperationException and the message "The type TraceSourceLogger has multiple constructors of length 1. Unable to disambiguate." In this case, Unity's default injection rules cannot determine how to build the instance, so the container must be explicitly configured to build it.

运行应用。调试器将会被一个未处理的异常中断,其指示了在尝试确定presenter的Logger属性为TraceSourceLogger实例的时候产生了一个新的错误。仔细检查异常链中的InnerExceptions展示了导致这个错误的根本原因是一个InvalidOperationException异常,其消息是"The type TraceSourceLogger has multiple constructors of length 1. Unable to disambiguate."在这个情况下,Unity的默认注入规则不能确定如何创建实例,所以容器必需明确的配置如何构建他。

Indicating Which Constructor to Use When Building an Instance of TraceSourceLogger with the InjectionConstructor Attribute

用注入构造函数特性来指定当创建一个TraceSourceLogger实例使用哪个构造函数

This lab uses an attribute to indicate which of the two available constructors should be used to create an instance of the TraceSourceLogger class.

这个实验使用一个特性来指示已有的两个构造函数中的哪个来创建TraceSourceLogger类的实例。

To indicate which constructor to use when building an instance of TraceSourceLogger with the InjectionConstructor attribute

用注入构造函数特性来指定当创建一个TraceSourceLogger实例使用哪个构造函数

  1. Open the Loggers/TraceSourceLogger.cs file.
  2. Add a using directive for the Unity namespace.
  1. 打开Loggers/TraceSourceLogger.cs文件。
  2. 添加一个指向Unity的命名空间引用。

    using Microsoft.Practices.Unity;

    1. Add the InjectionConstructor attribute to the constructor that takes a TraceSource as its sole parameter, as shown in the following highlighted code.
  3. 添加一个InjectionConstructor特性到使用一个TraceSource作为其唯一参数的构造函数上,如下代码所示。

Adding an Instance Registration to Resolve the TraceSource Type

添加一个实例注册器来确定的TraceSource类型

After being pointed to one of the constructors, Unity's default injection rules take effect and an instance of the .NET Framework TraceSource class will be resolved to be used as the argument for the constructor call. Instead of instructing the container about how to build such an instance, which would be problematic since the class cannot be annotated with attributes, a pre-built instance will be supplied to the container.

在指定了一个构造函数之后,Unity的默认注入规则将起作用并且一个.NET Framework TraceSource类的实例将会被确认用来作为调用个构造函数时的参数。不是告诉容器如何创建一个这样的实例,因为这样可能会有问题如果这个类不能通过特性注释,取而代之的是,直接预先建立一个实例并提供给容器。(这里翻译我自己都觉得奇怪,我也没看懂)。

To add an instance registration to resolve the TraceSource type

添加一个实例注册器来确定的TraceSource类型

  1. 1. Open the Program.cs file.
  2. 2. Use the RegisterInstance method to indicate the instance to return when resolving the TraceSource class, as shown in the following highlighted code.
  1. 打开Program.cs 文件。
  2. 使用RegisterInstance方法来指示当确定TraceSource类的时候返回的实例,如下所示高亮代码。

Running the Application

运行这个应用

Launch and use the application. Now the application should work exactly as it did initially, with messages from the UI being logged to the ui.log file (located in the StocksTicker/bin/Debug folder) and messages from the service being logged to the console.

运行并使用这个应用。现在这个应用应该能够像最初那样正确的工作了,来自UI的消息将被记录到ui.log文件中(位于StocksTicker/bin/Debug文件夹)而来自服务的消息将会被记录到控制台。

Attributes are a convenient mechanism to override or disambiguate the container's default injection rules but can result in brittle dependencies. Using names can make particularly brittle dependencies because they get hard-coded in the source code. The next labs show alternative mechanisms to externalize the setup of a container without involving the objects being created. To verify you have completed the lab correctly, you can use the solution provided in the /Lab01/end/StocksTicker folder.

特性是一个方便的机制来重载或消除容器的默认注入规则但是可能导致零碎的依赖关系。使用名称将导致特别零碎的依赖因为他们使用硬编码方式存在源代码里面。在下一个实验中将展示台体的机制来具体化一个容器的安装避免涉及到对象的创建。你可以使用/Lab01/end/StocksTicker文件夹下提供的解决方案来来验证你完成的实验是否正确。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表