Apr 9 2024

Software Architecture with C# 12 and .NET 8 is out!

The fourth edition of my book is out! You can buy it on Amazon

fourthedition

If you are a an aspiring .NET software architect, or a C# developer wishing to jump into the world of enterprice applications and cloud, this is the right book for you!

Software Architecture with C# 12 and .NET 8 puts high-level design theory to work in a .NET context, teaching you the key skills, technologies, and best practices required to become an effective .NET software architect.

This fourth edition puts emphasis on a case study that will bring your skills to life. You'll learn how to choose between different architectures and technologies at each level of the stack. You'll take an even closer look at Blazor and explore OpenTelemetry for observability, as well as a more practical dive into preparing .NET microservices for Kubernetes integration.

Divided into three parts, this book starts with the fundamentals of software architecture, covering C# best practices, software domains, design patterns, DevOps principles for CI/CD, and more. The second part focuses on the technologies, from choosing data storage in the cloud to implementing frontend microservices and working with Serverless. You'll learn about the main communication technologies used in microservices, such as REST API, gRPC, Azure Service Bus, and RabbitMQ. The final part takes you through a real-world case study where you'll create software architecture for a travel agency.

What’s new in this edition?

Topics are analyzed in greater detail and updated for .NET 8 and the latest Azure components. We have also added a new practical chapter on developing .NET applications for Kubernetes.

Finally, the book has been organized into three parts, creating a flow that will guide you in your journey to becoming a software architect: architectural fundamentals, .NET technologies, and practical coding with a great case study.

Highlights from the World Wide Travel Club case study:

  • Code examples in past editions restructured and re-organized into a case study
  • Examining user needs and managing requirements with Azure DevOps
  • Understanding the application domains and choosing cloud data storage
  • Implementing worker microservices with gRPC and RabbitMQ

How does this book differ from other books on C# 12 and .NET 8?

Although we are using .NET 8, the current Long Term Support version of .NET, and the book’s programming language is C# 12, we don’t only talk about technology. We connect different modern topics needed to design an enterprise application, and we enable you to understand how these techniques work together. This means the book focuses more on architectures, patterns, and design techniques, than on the syntax of the language and its features.

In a few words, the book assumes you already have basic knowledge of .NET and C#, driving you toward their usage for implementing cutting-edge applications based on microservices and modern architectures and design techniques.

Table of Contents

  1. Understanding the Importance of Software Architecture
  2. Non-Functional Requirements
  3. Managing Requirements
  4. Best Practices in Coding C# 12
  5. Implementing Code Reusability in C# 12
  6. Design Patterns and .NET 8 Implementation
  7. Understanding the Different Domains in Software Solutions
  8. Understanding DevOps Principles and CI/CD
  9. Testing Your Enterprise Application
  10. Deciding on the Best Cloud-Based Solution
  11. Applying a Microservice Architecture to Your Enterprise Application
  12. Choosing Your Data Storage in the cloud
  13. Interacting with Data in C# - Entity Framework Core
  14. Implementing Microservices with .NET
  15. Applying Service-Oriented Architectures with .NET
  16. Working with Serverless - Azure Functions
  17. Presenting ASP.NET Core
  18. Implementing Frontend Microservices with ASP.NET Core
  19. Client Frameworks: Blazor
  20. Kubernetes
  21. Case Study
  22. Case Study Extension: Developing .NET Microservices for Kubernetes

DO NOT MISS IT!

