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: , , ,

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: ,

Aug 1 2017

1.2.7 release of the Asp.net core Mvc Controls Toolkit

Category: Asp.net | MVC | Asp.net coreFrancesco @ 21:29

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

Tags: ,

Jul 13 2017

#Asp.net Core Mvc Controls Toolkit complete tutorial on @DotNetCurry

Category: MVC | Asp.net core | Asp.netFrancesco @ 22:30

Available complete Mvc Controls Toolkit Core tutorial on @DotNetCurry. Enjoy it!

Build a complete ASP.NET MVC Core web application from the DB layer to the UI using the Mvc Controls toolkit core free library. We will also show data from a database in a paged Grid with filtering/sorting/grouping and add/edit/delete capabilities….Read full article,

 

mvc-controls-toolkit-install

Tags: ,

Jun 26 2017

New 1.2.5 release of the Asp.net core Mvc Controls Toolkit

Category: Asp.net | Htnl5 fallback | MVCFrancesco @ 05:55

The new 1.2.5 release of the Asp.net core Mvc Controls Toolkit is ready for download. Play live with ajax sorting, filtering and grouping. Now, thanks to full ajax support, you may have several independent grids in the same page! Each grid may have an ajax “back button” to go back to its previous query.

Several Grid

Install in your project and follow Quickstart

Tags: ,

May 9 2017

Customization And Localization Of ASP.NET Core MVC Default Validation Error Messages

Category: MVC | Asp.net core | Asp.netFrancesco @ 00:25

This time my post has been published on the MSDN Blog! Enjoy it!.

………Moreover, the new validation provider architecture made it easy to override the default messages built-in, in the .Net validation attributes with customized default messages defined in resource files. This way, the user can provide global custom messages once and for all, thus avoiding the burden of having to specify an error message in each occurrence, of each attribute.This article goes into detail about how to customize both all ASP.NET MVC specific error messages, and all default messages coming from validation attributes……Read full article

Tags: , , , , ,

May 7 2017

Asp.net core: Deserializing Json with Dependency Injection

Category: MVC | Asp.net core | Asp.netFrancesco @ 21:30

Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces

In a previous post I discussed how to model bind Interfaces/abstract classes with the help of Asp.net core dependency injection features. However, the technique discussed there doesn’t apply to Json data added to the request body, since request body is processed by the BodyModelBinder that, in turn, selects a formatter based on the request content-type header. The formatter for “application/json” is a wrapper for Json.net, so the code of our previous “interfaces model binder” is never called, and also if called it wouldn’t be able to process Json data in the request body.

The behavior of Json.net serializer/deserializer may be customized through an MvcJsonOptions options object.In this post I am going to show how to modify Json.net behavior so that it attempts to use Dependency Injection to create any .Net object before creating it through its constructor. This, will enable not only the deserialization of interfaces, but also the customization of object creation through Asp.net Core DI engine.

Preparing the project

As a first step let create a new asp.net core project named “JsonDI”:

Project

Select “no authentication” to simplify the code created by VS project template.

