Series is introduced

Five Minutes of DotNet is a blog series that uses your fragmented time to learn and enrich your.NET knowledge. It covers all aspects of the.net architecture that might be involved, such as C# details, AspnetCore,.net knowledge in microservices, and so on. 5min+ does not mean more than 5 minutes, “+” is an increase in knowledge. So, it allows you to spend less than 5 minutes to improve your knowledge base.

The body of the

While reading the source code of AspNet Core some time ago, I found a static class called ChangeToken. It might look something like this:

public ActionDescriptorCollectionProvider(IEnumerable
       
         actionDescriptorProviders, IEnumerable
        
          actionDescriptorChangeProviders
        
       )
{
    _actionDescriptorProviders = actionDescriptorProviders
        .OrderBy(p => p.Order)
        .ToArray();

    _actionDescriptorChangeProviders = actionDescriptorChangeProviders.ToArray();

    //here!!
    ChangeToken.OnChange(
        GetCompositeChangeToken,
        UpdateCollection);
}  
Copy the code

In retrospect, it seems to have more than I see it twice, once in Microsoft. Extensions. FileProviders package also have found inside. Today, after a long time of confusion, I had an opportunity to scratch it and see what it really was.

In fact, ChangeToken has an article dedicated to it in Microsoft’s official AspNet Core tutorial documentation: detecting changes using Change Tokens in ASP.NET Core. But this article I personally feel a little bit of emphasis on the use, and the principle of the desalination. How can this satisfy our programmer’s exploration desire 😏, must baidu wave again for sure, then ……………… Only one article…. . (Manual blog garden niubi!)

The observer?

In fact, from the first sentence description in MSDN and the name of the class, we can still read the general meaning of it. Isn’t it something like the observer model? When something changes, an operation is performed.

So can’t you just delegate to subscribe? Let’s think about what it would look like to operate with a traditional delegate.

