[Translation] WebAPI, Autofac, and lifecycle scope

Explanation

Original Address: http://decompile.it/blog/2014/03/13/webapi-autofac-lifetime-scopes/

Introduction

This is an article about AutoFac the lifecycle scope of the article.

About lifecycle domain has always been a daunting proposition, some of the concepts can easily cause misunderstanding and confusion, such as a singleton domain (PerLifetimeScope) and internal requests singleton (InstancePerRequest) What is the difference, and they Can be used interchangeably and many more......

Prior to these problems have been plaguing me until I found the link to this article on stackoverflow, the authors used the example code + illustrated the way, thoroughly answered all my doubts, I would like to thank the more than shoving it translated down.

Before reading the text, you can take a look at the following questions, if you have been very clear on these issues, then congratulations, you have been strong enough to not need to waste time reading this article, you can go directly to the right turn:

  1. Domain singleton (PerLifetimeScope) What does it mean?

  2. Request within singleton (InstancePerRequest) What does it mean?

  3. Within a single case and within the request Singleton What is the difference? In WebApi types of projects, Can they be used interchangeably?

  4. In the .NET Core, AutoFac of the request singleton (InstancePerRequest) is no longer valid, but some need to be registered as the object has a single embodiment within the request (such as in the DbContext EF), it can use a single embodiment art to replace (PerLifetimeScope) ? What is the impact?

If any of these problems still have doubts, then I believe that this article will be helpful for you in (the same as it was for me).

prompt

  1. The article mentioned in the Http request singleton (InstancePerHttpRequest) and within Api request singleton (InstancePerApiRequest) now AutoFac the obsolete, replaced by a consolidated single cases of request (InstancePerRequest)

  2. The original author of the source code is on GitHub open source, the address at the end of the article. I am a Fork, the AutoFac update to the latest version, and added a Chinese document, there is a need also can go to download or browse my GitHub

  3. This article is based on the default readers already know the basics of dependency injection and AutoFac as a precondition, if a friend or a beginner, I suggest you can go to read AutoFac technical documentation, or written down before I can see the two and a half hours lying .NET dependency injection articles ~

original

When we use AutoFac (or any other container for dependency injection) when there is often a very troubled our proposition, that is lifecycle scope.

If you are a beginner, I suggest to read a great article of Nicholas Blumhardt: An Autofac Lifetime Primer . Given that you may need to repeatedly read several times to digest this knowledge, I suggest that you can save a bookmark.

For AuotoFac, I have heard such a question in many occasions:

Domain singleton (InstancePerLifetimeScope), within Http request singleton (InstancePerHttpRequest) and Api requests within a single case (InstancePerApiRequest) What is the difference?

I have always been puzzled by this question, and so far I have not found a satisfactory answer. So, today I will try to answer this question himself.

First throw my ultimate conclusion:

  • If you want your registration rely on any domain may have been resolved, please use the singleton domain (InstancePerLifetimeScope). Your life cycle of dependency in conjunction with the release of the domain. If this domain is the root domain , it will exist until the end of the program.

  • If you want to make your registration rely only be resolved in the request type (HTTP / API) of the request context, then use a singleton in the request (InstancePerApiRequest / InstancePerHttpRequest). Dependent release after the end of the request.

Here I will not go to explain the concept and scope of the life cycle, Nicholas has done a good part of this work, I have also put a link above his article posted out. So, I will assume that you already have a basic knowledge of dependency injection, and now you just want to know for the Web program how they operate.

In order to better explain, I wrote a simple program that can download their required down trying to run a race. I created the program in four Resolvablescategories - each of them is very simple, the only function is to demonstrate service is from where parsed out. Register their codes are as follows:

private static void RegisterResolvables(ContainerBuilder builder)
{
    builder.RegisterType<SingletonResolvable>()
        .SingleInstance();
 
    builder.RegisterType<PerLifetimeResolvable>()
        .InstancePerLifetimeScope();
 
    builder.RegisterType<PerRequestResolvable>()
        .InstancePerApiRequest();
 
    builder.RegisterType<PerDependencyResolvable>()
        .InstancePerDependency();
}

