C# – Multithreading

The Main Thread

using System;
using System.Threading;

namespace MultithreadingApplication {
   class MainThreadProgram {
      static void Main(string[] args) {
         Thread th = Thread.CurrentThread;
         th.Name = "MainThread";
         
         Console.WriteLine("This is {0}", th.Name);
         Console.ReadKey();
      }
   }
}
Sr.No.Property & Description
1CurrentContext Gets the current context in which the thread is executing.
2CurrentCulture Gets or sets the culture for the current thread.
3CurrentPrinciple Gets or sets the thread’s current principal (for role-based security).
4CurrentThread Gets the currently running thread.
5CurrentUICulture Gets or sets the current culture used by the Resource Manager to look up culture-specific resources at run-time.
6ExecutionContext Gets an ExecutionContext object that contains information about the various contexts of the current thread.
7IsAlive Gets a value indicating the execution status of the current thread.
8IsBackground Gets or sets a value indicating whether or not a thread is a background thread.
9IsThreadPoolThread Gets a value indicating whether or not a thread belongs to the managed thread pool.
10ManagedThreadId Gets a unique identifier for the current managed thread.
11Name Gets or sets the name of the thread.
12Priority Gets or sets a value indicating the scheduling priority of a thread.
13ThreadState Gets a value containing the states of the current thread.

Creating Threads

using System;
using System.Threading;

namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         Console.WriteLine("Child thread starts");
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         Thread childThread = new Thread(childref);
         childThread.Start();
         childThread.Join(1000);
         Console.ReadKey();
      }
   

Thread Pool

List<string> urls = new(){
    "https://www.google.com/",
    "https://www.duckduckgo.com/",
    "https://www.yahoo.com/",
};

foreach (var url in urls)
{
    ThreadPool.QueueUserWorkItem((state) => CheckHttpStatus(url));
}

async and await

static void Main()
    {
        Task task = new Task(CallMethod);
        task.Start();
        task.Wait();
        Console.ReadLine();
    }

    static async void CallMethod()
    {
        string filePath = "E:\\sampleFile.txt";
        Task<int> task = ReadFile(filePath);

        Console.WriteLine(" Other Work 1");
        Console.WriteLine(" Other Work 2");
        Console.WriteLine(" Other Work 3");

        int length = await task;
        Console.WriteLine(" Total length: " + length);

        Console.WriteLine(" After work 1");
        Console.WriteLine(" After work 2");
    }

    static async Task<int> ReadFile(string file)
    {
        int length = 0;

        Console.WriteLine(" File reading is stating");
        using (StreamReader reader = new StreamReader(file))
        {
            // Reads all characters from the current position to the end of the stream asynchronously
            // and returns them as one string.
            string s = await reader.ReadToEndAsync();

            length = s.Length;
        }
        Console.WriteLine(" File reading is completed");
        return length;
    }
static async Task Main(string[] args)
   {
     await callMethod();
     Console.ReadKey();
   }

   public static async Task callMethod()
   {
     Method2();
     var count = await Method1();
     Method3(count);
   }

   public static async Task<int> Method1()
   {
     int count = 0;
     await Task.Run(() =>
     {
       for (int i = 0; i < 100; i++)
       {
         Console.WriteLine(" Method 1");
         count += 1;
       }
     });
     return count;
   }

   public static void Method2()
   {
     for (int i = 0; i < 25; i++)
     {
       Console.WriteLine(" Method 2");
     }
   }

   public static void Method3(int count)
   {
     Console.WriteLine("Total count is " + count);
   }

ASP.NET Core – Dependency Injection and Middlewares

Services

assume we have logger service like

public interface ILog
{
    void info(string str);
}

class MyConsoleLogger : ILog
{
    public void info(string str)
    {
        Console.WriteLine(str);
    }
}

then we can register it in ioc like


builder.Services.Add(new ServiceDescriptor(typeof(ILog), typeof( MyConsoleLogger)));

in the above example the service it singleton by default

  1. Singleton: IoC container will create and share a single instance of a service throughout the application’s lifetime.
  2. Transient: The IoC container will create a new instance of the specified service type every time you ask for it.
  3. Scoped: IoC container will create an instance of the specified service type once per request and will be shared in a single request.
public void ConfigureServices(IServiceCollection services)
{
    services.Add(new ServiceDescriptor(typeof(ILog), new MyConsoleLogger()));    // singleton
    
    services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), ServiceLifetime.Transient)); // Transient
    
    services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), ServiceLifetime.Scoped));    // Scoped
}

access to service

var services = this.HttpContext.RequestServices;
var log = (ILog)services.GetService(typeof(ILog));
// or in controller api parameter you can access it by 
[FromServices] IReCaptcha reCaptcha

