Deserialize XML to Object in C#

<?xml version="1.0" encoding="utf-8"?>
<Company xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Employee name="x" age="30" />
  <Employee name="y" age="32" />
 </Company>
using System.Xml.Serialization;

[XmlRoot(ElementName = "Company")]
public class Company

{
    public Company()
    {  
        Employees = new List<Employee>();
    }

    [XmlElement(ElementName = "Employee")]
    public List<Employee> Employees { get; set; }

    public Employee this[string name]
    {
        get { return Employees.FirstOrDefault(s => string.Equals(s.Name, name, 							StringComparison.OrdinalIgnoreCase)); }
    }
}

public class Employee
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlAttribute("age")]
    public string Age { get; set; }
}
public static T DeserializeXml<T>(string str)
{
    var serializer = new XmlSerializer(typeof(T));
    object result;

    using (TextReader reader = new StringReader(str))
    {
        result = serializer.Deserialize(reader);
    }

    return (T) result;
}
var s = "--your xml string--";
var obj = Deserialize<CMS>(s);

References
https://www.delftstack.com/howto/csharp/deserialize-xml-to-object-in-csharp/
https://stackoverflow.com/questions/47158427/how-to-convert-xml-to-list-of-objects

ASP.NET Core Blazor State Management

We can use ASP.NET Core Protected Browser Storage:

Use the Local Storage

@page "/"
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage BrowserStorage

<h1>Local Storage!</h1>

<input class="form-control" @bind="currentInputValue" />
<button class="btn btn-secondary" @onclick="Save">Save</button>
<button class="btn btn-secondary" @onclick="Read">Read</button>
<button class="btn btn-secondary" @onclick="Delete">Delete</button>

@code {
  string currentInputValue;

  public async Task Save()
  {
    await BrowserStorage.SetAsync("name", currentInputValue);
  }

  public async Task Read()
  {
    var result = await BrowserStorage.GetAsync<string>("name");
    currentInputValue = result.Success ? result.Value : "";
  }

  public async Task Delete()
  {
    await BrowserStorage.DeleteAsync("name");
  }
}

Use the Session Storage

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-6.0&pivots=server
https://www.thomasclaudiushuber.com/2021/04/19/store-data-of-your-blazor-app-in-the-local-storage-and-in-the-session-storage/

Transient fault handling in gRPC with retries in C#

gRPC calls can be interrupted by transient faults. Transient faults include:

  • Momentary loss of network connectivity.
  • Temporary unavailability of a service.
  • Timeouts due to server load.

When a gRPC call is interrupted, the client throws an RpcException with details about the error. The client app must catch the exception and choose how to handle the error.

var client = new Greeter.GreeterClient(channel);
try
{
    var response = await client.SayHelloAsync(
        new HelloRequest { Name = ".NET" });

    Console.WriteLine("From server: " + response.Message);
}
catch (RpcException ex)
{
    // Write logic to inspect the error and retry
    // if the error is from a transient fault.
}

Duplicating retry logic throughout an app is verbose and error-prone. Fortunately, the .NET gRPC client now has built-in support for automatic retries. Retries are centrally configured on a channel, and there are many options for customizing retry behavior using a RetryPolicy.

var defaultMethodConfig = new MethodConfig
{
    Names = { MethodName.Default },
    RetryPolicy = new RetryPolicy
    {
        MaxAttempts = 5,
        InitialBackoff = TimeSpan.FromSeconds(1),
        MaxBackoff = TimeSpan.FromSeconds(5),
        BackoffMultiplier = 1.5,
        RetryableStatusCodes = { StatusCode.Unavailable }
    }
};

// Clients created with this channel will automatically retry failed calls.
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
    ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

References
https://devblogs.microsoft.com/dotnet/grpc-in-dotnet-6/
https://docs.microsoft.com/en-us/aspnet/core/grpc/retries?view=aspnetcore-6.0

gRPC client-side load balancing in C#

The following code example configures a channel to use DNS service discovery with round-robin load balancing:

var channel = GrpcChannel.ForAddress(
    "dns:///my-example-host",
    new GrpcChannelOptions
    {
        Credentials = ChannelCredentials.Insecure,
        ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } }
    });
var client = new Greet.GreeterClient(channel);

var response = await client.SayHelloAsync(new HelloRequest { Name = "world" });

References
https://devblogs.microsoft.com/dotnet/grpc-in-dotnet-6/
https://docs.microsoft.com/en-us/aspnet/core/grpc/loadbalancing?view=aspnetcore-6.0

