Lab 1: Using a Unity Container
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
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
Update the Startup Code to Use a Container
To update the startup code to use a container
要更新启动代码来使用一个容器
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity;
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详细说明了销毁一个容器的过程和结果。
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消息揭示了一些有趣的细节:
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主题。
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
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属性设置注入
using Microsoft.Practices.Unity;
Adding a Type Registration to Resolve the ILogger Interface
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接口
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
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属性的注入
using Microsoft.Practices.Unity;
Adding a Type Registration to Resolve the ILogger Interface with the "UI" Name
To add a type registration to resolve the ILogger interface with the "UI" name
使用"UI"这个名字来添加一个类型注册,以确定ILogger接口
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
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实例使用哪个构造函数
using Microsoft.Practices.Unity;
Adding an Instance Registration to Resolve the TraceSource Type
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类型
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文件夹下提供的解决方案来来验证你完成的实验是否正确。
新闻热点
疑难解答