Francesco

    Tags: , , , , , ,

    Apr 1 2022

    Software Architecture with C# 10 and .NET 6 is out!

    The third edition of my book is out! You can buy it on Amazon

    imagebook3_thumb[1]

    If you are a C# developer wishing to jump into the world of enterprice applications and cloud, this is the right book for you!

    From how to collect requirements, and how to master DevOps, selecting the right cloud resources, Web API, front-end frameworks (ASP.Net MVC and Blazor) to microservices design principles and practice,. This new edition updates all subjects to the last cloud and .Net features and adds new chapters:

    • A detailed description of gRPC and of how to use it from .NET
    • A new chapter that explains in detail how to implement a worker microservice with  ASP.NET + gRPC, and .NET hosted services + RabbitMQ
    • An introduction to Artificial Intelligence and Machine Learning
    • An introduction to native clients (including a short review of .NET MAUI)

    Most of chapters give enough details to cover 90% of all practical applications and give all links and pointers to get more details.The only exceptions are the chapters about artificial intelligence and native clients that are just introductions to big subjects. However,  also there you will find complete learning paths to follow to become an expert.

    The first three chapters describe modern development processes, and how to collect and document functional and not-functional requirements. Example of requirement collection and management with Azure DevOps are given.

    Then the books moves to the basic cloud concepts and describes how to select the right cloud resources for each application.

    Chapter 5 explains the whole therory behind Microservices design, and lists .NET resources that plays a foundamental role in the .NET implementation of Microservices. A self-contained description of Docker, is given, too.

    Chapter 6 is dedicated to Kubernetes. There you will find all basic concepts and enough details to cover 90% of all practial applications.

    Chapter 7 and 8 are dedicated to data storage and how to interact with them with Entity Framework Core and other clients. There, you will find .the whole theory behind distributed databases, how to maximize read and write parallelism and how to choose between SQL and Not-SQL databases.

    Chapter 9 is about serverless and Azure functions. There, you  will find enough details to cover simple-middle complexity functions, and pointers on how to implement more complex functions.

    Chapter 10 is dedicated to  the concept of pattern and describes various patterns used throghout the book.

    Chapter 11 describes Domain Driven Design, that is the most used design methodology for microservices. Related patterns and their practical usage in .NET layered applications are given, too.

    Chapter 12 describes typical patterns of code reusability used in .NET applications.

    Chapter 14 gives a detailed description of gRPC and of its usage in .NET applications. Then, a complete implementation of a worker microservice with gRPC and ASP.NET CORE is given. Finally the same example is implemented with a .NET worker service and RabbitMQ.

    Further chapters describe SOA architectures  and their implementation with ASP-NET Core (13), ASP.NET Core and ASP.NET Core MVC(15) and Blazor (17).

    Chapter 16 puts in practice all concepts learned with ASP.NET Core MVC and Domain Driven Design with the implementation of a front-end microservice.

    Chapter 18 is a introduction to native .NET clients that includes also a first look to .NET MAUI. The description is not detailed since a detailed description would require another complete book, but native clients are compared with browser-based clients and frameworks (like Blazor) and complete learning paths are given.

    Chapter 19 is an introduction to artificial intelligence and machine learning. The basic principles of the main AI techniques are described, without going deep into the implementation details.Also. the basic theory about machine learning is given. Here the focus is on understanding which problems can be solved with machine learning and how many examples they require. A practical example of supervised learning is given.

    Chapter 20 is dedicated to best practices and code metrics.

    Chapter 21 and 22 are dedicated to DevOps and to the usage of Azure DevOps and GitHub actions.

    Finally chapter 23 is dedicated to testing, test-driven design, unit-tests and functional/acceptance tests.The chapter gives the complete theory and describes in detail xUnit, and Moq.Practical examples of functional tests based on AngleSharp and Selenium are given, too.

    DO NOT MISS IT!

    Francesco

    Tags:

    Dec 15 2021

    Move quickly your team to Asp.NET Core 6!

    Asp.NET Core online interactive course Start quickly with Asp.NET Core 6, with an interactive online course on the Educative platform

    Takeaway Skills

    ASP.NET Core
    MVC Pattern
    Razor and Razor tag-helpers
    Localization and globalization
    Option framework
    Dependency injection and hosted services
    Authentication and Authorization

    Start Now!

    Course Contents

    1. Razor Template Language

    2. Tag Helpers

    3. Controllers and ViewModels

    4. Validation and Metadata

    5. Dependency Injection

    6. Configuration and Options Framework

    7. Localization and Globalization

    8. Factoring out UI Logic

    9. Authentication and Authorization

    10. Publishing Your Web Application

    Try it|

    Tags: , , ,

    Jul 28 2020

    State Management and Error Recovery in Blazor WebAssembly part 3

    Category: Blazor | Asp.net coreFrancesco @ 05:35

    State Management and Error Recovery in Blazor WebAssembly part 2

    State Management and Error Recovery in Blazor WebAssembly part 1

     

    In this third an last part we will analyze how to save automatically the application state when the browser or the Blazor application tab are closed by the user.

    We will also add the possibility to ask confirmation of exiting the application to the user in case there are still open tasks. Since this can only be done via JavaScript

    we are forced to write some script and to connect it to C# code thanks to Blazor-JavaScript Interoperability (see here, and here). As a first step we must prepare to process and deploy JavaScript files.

    Processing and deploying JavaScript files

    JavaScript files contained in a library must be minimized and merged in a single file that will be deployed as a library internal resource. Minimization and merging of CSS and JavaScript files can be carried out with the help of the “BuildBundlerMinifier” Nuget package. Let install its last stable version in our “StateManager” project. After that let add a “js” folder in the project root, and let add a JavaScript file named “stateManager.js” inside of it. This file must be minimized and placed inside the library project wwwroot folder.

    “BuildBundlerMinifier” is informed about which file to process and how to process them through a json configuration file that must be called “bundleconfig.json” and must be placed in the library project root. Let add it and let place the following code in it:

    [
        {
            "outputFileName": "wwwroot/stateManager.min.js",
            "inputFiles": [
                "js/stateManager.js"
            ],
            "minify": {
                "enabled": true,
                "renameLocals": true
            },
            "sourceMap": true
        }
    ]

    Each object specifies how to create an output file, in our case "wwwroot/stateManager.min.js”. The input files to merge are listed in the “inputFiles” string array, “minify” specifies the minimization options, and finally “sourceMap” whether to create or not a source-map that maps instructions in the minimized file into their source instructions in the input files, in order to allow an easy debug.

    If now we right click on the state project and choose “rebuild”, the library project is rebuilt and our input JavaScript file is minimized and placed in the wwwroot folder. Clearly since our input file is empty also its minimized counterpart will be empty.

    Before starting our code let finish our configuration by recalling the minimized version of our JavaScript file in main program wwwroot/index.html file:

    <script src="_framework/blazor.webassembly.js"></script>
        //below the newly added JavaScript reference
        <script src="_content/StateManager/stateManager.min.js?v=6"></script>
    </body>

    In general a JavaScript file placed as a resource in a library can be referenced as “_content/<library name>/<file name>”.

    Now we need to design both our JavaScript side and our WebAssembly side code.

    We need a JavaScript function that adds both an event handler for the “beforeunload” event and for the “unload” event. We will call this JavaScript function from C# to enable the auto-save and exit confirmation features. Both JavaScript handlers, in turn, will call C# methods that will handle the events exploiting  all information available on the WebAssembly side.

    The C# side code

    The best place where to add our C# handler is the TaskStateService class. The unload handler must save the state in a default location, and possibly call a custom event. The code below do the job:

    public event Func<Task> BeforeUnload;
    public string  UnloadKey { get; set; }
    [JSInvokable]
    public async  Task OnUnload()
    {

        if (BeforeUnload != null)
            await BeforeUnload.Invoke();
        if (IsDirty())
            await Save(UnloadKey);
    }

    In the UnloadKey the user can place the name of the localStorage where to store the application state, BeforeUnload is an event where the developer can place some custom unload code, and finally the OnUnload method is the handler that will be called by JavaScript. The “[JSInvokable]” attribute makes it callable from JavaScript.

    OnUnload invokes custom events, if any, and then, if the application state is not empty, saves it to local storage.

    The beforeunload handler must return a not null, and not empty string if the user must be prompted for confirmation of leaving the application. In old browsers the string returned is used as prompt, but modern browser, instead, use a standard message:

    public string UnloadPrompt { get; set; }
    [JSInvokable]
    public  string OnBeforeUnload()
    {
        if (IsDirty()) return UnloadPrompt;
        else return string.Empty;
    }

    Both the above methods must be called by JavaScript handlers installed with “window.addEventListener”, as we will see in the next section.

    The JavaScript side code

    The JavaScript code consists in a “stateManager.AddUnloadListeners” function that receives as input a .Net reference to a TaskStateService instance and installs the JavaScript handlers that call the TaskStateService methods we defined in the previous section on this instance:

    (function () {
        window["stateManager"] = {
            "AddUnloadListeners": function (netObject) {
            try {
                window.addEventListener("beforeunload",
                    function (event) {
                        var res = null
                        try {
                            res = netObject.invokeMethod('OnBeforeUnload');
                        }
                        catch (ex) {
                            console.error(ex);
                        }
                        if (res) {
                            event.preventDefault();
                            event.returnValue = res;
                        }
                        else delete event["returnValue"];
                    });
                window.addEventListener("unload",
                    function () {
                        try {
                            netObject.invokeMethod('OnUnload');
                        }
                        catch (ex) {
                            console.error(ex);
                        }

                    });
            } catch (e) {
                console.error(e);
            }
        }
        }
    })();

    The code above is quite standard, the only peculiar snippets are the ones used to call the two .Net instance methods:

    res = netObject.invokeMethod('OnBeforeUnload');

     

    netObject.invokeMethod('OnUnload');

     

    Done! We need just to define a .Net function that invokes “stateManager.AddUnloadListeners”. We can define it as an extension method in the “Extensions/StateHandling.cs” file:

    public static async Task<IServiceProvider>
        EnableUnloadEvents(this IServiceProvider services)
    {
        var state = services.GetRequiredService<TasksStateService>();
        IJSRuntime jSRuntime = services.GetRequiredService<IJSRuntime>();
        await jSRuntime.InvokeVoidAsync(
                "stateManager.AddUnloadListeners", state.JsTeference);
        return services;
    }

    We are now ready to test our library.

    Putting everything together

    As a first step we must call the EnableUnloadEvents from the program.cs file of the main application:

     

    await built.Services.EnableUnloadEvents();
    await built.RunAsync();

     

    Now in the same file we need to update our InitializeState method, so that it set also the UnloadKey and the prompt for asking the user if he would like

    to quit the application or not :

    private  async static Task InitializeState(IServiceProvider services,
        string errorStateKey,
        string exitConfirm)
    {
        var state=services.GetRequiredService<TasksStateService>();
        state.ErrorKey = errorStateKey;
        state.UnloadKey = errorStateKey;
        state.UnloadPrompt = exitConfirm;
        if (await state.Load(errorStateKey))
        {
            await state.Delete(errorStateKey);
        }

    }

     

    After this change the main becomes:

    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");
                
        builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
        builder.Services.AddStateManagemenet();
        var built = builder.Build();
        await InitializeState(built.Services,
            "stateSaved", "There are unsaved changes. Quit anyway?");
        await built.Services.EnableUnloadEvents();
        await built.RunAsync();
    }

    Now just start the application, increment the counter, and then close the browser. You will be prompted for confirmation, confirm. The reopen the browser, you will see the same count you left before!

    It works!

     

    The updated code is available on Github here.

     

    Important: Some mobile browsers for smart phones are bugged and do not trigger the unload event when a browser tab is closed but only when you move to a different site. Therefore, when you target these devices you must provide also manual save.

     

    Here, you can see a complex application that shows what you can do with the state management technique described. The demo is based on the Blazor Controls Toolkit, which uses basically the same code described in these posts for its management. The trick for achieving similar results  is a careful design of the component state during each component design.

     

    That’s all for now! The next post will be about a new interesting subject.

    Francesco

    Tags: ,

    Jul 3 2020

    Blazor Controls Toolkit is out!

     Tree

    Start with all comforts, save 70% of your development time: a few declarations are enough to generate the markup you need  and  the whole server interaction code: forget about input fields, the right input filed is generated automatically based on the property type and ViewModel attributes! Changes tracking, to compute changes for the server, query tools to query local and remote data (also server side query tools to power-up your API controllers are included) , advanced components that include grids, detail lists and trees. Basically all components can be Drag and Drop enabled, you don’t need to handle the Drag and Drop process, because you drag automatically the data that are bound to your markup!

    Don’t worry about how to prevent the application you send to the client browser from being copied by hackers: you may rely on a double protection:

    1. Your code is protected by the best protector available on the market: Reactor, that is bundled with Blazor Controls Toolkit.
    2. Once Blazor Controls Toolkit is included as a dependency the whole application works properly only if it is validated by your server side Asp.net Core application with a complex cryptographic challenge. As a consequence your application is enabled to run properly only when it is connected with your web server!

    Below more details about Blazor Controls Toolkit features, but you can try also all of them live:

    • The equivalent of all Bootstrap JavaScript components.
    • A complete set of input controls that includes all Html5 inputs or their fallback when they are not supported by user browser, dropdowns and autocompletes.
    • Validation attributes , and other metadata attributes that enable the developer to define how to render and edit data in a purely declarative way! You just put a generic edit or display component in your markup and the Blazor Controls Toolkit generate automatically for you the markup that implements the behavior declared with your model attributes: space to reserve for each field, the right Html5 input and / or auto-complete to use, and so on.
    • Default validation messages, and default button text/labels are already localized in various languages, and the develpèer can customize all of them. Moreover, each customer can require the localization kit to insert his language in the Blazor Controls Toolkit, in case it is not supported, yet. This demo application shows all localized default messages, and labels. However, with the only exception of this introduction page all other application-specific contents are not localized.
    • Changes tracking, tracking of invalid objects, and model transactions. All handled with uniform interfaces throghout all components. They prevent futher processing on invalid objects, enable the user to revert changes, and computes all changes to send to the server (additions, deletes and modifications).
    • Utility components, like modals, Tabs, pagers, and navigation tools
    • All components and html fragments can be drag-drop enabled, and bound to models. As a result of the drop operation list elements or grid rows are moved to different positions or modify the model bound to the drop target.
    • Behaviors that enrich existing Html element and other components with further features like collapsing, fading, input focus, visibility spy, anchor target spy.
    • Complex customizable components like DataGrids,TreeViews, Detail views, and Detail lists. Each component has its default row and column template that the developer can replace with custom ones.
    • Query tools for filtering, sorting, and aggregating data.These tools include components that enable the user to select the desired operations, attributes to declare how to build each filter view, and OData tools to translate the desired operations in OData format, to retrieve data from OData enabled servers, and to OData-enable your Asp.net controllers.
    • All components are accessible, and can be operated easily with just the keyboard. After each operation, the focus is moved where more appropriate for continuing keyboard processing. If possible accessibility is enforced also on developer provided custom templates

    Tags: , ,

    Jun 24 2020

    State Management and Error Recovery in Blazor WebAssembly part 2

    State Management and Error Recovery in Blazor WebAssembly part 1

     

    In the first post of this series we discussed the various options available to represent state information in Blazor WebAssembly. Our conclusion was that the best option is to represent state information in data structures held in Blazor Dependency Injection engine, and to store them on disk (IndexedDb, localStorage) only when the user leaves the application or when the application is about to crash.

    We gave also a way to catch unhandled exceptions in order to save the application state before the application crashes. However, are we sure there are no other events that might cause the in-memory state be lost? Of course there are! User might inadvertently navigate to an external page, or he/she might close the application browser page / tab. Luckily, in all these circumstances we can exploit the onbeforeunload and onunload events. More specifically, in case there are uncompleted tasks and the user is about to leave the application we can use the onbeforeunload event to ask confirmation, and in case the user decides to proceed we can use the onunload event to save the state of all uncompleted tasks.

    So now we have a complete plan! We need to decide just how to represent all state tasks and how to save them on disk.

     

    Representing Tasks State

    We have seen that it is convenient to enclose each Task state in a containe classr, so each processor can easily detect when a task is being processed just by looking if the container is empty or not. In case a container is empty a new task can be created from scratch and put in the container so that also other pages can find it.

    Let modify the code of the first post to add a TasksStateService class. As a first step let  create a State folder in the StateManager library project. Then let move the StateContainer.cs file that is in the client project to this new folder. After that, let modify the file namespace to “StateManager” to yield:

    namespace StateManager
    {
        public abstract class StateContainer
        {
            public abstract object RoughState {get;}
        }
        public class StateContainer<T> : StateContainer
        {
            public T State { get; set; }
            public override object RoughState => State;
        }
    }

    We can add also a method that verify if a task is executing:

    namespace StateManager
    {
        public abstract class StateContainer
        {
            public abstract object RoughState {get;}
            public abstract bool IsRunning {get;}
        }
        public class StateContainer<T> : StateContainer
        {
            public T State { get; set; }
            public override bool IsRunning { get {
                    return State != null && !State.Equals(default); } }
            public override object RoughState => State;
        }
    }

    We can index all task States with a dictionary enclosed in the  TasksStateService class. Let add this class to the same state folder and let replace the scaffolded code with the following code:

    namespace StateManager
    {
        public class TasksStateService
        {
            private Dictionary<string, StateContainer>
                OverallState
                = new Dictionary<string, StateContainer>();
            public bool IsRunning(string x)
            {
                return OverallState.TryGetValue(x, out var state)
                    && state.IsRunning;
            }
            public bool IsDirty()
            {
                return OverallState.Values
                    .Any(x => x.IsRunning);
            }
        }
    }

    The IsRunning method returns whether the Task indexed by string x was started and not yet completed, while IsDirty returns whether there is or not at least

    a task that is running and needs to be saved.

    Now we can add also a method to get an existing state or create it if it doesn’t exist:

    public T Get<T>(string x, bool createNew)
    {
        if (OverallState.TryGetValue(x, out var state))
        {
            if (state.IsRunning) return (T)state.RoughState;
            else if (createNew)
            {
                var res = Activator.CreateInstance<T>();
                ((StateContainer<T>)state).State = res;
                return res;
            }
            else return default;
        }
        else if (createNew)
        {
            var container = new StateContainer<T>
            {
                State = Activator.CreateInstance<T>()
            };
            OverallState[x] = container;
            return container.State;
        }
        else return default;
    }

    Finally, we need a method that finishes a task, thus resetting its container:

    public void Finish<T>(string x)
    {
        if (OverallState.TryGetValue(x, out var state))
            ((StateContainer<T>)state).State = default;
    }

    With all this in place we can start using our TasksStateService, it is enough to add it to the Dependency Injection of the application project.

    For this purpose it is enough to add it to the AddStateManagemenet extension method in the “Extensions/StateHandling.cs” file of the StateManager

    library project:

    public static IServiceCollection AddStateManagemenet(
        this IServiceCollection services)
    {
        services.AddSingleton<IErrorHandler, DefaultErrorHandler>();
        services.AddLogging(builder => builder.CustomLogger());
        //add the line below
        services.AddSingleton<TasksStateService>();
        return services;
    }

     

    At this point the only missing piece is a state saving/reloading facility.

    Saving and reloading the application state

    Now we have to decide where and how to save the application state: localStorage can only store strings, while IndexedDb can store also object graphs that satisfy certain constraint.Unluckily, we can’t take advantage of the better opportunity offered by IndexedDb since we can’t move object graphs from WebAssembly to JavaScript, since Blazor interop features just cope with JSON-serializable graphs, that are essentially object trees.

    Unluckily, in the general case the complete state of a .Net Core Task is not a tree but a more complex graph. Therefore, we are left with the only option sketched below:

    1. Serialize state information with the powerful .Net Core binary serializer.
    2. Transform bytes returned by the binary serializer into a BASE64 string that can be moved to JavaScript as a string.
    3. Once we have state information represented as a string the simplest and more efficient storage option is localStorage.

    We can proceed as follows:

    1. When application start if there is a saved state we load it. We can also improve this step by asking the user if he would like to restore a previously saved  state.
    2. Once the user decides to load or discard the previous state we delete the stored state to prevent the application to load it again at next application start, in case no new state is saved.

    Of course our library project will provide just the save, load, and delete methods that the developer can use as he/she prefer to build a custom state management strategy.

    Serialization and Deserialization

    As a first step let write two protected methods that perform serialization and deserialization of the application state. It is not convenient to serialize the whole dictionary containing state information, it is better to filter just KeyValue pairs containing uncompleted tasks. The serialize method code is straightforward:

    protected string Serialize()
    {
        var toSerialize=OverallState
            .Where(m => m.Value.IsRunning)
            .ToList();
        string result=null;
        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, toSerialize);
            stream.Flush();
            result=Convert.ToBase64String(stream.ToArray());
        }
        return result;
    }

    The deserialize method is the exact converse:

     

    protected void Deserialize(string s)
    {
        byte[] binary = Convert.FromBase64String(s);
        using (var stream = new MemoryStream(binary))
        {
            var formatter = new BinaryFormatter();
            var res = formatter.Deserialize(stream)
                as List<KeyValuePair<string, StateContainer>>;
            OverallState = res.ToDictionary(m => m.Key, m => m.Value);
        }
    }

    BinaryFormatter requires that all classes to be serialized/de-serialized  be marked with the [Serializable] attribute. Therefore we must add it to both StateContainer, and StateContainer<T>:

        [Serializable]
        public abstract class StateContainer

     

        [Serializable]
        public class StateContainer<T> : StateContainer

     

    Now we miss just the routines to store retrieve, and delete serialized strings from localStorage.

    Interacting with the localStorage

    We need to call methods of window.localStorage from TasksStateService C# code, so we must inject the IJSRuntime interface in its constuctor (see here for more information about the usage of the IJSRuntime interface). Moreover, TasksStateService needs also an instance of the IErrorHandler interface to add an event handler to its OnException event that saves the state in case of errors.

    Therefore, let add both interfaces to the TasksStateService constructor, and let save both interfaces in private variables:

    IJSRuntime JSRuntime;
    IErrorHandler ErrorHandler;
    public TasksStateService(IJSRuntime jSRuntime,
        IErrorHandler errorHandler)
    {
        JSRuntime = jSRuntime;
        ErrorHandler = errorHandler;
        ErrorHandler.OnException += SaveError;
    }

    SaveError is the error handler that saves the state in case of exceptions. Let write just its skeleton, we will complete it in a short time:

    public async Task SaveError(Exception ex)
    {
                
    }

    The SaveError handler must be detached when TasksStateService is destroyed, so TasksStateService must implement IDisposable:

    public class TasksStateService: IDisposable

     

    public void Dispose()
    {
        ErrorHandler.OnException -= SaveError; ;
    }

     

    Now we have everything in place to write our Save method:

    public async Task Save(string key)
    {
                
        try
        {
            var s = Serialize();
            await JSRuntime
                .InvokeVoidAsync("window.localStorage.setItem", key, s);
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    In case of errors we just write the error message in the browser console.

    Load is completely analogous:

    public async Task<bool> Load(string key)
    {
        try
        {
            var s = await JSRuntime
                    .InvokeAsync<string>("window.localStorage.getItem", key);
            if (s != null)
            {
                Deserialize(s);
                return true;
            }
            else return false;
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            return false;
        }
                    
    }

    In case no state is found in local storage, Load returns false.

    We need also a Delete method to delete a previously recorder state after its recovery:

    public async Task Delete(string key)
    {
        await JSRuntime
            .InvokeVoidAsync("window.localStorage.removeItem", key);
    }

    Finally, we need a default name for the location where to store the saved state in case of unhandled exceptions, so we can fill also the SaveError method skeleton:

    public string ErrorKey { get; set; }
    public async Task SaveError(Exception ex)
    {
        await Save(ErrorKey);
    }

    Our Save/Load state Ready! Now, we need just to modify our test application so we can test our TasksStateService class.

    Testing the overall state management / error recovery logic

    As a firs step let add the initialization logic of our state management/recovery to the program.cs file of our Blazor client application. For this purpose let add the following method to the Program class:

    private  async static Task InitializeState(IServiceProvider services,
        string errorStateKey)
    {
        var state=services.GetRequiredService<TasksStateService>();
        state.ErrorKey = errorStateKey;
        if (await state.Load(errorStateKey))
        {
            await state.Delete(errorStateKey);
        }

    }

    It gets the TasksStateService singleton, sets the name chosen for saving the state in case of crashes, and then tries to load a previously saved state. If it succeeds the Load method returns true, and the saved state is removed from localStorage.

    This method must be called, at application start as soon as the application host has been built. Therefore, we need to replace the default code scaffolded by Visual Studio below:

    await builder.Build().RunAsync()

    With:

    var built = builder.Build();
    await InitializeState(built.Services,
        "stateSavedBeforeError");
    await built.RunAsync();

    We can test everything in the Counter page. As a first Step we must create a state class for the state of this page:

    namespace StateManagement.Client
    {
        [Serializable]
        public class CounterStatus
        {
            public int Counter { get; set; }
        }
    }

    State types MUST be reference types so that when the a component modifies a copy it gets from TasksStateService, the copy held in the TasksStateService is automatically updated.

    Moreover, each state object must have a default constructor, so it can be created, when needed, by the TasksStateService with the Activator class. Finally, it must be marked with the [Serializable] attribute for our serialization methods to work properly. Optionally, we may replace the [Serializable] attribute with the implementation of the ISerializable interface in order to provide a custom serialization logic.

    When the page starts it must require a state instance to the TasksStateService singleton that must be injected in the page with something like:

    private CounterStatus currentCount;
    protected override void OnInitialized()
    {
        currentCount = tasksStateService
            .Get<CounterStatus>("counter", true);
    }

    If a state object has been already created, that one is returned, otherwise a fresh one is created because we set the createNew parameter to true. The page will have a button to increment the counter and a button that throws an exception, so we can verify the state recovery capabilities of the application. The full code of the page is shown below:

    @page "/counter"
    @inherits ComponentBase
    @inject StateManager.TasksStateService tasksStateService
    <h1>Counter</h1>

    <p>Current count: @currentCount.Counter</p>

    <button class="btn btn-primary"
            @onclick="IncrementCount">
        Click me
    </button>
    <button class="btn btn-primary"
            @onclick="TryException">
        TryException
    </button>

    @code {
        private CounterStatus currentCount;
        protected override void OnInitialized()
        {
            currentCount = tasksStateService
                .Get<CounterStatus>("counter", true);
        }
        private void IncrementCount()
        {
            currentCount.Counter++;
        }
        private void TryException()
        {
            throw new Exception();
        }
    }

    Now let start the application, go to the counter page, increment a few times the counter, and then let click the “TryException” button. The application crashes and we are prompted to reload the browser page. When we reload the page the value of the counter is retained! We were able to recovery the application state.

    If you don’t want to mark all state objects with a [Serializable] attribute, you can mark the Serialize and Deserialize methods as virtual, and override them with third parties serializer. Among them a good one is SharpSerializer. It overcomes the needs for the [Serializable] attribute but has other limitations.

     

    Thats all for now! The code respository of the first post has been updated with the new code.

    In the next post of this series we will add support for the onbeforeunload and onunload events.

    Francesco

    Tags: ,

    Nov 14 2018

    My new book: Hands-On TypeScript for C# and .NET Core Developers.

    Category: Angular | TypeScript | JavaScript | Asp.net coreFrancesco @ 03:28

    An exhaustive introduction to modern client side techniques for .Net Web developers.

    All you need to learn for using modern client-side frameworks like Angular in a single place! I conceived this book to avoid the frustration of a never-ending search for the knowledge required to afford a modern JavaScript framework. This book consolidates in a single place all the knowledge required to implement a modern "rich-client" Web application using a non-trivial JavaScript / TypeScript code base:TypeScript, ECMAScript 6 features, JavaScript modules, TypeScript library development  and testing, bundling modules with WebPack, and the Angular single page application framework.

    TypescriptCover_

    JavaScript was initially conceived to enrich server-generated HTML pages with JavaScript widgets, including date pickers, autocomplete, tabs, and so on. With the increase in available internet bandwidth, and the enhanced computational power of desktops, laptops, mobile devices, and smartphones, in order to ensure faster responses to all user inputs, and to be in a position to better exploit all available resources, increasingly, application logic moved from the server-side to JavaScript code on the client machine, that is, until the diffusion of single page applications, where the entire application logic runs in JavaScript on the client machine and the server's role is limited to handling shared data, as well as authentication / authorization logic.The increasing complexity of JavaScript code bases led to the definition of new JavaScript specifications and toolsets to bring JavaScript from the level of a scripting language to that of modern object-oriented languages, like Java, C#, and C++. Among the significant changes and tools, the following are worthy of mention:

    1. The new ECMAScript 6 specifications that turn JavaScript into an advanced object-oriented language.
    2. The new TypeScript language that adds types to JavaScript to enable better compilation-time checks, and implements almost all new ECMAScript 6 features that are not yet supported by all browsers. What makes TypeScript great is that it is JavaScript of the future plus types, and that it transpiles to browser-compatible JavaScript.
    3. JavaScript library repositories, such as NPM, that are capable of automatically tracking dependencies among libraries.
    4. JavaScript test frameworks, such as Jasmine.
    5. The organization of JavaScript code into modules, and the usage tools called bundlers that facilitate the linking of several interdependent modules into a few JavaScript files to add to each HTML page.
    6. Frameworks such as Angular, that contain everything needed to implement single page applications.

    Somewhat unfortunately, knowledge of the above subjects is spread across a variety of locations, so it is very frustrating when you come to write modern "rich-client" web applications. For instance, if you decide to learn Angular, you'll discover that you need to learn TypeScript beforehand, and then you'll discover that a knowledge of TypeScript is not enough either, because you also need to learn more about ECMAScript 6 and JavaScript modules. Finally, if you have resisted hitherto, you'll discover that you also need to learn about bundling and WebPack.

    This book consolidates in a single place all the knowledge you require to implement a modern "rich-client" web application using a non-trivial JavaScript/TypeScript code base:TypeScript, ECMAScript 6 features, JavaScript modules, TypeScript library development  and testing, bundling modules with WebPack, and the Angular single page application framework.

    What the book covers in detail.

    Chapter 1, Introduction to TypeScript, explains how to install and configure TypeScript transpiler, TypeScript base types, variable declarations, and scoping. It also discusses TypeScript's mission, and how TypeScript types can help you to write, debug, and maintain your code bases.

    Chapter 2, Complex Types and Functions, explains the basics of the language: arrays, tuples, interfaces, and function declarations. It also explains how to define new types by performing operations on existing types, and how to simplify your code with ECMAScript 6 destructuring and spread.

    Chapter 3, DOM Manipulation, covers TypeScript types used to describe and manipulate the DOM, and how to use JavaScript libraries such as jQuery from TypeScript.

    Chapter 4, Using Classes and Interfaces, covers TypeScript object programming, classes, interfaces, inheritance, and interface implementations. A complete code example explains how to architect a modular application with the help of abstract classes, interfaces, and inheritance.

    Chapter 5, Generics, covers TypeScript generics, and how to define constraints on generics and type-mappings based on generics. TypeScript generics mimic C# generics, but, like C++ generics, they disappear in the compiled code.

    Chapter 6, Namespaces and Modules, covers TypeScript's modular organization of code based either on namespaces, or on ECMAScript 6 modules. While TypeScript modules are completely based on ECMAScript 6 modules, they may run also in environments that do not support ECMAScript 6 modules, since ECMAScript 6 syntax may be processed by JavaScript bundlers such as WebPack, or transpiled in the syntax of AMD, CommomJs, or
    SystemJs loaders, that run on all platforms/browsers.

    Chapter 7, Bundling with WebPack, contains a quite complete and practical description of WebPack, and of its more frequently used modules and loaders. Here, the reader can learn everything that is worth knowing in terms of using WebPack with most modern JavaScript frameworks/libraries.

    Chapter 8, Building TypeScript Libraries, describes how to develop a TypeScript library package with VS Code, how to test it with Jasmine, and how to package it as an NPM package.

    Chapter 9, Decorators and Advanced ES6 Features, covers all ECMAScript 6 features, such as Symbols, Iterators/Generators, and Promises, that were not covered in previouschapters. The chapter also covers TypeScript's async/await notation, that is transpiled to Promise-based code, and TypeScript decorators and metadata that are important Angular building blocks.

    Chapter 10, Angular ASP.NET Core Project Template, introduces Angular architecture, and describes all the parts an Angular CLI project is composed of, and how to configure a project. The chapter then lists all Angular building blocks, focusing on modules,
    components, and data binding.

    Chapter 11, Input and Interactions, explains how to take and validate user input, and how to customize standard data binding behavior with pipes and life cycle hooks. The chapter also covers the interaction of components through JavaScript and custom events.

    Chapter 12, Angular Advanced Features, covers the details of attribute and structural directive usage and definition. The chapter also explains how to customize components with content projection (that is, filling predefined holes with input content), and how to improve the user interface with Angular animations, giving all details of Angular animation syntax.

    Chapter 13, Navigation and Services, covers all Angular features conceived for complex applications, navigation among application pages, and how to dynamically load Angular modules. It also covers how components can communicate with the server using Angular HTTP Client class, and how HTTP Client and other services can be injected into components' constructors with the help of dependency injection. It also describes how to test components and other Angular classes.

    Tags: , , , , ,

    Jan 15 2018

    2.1.0 release of the Mvc Controls Toolkit Core

    Category: MVC | Asp.net | Asp.net coreFrancesco @ 05:53

    2.1.0 release of the #AspNetCore  Mvc Controls Toolkit. See release notes  and live examples.

    Tags: ,

    Oct 4 2017

    Building Web applications with Knockout.js and ASP.NET core

    Category: Asp.net | Asp.net core | MVC | TypeScript | WebApi | JavaScriptFrancesco @ 05:40

    Amongst all the client side frameworks backed by big companies, React.js and Angular.js appear to be the most popular. However, Knockout.js still maintains a good market share, thanks to its interesting peculiarities.

    Knockout is based on an MVVM paradigm similar to Angular.js, but unlike React.js. While it is adequate for modular complex applications, at the same time, it is very simple to mix with server side templating, similar to React.js, but unlike Angular.js….Read full article

    Contact us if you want to learn more

    aspnet-core-running-spa

    Tags: , ,

    Sep 27 2017

    2.0.0 release of the Mvc Controls Toolkit compatible with Asp.net Core 2.0

    Category: Asp.net core | MVC | Asp.netFrancesco @ 07:15

    2.0.0 release of the #AspNetCore (2.0 and 1.1) Mvc Controls Toolkit. See release notes  and live examples.

    Tags: ,