asp.net core Identity and authentication

HttpContext

HttpContext encapsulates all information about an individual HTTP request and response.
and it capsulated by ControllerBase

HttpContext.User it will represent Th Identity any object implement System.Security.Principal.IIdentity and it wrapped by Principal Class Object 
HttpContext Can Access to Any WebApplication Service by RequestServices.GetService<>() .... 

Identity 
It is Group OF Claims each claim represent kind of user data
most two famous Identity is ClaimsIdentinty And Generic Identity

Principal
it will Cover the Identity and provide you utilities to check if is there claim or schema or policy ... etc 

protected async override sealed Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        
        var authorizationHeader = Request.Headers["Authorization"].ToString();
        if (authorizationHeader != null && authorizationHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            var token = authorizationHeader.Substring("Basic ".Length).Trim();
            var credentialsAsEncodedString = Encoding.UTF8.GetString(Convert.FromBase64String(token));
            var credentials = credentialsAsEncodedString.Split(':');
            try
            {
                User? user = await Users.Login(credentials[0], credentials[1]);
                var identity = user;
                List<Claim> claims = new() { new Claim("uid", user.user_info.uid), new Claim("token", user.user_info.token) };
                foreach (var authorization in user.user_info.authorization)
                {
                    claims.Add(new Claim(authorization.ToString("G"), "true"));
                }
                this.Context.Items.Add("user", new ClaimsPrincipal(identity));
                ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims,"Basic"));
                return await Task.FromResult(
                    AuthenticateResult.Success(new AuthenticationTicket(principal, "Basic")));

            }
            catch (Exception e)
            {
                Response.StatusCode = 401;
                Response.Headers.Add("WWW-Authenticate", "Basic realm=\"thesmartcircuit.com\"");
                return await Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
            }
        }

        Response.StatusCode = 401;
        Response.Headers.Add("WWW-Authenticate", "Basic realm=\"thesmartcircuit.com\"");
        return await Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
    }

then you can add new authoentication to this services of web application .

builder.Services.AddAuthentication("Basic")
    .AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("Basic", null);

to apply this authentication on any minimal api


app.MapGet("/", () => "Hello World!").RequireAuthorization((b) => { b.RequireClaim("admin");});
//or 
[Authorize(AuthenticationSchemes = "Basic")]

Authorizations And Policies
add authorization service with Admin policy

builder.Services.AddAuthorizationBuilder().AddPolicy("Admin", (pb) =>
{
    pb.RequireAuthenticatedUser().AddAuthenticationSchemes("Basic").RequireRole("admin");
});

then you can use this authorized policy with minimal api like

[Authorize(Policy = "User")]

Authentication Handler
there are already built in auth handler service like cookies and ODB if you like to customize new you can inherit AuthenticationHandler

add roles

new Claim(ClaimTypes.Role,authorization.ToString("G"));
//or instean of using ClaimTypes.Role you can identify any string as role type by add it to roletype parameter in  ClaimsIdentity

dotnet CLI and Project file

dotnet

run

dotnet run --project ./projects/proj1/proj1.csproj
dotnet run --configuration Release
dotnet run -c Release --arch x64 --project ConsoleTest/ConsoleTest.csproj

#--no-build to run with no build

build

Builds a project and all of its dependencies.

Executable or library output

Whether the project is executable or not is determined by the <OutputType> property in the project file.

<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>

To produce a library, omit the <OutputType> property or change its value to Library. The IL DLL for a library doesn’t contain entry points and can’t be executed.

  • --no-self-containedPublishes the application as a framework dependent application. A compatible .NET runtime must be installed on the target machine to run the application. Available since .NET 6 SDK.
dotnet build --source d1/d2 --output d3/d4 -c Release 

publish

dotnet publish – Publishes the application and its dependencies to a folder for deployment to a hosting system.

dotnet publish [<PROJECT>|<SOLUTION>] [-a|--arch <ARCHITECTURE>]
    [-c|--configuration <CONFIGURATION>]
    [-f|--framework <FRAMEWORK>] [--force] [--interactive]
    [--manifest <PATH_TO_MANIFEST_FILE>] [--no-build] [--no-dependencies]
    [--no-restore] [--nologo] [-o|--output <OUTPUT_DIRECTORY>]
    [--os <OS>] [-r|--runtime <RUNTIME_IDENTIFIER>]
    [--sc|--self-contained [true|false]] [--no-self-contained]
    [-s|--source <SOURCE>] [--use-current-runtime, --ucr [true|false]]
    [-v|--verbosity <LEVEL>] [--version-suffix <VERSION_SUFFIX>]

test

dotnet test

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
    <PackageReference Include="xunit" Version="2.4.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
  </ItemGroup>

