Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
210 views
in Technique[技术] by (71.8m points)

c# - Blazor CascadingParameter vs singleton DependencyInjection

I have recently learned that you can provide cascadingValues to the entire project by wrapping the Router component in the provider Microsoft doc. How is this different to using dependency injection with a singleton pattern? (I know how injection works, I mean performance and architecture wise)

Which do you think is better to use?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There has been some discussion about the performance impact of CascadingValues. I can recommend this article (it is an excellent tutorial as well).

As you mentioned, there are two aspects: performance and architecture.

Performance

I'd see [CascadingParameter] are costly compared to [Parameter] or "normal" fields and properties. Each component down the tree, subscribe to the [CascadingParameter] changes. If the value changes, a new cycle of ParamtersSet is started, which could lead to a call to the render tree and check if something in DOM needs to be changed. So, even if no rerendering is required, the process to reach this conclusion consumes time. The more components, the more depth the tree has, the slower this process becomes.

Architecture

To discuss this aspect, we can think about the CascadingAuthenticationState. It is part of the authentication framework for Blazor and provides access to check whether a user is authenticated or not. It is implemented as a cascading value instead of a singleton. Components down the tree, like menus, can easily use this value to hide/show items for non authenticated users. Why?

Frequency of change and impact to the DOM

A question to answer is regarding the impact of the change of a cascading value. If a user logins/log out, it is reasonable to assume that this will trigger a huge DOM change. So, checking a huge part of the tree (if not the entire based on where the cascading value is placed) is not overhead.

Besides, it is a good guess that there will be few changes to AuthenticationState during the lifetime of the application.

Simplicity

The menu component uses the AuthorizeView which uses the cascading parameter of Task<AuthenticationState>.

<AuthorizeView>
    <Authorized>
        <li><a href="/admin">Admin</a></li>
    </Authorized>
    <NotAuthorized>
        <li><a href="authentication/login">Log in</a></li>
    </NotAuthorized>
</AuthorizeView>

This snippet is easy to read, and you can understand it very quickly. If you did the same thing with a singleton service, you would need to implement the "communication" between component and service. It would be best to implement a subscribe/unsubscribe scenario, maybe using events or more advanced technologies. You will need to write your own code, and again don't forget to write your implementation of IDisposable to unsubscribe.

Cascading parameters are focused on UI

While a singleton service is a very generic approach to solve many different issues, cascading values are specially designed to solve UI update problems. They are doing it very efficiently. In the case of the AuthenticationState, it uses a specialized view.

There is space for arguments if Blazor isn't all about UI, but with modern, rich features GUI, sometimes we have a layered approach inside the application. So, with UI, I mean the part of the application ultimately responsible for rendering.

Services could be used outside of this inner UI layer, through the entire application, and then reused in the UI as well, while cascading parameters could only be used inside components.

Cascading parameters are (mostly one way)

A cascading parameter is "owned" by a component. Usually, the component where it is declared. From that point, it is passed down the tree. All other components can consume it. There is no straightforward, easy, and scalable way to update a value from a child component. As I said, mostly, there are ways to do it, but it is a dirty path, in my view.

Summary

As with a lot of other technologies, the answer is: It depends on the use case.

top-down usage: cascading values

Components need to update the value: service

many changes: It highly depends on the tree structures if easiness outweighs the performance impact.

use outside and inside the inner UI layer: service

And, another approach to this problem could be something like Blazor Component Bus

Update

In addition to what was said by Just the benno, I may add that there is a fundamental difference between a CascadingValue component and a Singleton service regarding their scope. A Singleton service, in Blazor Server App, is singleton across the lifetime of the application, across multiple connections, and across multiple browsers... while CascadingValue component is scoped to the current instance of your app. Changing the state of an object provided by a CascadingValue component has no effect on a new instance of the app. But if you change the state of a Singleton service in an instance of your app, this change will be propagated to other instances of your app. Try to imagine what would be the implications of implementing the functionality of the CascadingAuthenticationState component as a Singleton service rather than CascadingValue.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...