Parallel.ForEachAsync in .NET 6

using System.Net.Http.Headers;
using System.Net.Http.Json;

var userHandlers = new []  { "users/VahidN", "users/shanselman", "users/jaredpar", "users/davidfowl" };

using HttpClient client = new()
{
    BaseAddress = new Uri("https://api.github.com"),
};
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("DotNet", "6"));

ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = 3 };

await Parallel.ForEachAsync(userHandlers, parallelOptions, async (uri, token) =>
{
    var user = await client.GetFromJsonAsync<GitHubUser>(uri, token);
    Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}\n");
});

public class GitHubUser
{
    public string Name { get; set; }
    public string  Bio { get; set; }
}

References
https://www.hanselman.com/blog/parallelforeachasync-in-net-6

Template Matching on Images using OpenCvSharp

//read image
// var refMat = new Mat("001f.png", ImreadModes.Unchanged);
// var tplMat = new Mat("001.png", ImreadModes.Unchanged);
using (Mat refMat = new Mat("001f.png", ImreadModes.Unchanged))
using (Mat tplMat = new Mat("001.png", ImreadModes.Unchanged))
using (Mat res = new Mat(refMat.Rows - tplMat.Rows + 1, refMat.Cols - tplMat.Cols + 1, MatType.CV_32FC1))
{
    //Convert input images to gray
    Mat gref = refMat.CvtColor(ColorConversionCodes.BGR2GRAY);
    Mat gtpl = tplMat.CvtColor(ColorConversionCodes.BGR2GRAY);

    Cv2.MatchTemplate(gref, gtpl, res, TemplateMatchModes.CCoeffNormed);
    Cv2.Threshold(res, res, 0.8, 1.0, ThresholdTypes.Tozero);

    while (true)
    {
        double minval, maxval, threshold = 0.8;
        Point minloc, maxloc;
        Cv2.MinMaxLoc(res, out minval, out maxval, out minloc, out maxloc);

        if (maxval >= threshold)
        {
            //draw a rectangle of the matching area
            Rect r = new Rect(new Point(maxloc.X, maxloc.Y), new Size(tplMat.Width, tplMat.Height));
            Cv2.Rectangle(refMat, r, Scalar.Red, 2);

            //debug
            String msg =
                $"MinVal={minval.ToString()} MaxVal={maxval.ToString()} MinLoc={minloc.ToString()} MaxLoc={maxloc.ToString()} Rect={r.ToString()}";
            Console.WriteLine(msg);

            //fill in the res mat so you don't find the same area again in the minmaxloc
            //Rect outRect;
            //Cv2.FloodFill(res, maxloc, new Scalar(0), out outRect, new Scalar(0.1), new Scalar(1.0), FloodFillFlags.Link4);
            Cv2.FloodFill(res, maxloc, new Scalar(0));
        }
        else
        {
            break;
        }
    }
}

 

Dependency Injection in WPF Application using Generic HostBuilder

Creating Generic HostBuilder

Nuget :

PM> Install-Package Microsoft.Extensions.Hosting -Version 3.1.2

The HostBuilder class is available from the following namespace,

using Microsoft.Extensions.Hosting;

Initialize the Host

Within Constructor of App class(file: App.xaml.cs) please add below code to build Host,

host = new HostBuilder()
           .ConfigureServices((hostContext, services) =>
           {
 
           }).Build();

DI Container

host = new HostBuilder()
          .ConfigureServices((hostContext, services) =>
          {
              //Add business services as needed
              services.AddScoped<IEmployeeViewModel, EmployeeViewModel>();
 
              //Lets Create single tone instance of Master windows
              services.AddSingleton<EmployeeWindow>();
 
          }).Build();

Setting up OnStartup and OnExit Application events

private void OnStartup(object sender, StartupEventArgs e)
        {
            var mainWindow = host.Services.GetService<EmployeeWindow>();
            mainWindow.Show();
        }
protected override async void OnExit(ExitEventArgs e)
       {
           using (host)
           {
               await host.StopAsync();
           }
 
           base.OnExit(e);
       }

App.XAML file used as below,

<Application x:Class="WPFDesktopApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Startup="OnStartup">
    <Application.Resources>
         
    </Application.Resources>
</Application>

References
https://www.thecodebuzz.com/dependency-injection-wpf-generic-hostbuilder-net-core/
https://laurentkempe.com/2019/09/03/WPF-and-dotnet-Generic-Host-with-dotnet-Core-3-0/