There is also a program responsible for parsing the class, its only task is responsible for parsing the above four Resolvablescategories. The following is a class constructor:

public ResolvableConsumer(
    SingletonResolvable singleton,
    PerLifetimeResolvable lifetime,
    PerRequestResolvable request,
    PerDependencyResolvable dependency)
{
    // ...
}

Now, I have to do a marvelous thing! I created a ScopeTokenclass, and simply encapsulates what it so that it can show itself to be parsed out what the scope, and then let four Resolvablesclasses rely on this ScopeTokenclass. Sign in ScopeTokenclass, we can modify the scope to observe its life cycle in the end what changes will produce the program. Here, we first register it as a transient instance (InstancePerDependency) give it a try.

private static void RegisterToken(ContainerBuilder builder)
{
    var tokenRegistration = builder.RegisterType<ScopeToken>();
 
    // TODO: 挨个尝试
    // tokenRegistration.SingleInstance();
    // tokenRegistration.InstancePerLifetimeScope();
    // tokenRegistration.InstancePerApiRequest();
    tokenRegistration.InstancePerDependency();
}

We can request TestControllerto test our procedures in a GET request. I use the tool to simulate HTTPie Web requests (on the use of this tool, you can refer to Scott Hanselman's installation notes )

Now our preparations have been completed, the next we look together using different lifecycle scope registered, will resolve ScopeTokenwhat kind of impact.

Example transient single (InstancePerDependency)

When using AutoFac registration component, if we do not specify the life cycle of their own domain, the domain will be the default option. In the technical documentation is so explained:

The field marked with the registration assembly, then each component or each pass depend Resolve () will be parsed to a new instance.

We look at, what to call GET Interface happens:

PerDependency

As expected, each 解析对象within are injected only a token of their own. Look, dependency injection worked!

We can see a few interesting places:

  • SingletonResolvableThe token from the 根域inner (root scope) the parsed

  • Other resolve all class token from a domain called AutofacWebRequest of parsed

As shown below:

PerDependency1

Out of curiosity, if we look at the interface called once again what happens:

PerDependency_2

Token # 1 has not changed. This is because the life cycle of the program and the root domain is consistent. In other words, SingletonResolvableobjects, and it depends on ScopeTokenthe object will exist until the program stops running so far.

Instead, Tokens # 2, # 3 and # 4 have all been freed, because AutofacWebRequest域the life cycle of a Web request and consistent. That is, the field is created when the request is initiated when the request is released immediately after the end off.

Global singleton (the SingleInstance)

private static void RegisterToken(ContainerBuilder builder)
{
    var tokenRegistration = builder.RegisterType<ScopeToken>();
    tokenRegistration.SingleInstance();
}

Next easier to understand it is a global singleton, its meaning as expressed by its name: any time will be a unique instance. Indeed, Autofac singleton object will be attributed to 根域the (root scope) (or called "container" scope), while all other fields are the sub-domains in the root domain. Here is the output call interface:

SingleInstance

Again as expected, each object gets resolved are the same ScopeTokeninstance.

SingleInstance1

Two points should be noted:

  1. All the cases are in the single root domain, and I have already said, as long as the life cycle of the program and the root domain.
  2. AutoFac when parsing component, it will be followed up to find the dependent parent class domain

EXAMPLE single domain (PerLifetimeScope)

private static void RegisterToken(ContainerBuilder builder)
{
    var tokenRegistration = builder.RegisterType<ScopeToken>();
    tokenRegistration.InstancePerLifetimeScope();
}

From here, things will start to get interesting. AutoFac interpretation of the document a single case of domain as follows:

Registered with the lifecycle scope, each subsequent component dependent or parsed by the Resolve () object, the life cycle of the same scope are identical, they share the same single embodiment, but within a different life cycle effect it is different.

Remember the example above, a single case of momentary do? SingletonResolvableClass is parsed in the root domain of the other Resolvablesclasses to be resolved AutofacWebRequest域. Let's look at a single case within what will happen:

PerLifetimeScope

正如预期的,我们有两个“激活”的域,而且每个域内都有一个ScopeToken实例。

PerLifetimeScope1

让我们来看下当再次调用接口会发生什么:

PerLifetimeScope_2

和之前的瞬时单例一样,处在根域内的Token #1一直存在着,而处在AutofacWebRequest域内的Token #2在请求结束后被释放掉了。

一直以来有一个普遍的错误认知,就是认为在WebAPI项目中如果组件被注册为域内单例(InstancePerLifetimeScope)的话,那么意思就是它将存活在一次request请求内,即它的生命周期就是一次request请求的生命周期。但是正如上面的例子所展示的,这种认知是错误的。

被注册为域内单例的组件,它的生命周期是由解析它的域所决定的。

因为SingletonResolvable实例是在根域内解析它的token,所以这个token实例就存在于根域内,而不是一次web请求的生命周期域。之前已经说过,这里我要再重复一遍:这个token会一直存在直到整个应用程序停止运行为止(即IIS工作进程被回收时)。任何对象只要是在根域内要求获取依赖的ScopeToken,那么它就会得到这个唯一单例的对象。

Api请求内单例(InstancePerApiRequest)

private static void RegisterToken(ContainerBuilder builder)
{
    var tokenRegistration = builder.RegisterType<ScopeToken>();
    tokenRegistration.InstancePerApiRequest();
}

最后,也是最重要的,让我们来看下Api请求内单例。下面是调用接口后的情况:

PerApiRequest

请求出现了一个令人不快的异常,内容是:

被请求获取的实例所在的域内,找不到一个标签为‘AutofacWebRequest’的域。这通常表明,有一个被注册为每次HTTP请求内单例的组件被一个全局单例的组件请求获取(或者是类似的其他场景)。web项目通常是从DependencyResolver.Current或者ILifetimeScopeProvider.RequestLifetime中获取依赖,但是不允许直接从根容器中获取。

为了明白为什么会发生这样的异常,我们需要回到AutoFac的技术文档上来。里面说,Api请求内单例(InstancePerApiRequest)实际上是每个匹配域内单例(InstancePerMatchingLifetimeScope)的一种特殊情况,文档原文是这样的 :

用Api请求内单例来注册组件,那么每个依赖组件或者每次通过Resolve()解析,只要是在打了统一标签名称的域内,就会得到同一个对象,即它们共享同一个单例。在这个特定标签域下面的所有子域中,依赖组件也会共享其父域中的单例。如果在当前域和它的父域中都找不到这个标签域,那么一个类型为DependencyResolutionException的异常将会被抛出。

具体来说,Api请求内单例(InstancePerApiRequest)实质上是在一个特定标签域内单例,正如你所猜测的,这个特定标签域就是AutofacWebRequest域。这个域会在一次请求开始时被创建,并且在请求结束后被立即释放。综上,如果使用Api请求内单例(InstancePerApiRequest)来注册组件,那么这个组件只允许在AutofacWebRequest域内或其子域内被解析。

Our abnormality occurs in the analysis SingletonResolvablewhen the object. Before we registered it as a global singleton (SingleInstance), so it is in the 根域inside, and 根域(as the name implies) is the parent domain for all other domains. Analytical dependence is not allowed to look down towards the sub-field direction, only to find upwardly shining parent domain dependent. In summary, SingletonResolvablewe must not go AutofacWebRequest标签域within to find their dependence, so it can not get its dependencies ScopeToken, and again, we get thrown on top of an exception.

PerApiRequest1

Http request a single embodiment (InstancePerHttpRequest)

I do not have the above mentioned single embodiment the Http request (InstancePerHttpRequest), because of its nature and Api embodiment a single request (InstancePerApiRequest) are the same, but only for the HTTP request (WebApi relative terms). In fact, it is still used internally matched within a single case (InstancePerMatchingLifetimeScope), the same, the name used for matching tags also called AutofacWebRequest. Therefore, it is registered as a single embodiment of the Http request component may be registered as resolved single embodiment within Api request object, and vice versa.

Hopefully this article will help you better understand the life cycle of AutoFac under WebAPI project scope. A friend in need can freely download the source code and use.


Gerrod published in the May 13, 2014 .NET plate

End

After reading several issues that go back to see the beginning, is not it already have the answer?

Guess you like

Origin www.cnblogs.com/RayWang/p/11232911.html