You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<p>In modern websites, some pieces of information may appear in multiple places, such as the profile avatar, the website language, theme, etc. One way to ensure data consistency and accuracy is to implement the Single Source of Truth (SSOT) pattern, which centralises all data instead of distributing it across multiple components. In this tutorial, we will go through:</p>
<p>In Blazor, maintaining consistent data across components is essential, particularly in features like profile management. Consider the scenario profile management as in the image:</p>
<p>When the user inputs data and the change is accepted, it should update the display name on the menu bar and the profile page. Without SSOT, developers might risk:</p>
17
+
<ul>
18
+
<li>Data inconsistency and inaccuracy.</li>
19
+
<li>Difficulty in updating data in multiple places.</li>
20
+
<li>An unfriendly SPA where users have to reload the page to see new data.</li>
21
+
</ul>
22
+
<p>With data centralised with SSOT, developers can easily find the data needed to display. Furthermore, when changes are applied to the data source, all components will be automatically updated. This ensures data consistency and accuracy throughout the app and reduces the effort to maintain such data.</p>
23
+
<hrclass="my-4" />
24
+
<h1>Implementation Approaches</h1>
25
+
<p>There are 2 ways to implement the SSOT pattern in Blazor:</p>
26
+
<ul>
27
+
<li>Using <code>CascadingValueSource</code>: This method leverages a cascading parameter with a source that automatically notifies and updates all dependent components when the central data changes. It’s ideal for real-time updates, such as reflecting a new display name across the app, with minimal manual intervention.</li>
28
+
<li>Using a Scoped Service: This approach involves a service registered as scoped, requiring manual updates to components via event handling or state management. It offers more control but demands additional code, making it suitable for legacy projects or complex state logic.</li>
29
+
</ul>
30
+
<h3>Best practice</h3>
31
+
<p>For new projects, <code>CascadingValueSource</code> is typically the better option due to its simplicity and automatic updates. Use a scoped service when integrating with older codebases.</p>
<li><strong>Define the data-holding class</strong>: Create a class with a <code>CascadingValueSource<T></code> property, where <code>T</code> is the class itself:</li>
36
+
</ol>
37
+
<prelanguage="csharp">public class CascadingParameterSharedData
38
+
{
39
+
public int Value { get; set; }
40
+
41
+
public CascadingValueSource<CascadingParameterSharedData> Source { get; set; }
42
+
}</pre>
43
+
<olstart="2">
44
+
<li><strong>Register the class in </strong><code>Program.cs</code>: While registering the class, set the source value.</li>
public CascadingParameterSharedData SharedData { get; set; }
62
+
63
+
public async Task ChangeValue()
64
+
{
65
+
var random = new Random();
66
+
SharedData.Value = random.Next(1, 100);
67
+
await SharedData.Source.NotifyChangedAsync();
68
+
}
69
+
}</pre>
70
+
<blockquote>After modifying the shared data (e.g., <code>SharedData.Value</code>), always invoke <code>NotifyChangedAsync</code> to propagate the change. Failing to do so will leave other components using the old value, breaking the SSOT principle and causing rendering discrepancies.</blockquote>
71
+
<hrclass="my-4" />
72
+
<h1>Scoped Service Approach</h1>
73
+
<ol>
74
+
<li><strong>Define the data-holding class</strong>: Create a class with data and a notification mechanism:</li>
75
+
</ol>
76
+
<prelanguage="csharp">public class BlazorSchoolTransferService
77
+
{
78
+
public string Message { get; set; } = "";
79
+
public event EventHandler MessageChanged = (sender, args) => { };
80
+
81
+
public void NotifyChanged()
82
+
{
83
+
MessageChanged.Invoke(this, EventArgs.Empty);
84
+
}
85
+
}</pre>
86
+
<olstart="2">
87
+
<li><strong>Register the class in</strong><code>Program.cs</code>:</li>
<li><strong>Event Subscription</strong>: Every component accessing data must subscribe to change event (e.g., in <code>OnInitialized</code>) and call <code>StateHasChanged</code> to update the UI when notified. The number of events depends on the requirement. It could be one event for multiple properties or one event per property.</li>
129
+
<li><strong>Notification</strong>: After modifying data, always call notify method to propagate the change to all subscribers.</li>
130
+
<li><strong>Unsubscription</strong>: Unsubscribe from the event in <code>Dispose</code> to prevent memory leaks.</li>
0 commit comments