Action myAction = () => { Console.WriteLine("The men are coming!); };
myAction += () => { Console.WriteLine("The dog barks!); };
myAction += () => { Console.WriteLine("The cat will meow!); };
Copy the code

Something like that. Both cats and dogs bark when they observe people coming.

But if you write it this way, you’ll see that the three things in the demo above (people, cats, and dogs) are very closely related. In terms of code, maybe we’ll create three classes later, and all of them will interact with each other by direct reference. If there are more types, it can turn into a nightmare.

So is there a good way? There must be.

Accepted as reasonable?

I’ve always felt that all code can be explained by the little things around us. So, I tell a story 😂.

Let’s think about how we were connected 30 years ago. Well………………… It does seem hard to get a hold of. Because transportation and communication tools were not developed at that time, people could only communicate by meeting each other. So, when I want to tell someone something, I have to go to their house and I can’t do it until I see them in person or with their family. It would have been better, of course, to send a message to someone else, but that would have required me to see the broker and to trust him.

In that “Communication is basically yelling; Transportation basically depends on walking; Back in the days when the law was largely governed by dogs, it seemed to pay to be loud.

So how do we connect now? Silently, I pulled the bird phone out of my pocket (bird phone, fighter phone, oh yeah). In this society, who doesn’t have a mobile phone ah, even if there is no mobile phone maybe also have a phone watch. 🤔

OK, back to the question above. Do you have any inspiration? When one class completes an operation, the next class needs to react. At first, we might explicitly call class B directly from class A (only by going to his home). Later, we can choose a commission (find a middleman to carry the message, or a postman, etc.). Now, we can choose a phone to do it.

So what is this “phone” in the code? Everyone who needs to keep in touch has to have it, and as long as the phone is online, it can communicate, and everyone has the phone and nobody thinks it’s weird? CancellationTokenSource. Like it or not, have you introduced it in most categories of the project and not been surprised at all?

So when everyone agrees on something like a TokenSource, it feels normal, even though we introduce the System.threading namespace every time we use CancellationTokenSource.

CancellationTokenSource

Let’s use CancellationTokenSource to trigger an observation action:

var cancellationTokenSource = new CancellationTokenSource();

cancellationTokenSource.Token.Register(() =>
{
    Console.WriteLine($"{nameof(cancellationTokenSource)}Changes, triggering a callback.");
});

cancellationTokenSource.Cancel();
Copy the code

Isn’t that easy? CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource CancellationTokenSource Since its inception, CancellationTokenSource has been widely used in asynchronous programming because of its thread-safety nature.

At this point you may ask, does this have anything to do with the ChangeToken we mentioned today? Take your time, let’s take a closer look at today’s main characters:

public static class ChangeToken
{
    public static IDisposable OnChange(Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer);
}
Copy the code

This class simply provides a static method of OnChange that requires a parameter that returns type IChangeToken. CancellationToken CancellationToken CancellationToken CancellationToken CancellationToken CancellationToken CancellationToken Yes, that’s right. The official name for this kind of thing is actually “token”. So, as you might guess, it might have a method for registering callbacks:

public interface IChangeToken
{
    bool HasChanged { get; }
    bool ActiveChangeCallbacks { get; }

    IDisposable RegisterChangeCallback(Action<object> callback, object state);
}
Copy the code

Well, that seems to fit our suspicions. So what is the point of its existence? High-level abstraction! Just like the “mobile phone” we just said, mobile phone is an abstract concept, and “OPPO mobile phone”, “Huawei mobile phone”, and my “Bird mobile phone” are its concrete realization. We may use different phones in different circles.

For example, the following code:

Console.WriteLine("Start monitoring folder C :\\temp");

var phyFileProvider = new PhysicalFileProvider("c:\\temp");
IChangeToken changeToken = phyFileProvider.Watch("*. *");
changeToken.RegisterChangeCallback(_ =>
{
    Console.WriteLine("Folder changes detected!" + _);
}, "xiaoming");

Console.ReadLine();
Copy the code

Code is quoted from:Jackletter blog

Looks like a carrier called PhysicalFileProvider sent me a “phone” (token). Once I have this token, the carrier can contact me, and when it contacts me, I can respond accordingly. For example, the top is to print out a line of words.

In the “physical file” sphere, the IChangeToken’s real body is called PollingFileChangeToken; In the “configuration system” community, the actual IChangeToken is called ConfigurationReloadToken.

What if we want to implement our own IChangeToken? Remember the CancellationTokenSource at the top? Since.net has provided us with a thread-safe and straightforward tool to use, we are welcome:

public class MyOwnChangeToken : IChangeToken
{
    public CancellationTokenSource _cts = new CancellationTokenSource();

    public bool ActiveChangeCallbacks => true;

    public bool HasChanged => _cts.IsCancellationRequested;

    public IDisposable RegisterChangeCallback(Action<object> callback, object state) => _cts.Token.Register(callback, state);

    public void MyOwnChange() => _cts.Cancel();
}
Copy the code

In “my own circle”, I can use MyOwnChangeToken. When the outside world obtains my IChangeToken, I can trigger MyOwnChange to notify them.

In fact, most ichangeTokens in.net Core use CancellationTokenSource internally.

Understanding IChangeToken makes it easy to understand ChangeToken as a static class, which must be implemented as a utility class.

To put it bluntly, we can subscribe directly using static methods:

 ChangeToken.OnChange(
    () => physicalFileProvider.Watch("*. *"),
    () => Console.WriteLine("Folder changes detected!"));Copy the code

So you might say, can’t I just subscribe using the RegisterChangeCallback method above? What’s the difference between them? The answer is: “Number of calls.” With the RegisterChangeCallback method, only one callback is executed, because the token is actually invalidated after it is used once. So the code above, which monitors file changes, doesn’t actually perform a callback when the file changes a second time.

Using a static class called ChangeToken, it can help you constantly get new tokens and register the corresponding callbacks, so you can ensure that multiple changes can trigger callbacks.

So look at the code above ChangeToken. OnChange (() = > physicalFileProvider. Watch (” *. * “),…). The phyFileProvider provides us with a token, and when the token changes, we have the opportunity to complete the operation. () = > physicalFileProvider. Watch (” *. *) “this code we can call it” token “production process, and () = > Console. WriteLine (” detect folder has changed!” ) is called “token consumption process.” What ChangeToken does is that when a consumer spends money, the production process is regenerated into a token, and the consumption process is mounted on the token so that it is guaranteed to be “observed” all the time.

In fact, ChangeToken implementation is very simple, you can refer to its source code: Github source code.

conclusion

In fact, this issue mainly introduces IChangeToken and ChangeToken. In fact, we also have related to IChangeToken in the later article. It is also one of the most important interfaces in.NET Core, and it is necessary to understand its “responsibilities” and “principles”. This will make it easier for us to learn later about the “different circles” in which it resides, such as the physical file system mentioned in this article.

Finally, secretly say: creation is not easy, point a recommendation…..