Then let create a new folder called “Models” and add it the following “IPerson.cs” file, that contains both an interface definition and its default implementation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JsonDI.Models
{
    public interface IPerson
    {
       string Name { get; set; }
       string Surname { get; set; }
    }
    public class DefaultPerson: IPerson
    {
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

Now let modify the code of the Home controller to add an HttpPost for the Index action:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using JsonDI.Models;

namespace JsonDI.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Index([FromBody] IPerson model)
        {
            return Json(model);
        }
        ....
        ....

We need an Ajax call to send Json data to our newly created HttpPost action method. Go to the Index.cshtml file in the Views/Home folder and substitute its code with the code below:

@{
    ViewData["Title"] = "Deserialization with DI";
}

<h2>@ViewData["Title"]</h2>

<form asp-action="Index" asp-controller="Home">
    
    <button data-url="@Url.Action("Index", "Home")" type="button" class="test btn btn-default">Submit</button>
</form>
@section Scripts
{
    <script type="text/javascript">
        $(".test").click(function (evt) {
            var url = $(evt.target).attr("data-url");
            $.ajax(url,
                {
                type: 'POST',
                data: JSON.stringify({
                    name: "Francesco",
                    surname: "Abbruzzese"
                }),
                success: function () { alert("message received"); },
                contentType: "application/json",
                dataType: 'json'
            });
        });
    </script>
}

Now place a breakpoint here:

Breakpoint

…and run the project.

When we click the “Submit” button an Ajax request is issued to our HomeController that contains an IPerson interface in the request body. However, when the breakpoint is hit, we may verify that the model parameter is null! In fact Json.net is not able to deserialize the IPerson interface because it doesn’t know how to create an instance of it.

Enriching Asp.net Core Dependency Injection.

Pieces of code that need Asp.net Core Dependency Injection engine creates type instances do it through the IServiceProvider interface that contains the unique method “GetService(Type t)”. Accordingly, we may create a type instance calling GetService or some other extension method that, in turn, calls it, but we are not able to ask if a type has been registered with the DI engine. This problem may be solved using a third party DI engine, such as Autofac. In this section we will show how to add this capability without using third party DI engines.

Let add an “Extensions” folder to the project. We will place there all extensions we need to have Json.net use DI. As a first step let define an interface containing all features we need and that are not exposed by IServiceProvider:

using System;

namespace JsonDI.Extensions
{
    public interface IDIMeta
    {
        bool IsRegistred(Type t);
        Type RegistredTypeFor(Type t);
    }
}

I called it IDIMeta because it provides meta-information about the content of the the DI container. The first method returns if a type has been registered with the DI engine, and the second returns the type that will be actually created when requiring an instance of the registered type.

The actual implementation of the above interface uses the IServiceCollection available in the ConfigureServices method of the Startup.cs class to collect all information needed to implement the interface methods in a dictionary :

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;

namespace JsonDI.Extensions
{
    public class DIMetaDefault: IDIMeta
    {
        IDictionary<Type, Type> register = new Dictionary<Type, Type>();
        public DIMetaDefault(IServiceCollection services)
        {
            foreach (var s in services)
            {
                register[s.ServiceType] = s.ImplementationType;
            }
        }
        public bool IsRegistred(Type t)
        {
            return register.ContainsKey(t);
        }

        public Type RegistredTypeFor(Type t)
        {
            return register[t];
        }
    }
}

As a final step we need to register IDIMeta itself in the DI engine, by adding the code below to the ConfigureServices method of the Startup.cs class:

services.TryAddSingleton<IDIMeta>(s =>
{
    return new DIMetaDefault(services);
});

Later on we will show the whole code to be added to the ConfigureServices method of the Startup.cs class.

Customizing Json.net behavior

Now we are ready to customize Json.net behavior! The way Json.net serializes/deserializes types is specified by ContractResolvers. ContractResolvers return a “contract” for each type that contains all information on how to deal with that type. In particular each contract specifies how to create an instance of the type and how to fill its properties. The way to fill type properties may be customized by passing a custom converter in the “Converter” property of the contract. However, we don’t need custom converters since we must customize just the way types are created.

Our custom ContractResolver inherits form the built-in “CamelCasePropertyNamesContractResolver” that is the one used as a default by Asp.net Core:

using System;
using Newtonsoft.Json.Serialization;

namespace JsonDI.Extensions
{
    public class DIContractResolver: CamelCasePropertyNamesContractResolver
    {
        IDIMeta diMeta;
        IServiceProvider sp;
        public DIContractResolver(IDIMeta diMeta, IServiceProvider sp)
        {
            this.diMeta = diMeta;
            this.sp = sp;
        }
        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {

            if (diMeta.IsRegistred(objectType))
            {
                JsonObjectContract contract = DIResolveContract(objectType);
                contract.DefaultCreator = () => sp.GetService(objectType);

                return contract;
            }

            return base.CreateObjectContract(objectType);
        }
        private JsonObjectContract DIResolveContract(Type objectType)
        {
            var fType = diMeta.RegistredTypeFor(objectType);
            if (fType != null) return base.CreateObjectContract(fType);
            else return CreateObjectContract(objectType);
        }
    }
}

We override the CreateObjectContract method to modify the custom contract. If the type our ContractResolver has been invoked on is registered in the DI container we call DIResolveContract that, if available, returns a contract for the type that will be actually created by the DI engine. If no type is specified DIResolveContract falls back on a contract for the original type (which might have less properties than the actual type created). After that CreateObjectContract changes the contract DefaultCreator property to use DI.

Our ContractResolver needs both IServiceProvider and IDIMeta to do its job, so we passed them in its constructor.

Installing our DIContractResolver

Our DIContractResolver may be installed by configuring the MvcJsonOptions options object. In my previous posts of the custom model binding series I showed how to configure options by passing a lambda function to various extension methods in the ConfigureServices method of the Startup.cs class. We may also factor out the configuration code for each specific option object in a class by writing a class that inherits from IOption<MyOptionObject>:

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace JsonDI.Extensions
{
    public class JsonOptionsSetup: IConfigureOptions<MvcJsonOptions>
    {
        IServiceProvider serviceProvider;
        public JsonOptionsSetup(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
        public void Configure(MvcJsonOptions o)
        {
            o.SerializerSettings.ContractResolver =
                new DIContractResolver(serviceProvider.GetService<IDIMeta>(), serviceProvider);
        }
    }
}

After that, it is enough to call “services.AddTransient<IConfigureOptions<MvcJsonOptions>, JsonOptionsSetup>();” in the ConfigureServices method of the Startup.cs class. Summing up the whole code of the ConfigureServices method of the Startup.cs class is:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
            
            services.AddTransient<IPerson, DefaultPerson>();
            services.TryAddSingleton<IDIMeta>(s =>
            {
                return new DIMetaDefault(services);
            });
            services.AddTransient<IConfigureOptions<MvcJsonOptions>, JsonOptionsSetup>();
        }

For the above to compile properly we need the “usings” below:

using JsonDI.Extensions;
using JsonDI.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

 

That’s all! Run the project, click the submit button and wait on our previous breakpoint. This time the IPerson model contains the right data sent by the client!

Stay Tuned!

Francesco

Tags: , , , ,