Project File

item group and property group examples

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        
    </PropertyGroup>
<ItemGroup>
      <PackageReference Include="Google.Cloud.Storage.V1" Version="4.4.0" />
        <None Update="settings.json">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="cloud_credintial.json">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="shell">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <Content Include="shell/*.*">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
    </ItemGroup>

C# Topics (Pattern matching)

Pattern matching

switch (aa)
{
    case {val:12}:
        Console.WriteLine("hello");
        break;
    case A aaa when aa.val2==13:
        Console.WriteLine(aaa.val);
        break;
}

Simplifying switch statements with switch expressions


Animal animal = new Animal() { Name = "tiger" };
string message = animal switch
{
    Animal fourLeggedCat when fourLeggedCat.Name=="cat"
        => $"small cat",
    Animal wildCat when wildCat.Name == "tiger"
        => $"big cat",
};
Console.WriteLine($"switch expression: {message}");

class Animal
{
    public string Name { get; set; }
}

with array patterns

int[] mm = new[]{1,2,3,4,5,6,7};
string vv=mm switch
{
    int[] vvv when mm is [_,2,_,4,..] => "one",
    int[] vvv when mm is {Length: 2} => "two"
};
Console.WriteLine(vv);


int[] mm = new[]{1,2,3,4,5,6,7};
string vv=mm switch
{
    [_,2,_,4,..] => "one",
    {Length: 2} => "two"
};
Console.WriteLine(vv);

relational patterns


bool b=v is (> 32) and (< 66);
string WaterState(int tempInFahrenheit) =>
    tempInFahrenheit switch
    {
        (> 32) and (< 212) => "liquid",
        < 32 => "solid",
        > 212 => "gas",
        32 => "solid/liquid transition",
        212 => "liquid / gas transition",
    };

var m=(12,44);
var l=new{val1=12,val2=44};
bool res=m is {Item1:12,Item2:_};
bool res2=l is {val1:12,val2:_};
Console.WriteLine($" m is {m}, and l is{l}");

C# Topics (1)

is operator

Console.WriteLine(new A{val1=1,val2=2} is { val1:1 ,val3:0});//true
public class A
{
    public int val1;
    public int val2;
    public int val3;
}

object o=default(object);
o is null //true
o is not null //false

is with patterns

object greeting = "Hello, World!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: hello, world!
}

int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
    Console.WriteLine(a + b);  // output: 30
}

with expresion

with expression produces a copy of its operand with the specified properties and fields modified.
it work only with record and struct for class you can use IClonable or serialization and deserialization
you use object initializer syntax to specify what members to modify and their new values:

public record Point(int X, int Y);
public record NamedPoint(string Name, int X, int Y) : Point(X, Y);

public static void Main()
{
   Point p1 = new NamedPoint("A", 0, 0);
   Point p2 = p1 with { X = 5, Y = 3 };
   Console.WriteLine(p2 is NamedPoint);  // output: True
   Console.WriteLine(p2);  // output: NamedPoint { X = 5, Y = 3, Name = A }
}

stackalloc

allocate stacked memory for performance purposes

const int MaxStackLimit = 1024;
Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
Span<int> first = stackalloc int[3] { 1, 2, 3 };
Span<int> second = stackalloc int[] { 1, 2, 3 };
ReadOnlySpan<int> third = stackalloc[] { 1, 2, 3 };

Touples

public class A
{
    public int val1;
    public int val2;
    public int val3;
    
    (int v1,int v2,int v3) GetVal()
    {
        return (val1, val2);
    }
}


 (int t2,int t3) T = (1, 2);

anonymous object

var m = new { m = 12 };
(int Id, string Name) M=(1, "hello");

List<int> vals = new(){ 1, 2, 3 };

A aa = new(1,2,3);

A aa = new(){val1=1,val2=2,val3=3};

Record

by default record is a class compares the record with == it compares the properties

with == operator
class compare with reference
struct not accept
record compare with values


record A
{
    public int a { get; init; }
    public int b { get; init; }
}

record AA(int a, int b);

extension method

public static class StringExtensions
{
    public static void GobbleGobble(this string s,int val) //new string("").GobbleGobble(12)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}
class Data1
{
    public int Id => 1; //property
    public string Name => "Test";//property
}

record Data2(int Id,string Name); //properties

var ( Id, Name) = new Data2(Id :1, "test");

Deconstruct function in class

class Data
{
    public int Id { set; get; }
    public string Name { set; get; }
    
    public void Deconstruct(out int Id, out string Name)
    {
        Id = this.Id;
        Name = this.Name;
    }
    
};

var ( Id, Name) = new Data(){Id =1, Name="test"};
( int Id, string Name) = new Data(){Id =1, Name="test"};