Category: projects

Comparing EFCore Database Providers-part-1

IDName
1 Part 1
2 Part 2
3 Part 3

I wanted to see if there are any differences in EFCore database providers listed at 

https://learn.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli

I want to test the capabilities for each one within a standard choice of tables , in order to know the capabilities

I choose only those that have a version for current STS / LTS , whatever it is current.

( I am particularly interested in SqlServer vs Sqlite )

Problem 1: Conflicting namespaces

For MySql – there are 2 providers , Pomelo.EntityFrameworkCore.MySql  and MySql.EntityFrameworkCore  . Both have the same namespace and class for .UseMySql  ( and other stuff)

So how to do it ? Fortunately, nuget supports alias .

So the code in csproj is

<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" Aliases="PomeloEFMySql"  />
<PackageReference Include="MySqlConnector" Version="2.2.5" Aliases="MySqlConnect" />

<PackageReference Include="MySql.EntityFrameworkCore" Version="7.0.5" Aliases="MySqlEFOracle" />
<PackageReference Include="MySql.Data" Version="8.1.0" Aliases="OracleMySql"/>
		

And the code in global.cs

extern alias OracleMySql;

extern alias PomeloEFMySql;
extern alias MySqlConnect;

global using MySqlCNBOracle = MySqlEFOracle.Microsoft.EntityFrameworkCore.MySQLDbContextOptionsExtensions;
global using MySqlOracle = OracleMySql.MySql.Data.MySqlClient;
global using MySqlEF = MySqlEFOracle::Microsoft.EntityFrameworkCore;
 
global using PomeloCN= MySqlConnect::MySqlConnector;
global using PomeloEF = PomeloEFMySql::Microsoft.EntityFrameworkCore;
global using PomeloMySqlCNB =PomeloEFMySql::Microsoft.EntityFrameworkCore.MySqlDbContextOptionsBuilderExtensions;

And the code to use it

case EFCoreProvider.Pomelo_EntityFrameworkCore_MySql:

    var serverVersion = PomeloEF.ServerVersion.AutoDetect(con);
    StepExecution.Current.Comment("version " + serverVersion.ToString());
    PomeloMySqlCNB.UseMySql(builder,con, serverVersion)
        .EnableSensitiveDataLogging()
        .EnableDetailedErrors();
    
    break;
case EFCoreProvider.MySql_EntityFrameworkCore:
    MySqlCNBOracle.UseMySQL(builder,con);
    break;

You can find the results at https://github.com/ignatandrei/TestEFCoreDatabaseProviders and https://ignatandrei.github.io/TestEFCoreDatabaseProviders/

Problem 2 : Conflict on container ports

When a container is started for a test it works on a port ( 1433 for SqlServer). When a new test arrives ( with new tables ) , it cannot be on the same port . So the docker containers must be disposed when the test finishes. Also , the tests must be done in serial, not in paralel.

For parallelism, it is simple ( LightBDD + XUnit)

[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: ClassCollectionBehavior(AllowTestParallelization = false)]

For disposing, can use IScenarioTearDown (LightBDD) or IAsyncLifetime (XUnit)

NetCoreUsefullEndpoints-part 8- adding start date

In my NuGet NetCoreUsefullEndpoints package  I have had already registered the actual date as

var rh = route.MapGet(“api/usefull/dateUTC”, (HttpContext httpContext) =>
            {
                return Results.Ok(DateTime.UtcNow);
            });

Now I want to register also the start date – the date where the application has been started.

1. How to do this  ?

2. What will be the route ?

For 1 can be a static constructor or, better , the singleton in C# :

private static DateTime startDateUTC = DateTime.UtcNow;

For 2 it is more complicated

My solution ( just break compatibility, since I have not a v1 and v2) was the following

var rh = route.MapGet(“api/usefull/date/startUTC”, (HttpContext httpContext) =>
{
     return Results.Ok(startDateUTC);
});

var rhUTC = route.MapGet(“api/usefull/date/nowUTC/”,
     (HttpContext httpContext) =>
     {
         return TypedResults.Ok(DateTime.UtcNow);
     });

rhUTC.AddDefault(corsPolicy, authorization);

So now I have same routing api/usefull/date

NetCoreUsefullEndpoints–part 7–restart application

In order to do the shutdown, I have added the following extension

public static CancellationTokenSource cts=new ();

public static void MapShutdown(this IEndpointRouteBuilder route, string? corsPolicy = null, string[]? authorization = null)
        {
            ArgumentNullException.ThrowIfNull(route);
            var rh = route.MapPost(“api/usefull/shutdown/”,
                (HttpContext httpContext) =>
                {
                    var h= cts.Token.GetHashCode();
                    cts?.Cancel();                   
                    return h;
                   
                });

           rh.AddDefault(corsPolicy, authorization);

        }

This code defines a static field called “cts” in the “UsefullExtensions” class. “cts” is an instance of the “CancellationTokenSource” class, which is used to create a CancellationToken that can be used to stop the application gracefully.

The “MapShutdown” method is an extension method for IEndpointRouteBuilder that creates a new endpoint for a POST request to the “api/usefull/shutdown/” URL. When the request is received, the method cancels the “cts” CancellationTokenSource if it is not null, and returns the hash code of the CancellationToken. The method also sets the “corsPolicy” and “authorization” parameters for the endpoint.

You can call with

app.MapUsefullAll();

or with

app.MapShutdown

Anyway , the runAsync should be modified with

await app.RunAsync(UsefullExtensions.UsefullExtensions.cts.Token);

The “RunAsync” method of the “app” object is used to start the application and listen for incoming requests. The method takes a CancellationToken as an argument, which allows the application to be stopped gracefully by cancelling the token. In this case, the token is provided by the “cts” field of the “UsefullExtensions” class. The code uses the “await” keyword to wait for the task returned by “RunAsync” to complete before continuing.

DIForFunctions – Improving constructor–part 5

I have received a suggestion : what if we just put into constructor what we need , and everything else ( such as ILogger ) are into fields ?

The Roslyn Source Code Generator will generate a constructor that calls the this constructor  and will assign fields needed.

Let’s give an example : We wrote

public partial class TestDIFunctionAdvWithConstructor2Args
    {
        [RSCG_FunctionsWithDI_Base.FromServices]
        private TestDI1 NewTestDI1;

       public TestDI2 NewTestDI2 { get; set; }

       public readonly TestDI3 myTestDI3;

       private TestDIFunctionAdvWithConstructor2Args(TestDI3 test, TestDI2 a)
        {
            myTestDI3 = test;
            NewTestDI2 = a;
        }

   }

and the generator will generate a new constructor with the required  field

public partial class TestDIFunctionAdvWithConstructor2Args
{
public TestDIFunctionAdvWithConstructor2Args  
(TestDI3 test, TestDI2 a, TestDI1 _NewTestDI1) : this (test,a)
{
this.NewTestDI1 = _NewTestDI1;
}//end constructor

}//class

The code is non trivial  – to find if a constructor exists, take his fields, generate new constructor with all fields.

But , as anything in IT , it is doable .

Record visitors- work on issues–part 7

Now it is time to solve some issues  There were 12 issues written by me – you can see here:

https://github.com/ignatandrei/RecordVisitors/issues?q=is%3Aissue+is%3Aclosed

Between the most important:

  1. Improve readme.md with more links and explanations for potential programmer and contributors
  2. Write version in static constructor – to know about the version, if some issue occurs
  3. Added custom link  lastvisitors/minutes/{time:int} to see the latest visitors in a time frame
  4. Add read the docs site https://record-visitors.readthedocs.io/en/latest/
  5. Modification on the interfaces – replacing FUNC property with a real Func

There seems little – but it takes a while.

The links for the project are now

SideCARCLI–Finish process after some time

Summary links SideCarCLI

NoName + Link 
1Description
2Specifications
3Refactor specifications and code
4Create Release
5Finish interceptors
6Send part of command to interceptors
7Line Interceptors
8Finish process after some time
9Documetation Diagram
10Technical Summary
11Create dotnet tool
( Description : SideCar for CLI applications. Interceptors for Line, Finish, Timer . See Code )

One of the feature is to let the original process execute just a limited amount of time. For this, I have defined an option

var maxSeconds = app.Option(“-mS|–maxSeconds”, “max seconds for the StartApp to run”, CommandOptionType.SingleOrNoValue);

and the code for waiting is

Process p = new Process()
{
StartInfo = pi
};

//code

var res=p.WaitForExit(this.MaxSeconds);

//code

if (res)
{
exitCode = p.ExitCode;
RunFinishInterceptors(exitCode);
}
else
{
Console.WriteLine($”timeout {MaxSeconds} elapsed”);
exitCode = int.MinValue;
}

 

where the default value for this.MaxSeconds is –1 – wait undefinetely

SideCarCLI – Line interceptors

Summary links SideCarCLI

NoName + Link 
1Description
2Specifications
3Refactor specifications and code
4Create Release
5Finish interceptors
6Send part of command to interceptors
7Line Interceptors
8Finish process after some time
9Documetation Diagram
10Technical Summary
11Create dotnet tool
( Description : SideCar for CLI applications. Interceptors for Line, Finish, Timer . See Code )

For the SideCarCLI I have the concept of Line Interceptors. That means for each line from the original program another program will be start .

The json looks like this

“LineInterceptors”: [
{
“Name”: “WindowsStandardWindowsOutputInterceptor”,
“Arguments”: “/c echo \”{site} {line}\””,
“FullPath”: “cmd.exe”,
“FolderToExecute”: null,
“InterceptOutput”: true
},
{
“Name”: “NextInterceptor”,
“Arguments”: “/c echo {line}”,
“FullPath”: “cmd.exe”,
“FolderToExecute”: null,
“InterceptOutput”: true
}
]

and you can activate by command line

-aLi WindowsStandardWindowsOutputInterceptor

Pretty simple , right ? For the code , means intercepting each line

p.OutputDataReceived += P_OutputDataReceived;
p.ErrorDataReceived += P_ErrorDataReceived;

and then run the process

foreach(var item in runningInterceptors.LineInterceptors)
{
try
{

var local = item;
var dataToBeParsed=new Dictionary<string, string>();

if(this.argsRegex.Count>0)
{
foreach (var reg in argsRegex)
{
dataToBeParsed.Add(“{“+reg.Key+”}”, reg.Value);
}
}
dataToBeParsed[“{line}”]= e.Data;
allProcesses.TryAdd(local.Name, local.RunLineInterceptor(local.Name,dataToBeParsed));

}
catch (Exception ex)
{
Console.WriteLine($”LineInterceptor:{item?.Name} error:!!!” + ex.Message);
}
}

Every time it is interesting how a simple specification means multiple lines of code….

SideCarCLI | Command Line – description –part 1

Summary links SideCarCLI

NoName + Link 
1Description
2Specifications
3Refactor specifications and code
4Create Release
5Finish interceptors
6Send part of command to interceptors
7Line Interceptors
8Finish process after some time
9Documetation Diagram
10Technical Summary
11Create dotnet tool
( Description : SideCar for CLI applications. Interceptors for Line, Finish, Timer . See Code )

There are those days a great deal of command line applications that performs a variety of things. The problem is that you cannot control them . The command line performs their duty well – but , from time to time, you need something else integrated with this.

The pattern for this is https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar – it is applied to microservices , but why not applied to command lines ?

So – let’s start this project  with specifications.

Let’s suppose that I want to run an command line application – let name it StartApp. But I want also:

  1. Intercept every line of the StartApp that is outputting to the console and run something with that with the line ( send to HTTP endpoint, log somewhere, and so on).
  2. Intercept the finish of the StartApp and run something with the output ( either all lines, either with the result of the application)
  3. Timers:
    • Do not let the StartApp to run more than an maximum amount of time
    • Run something periodically  with arguments  from the StartApp arguments

 

 

The solution is to make another application ( let’s name SideCarCLI ) that runs the  StartApplication.

What it is complicated her is how we pass the arguments of the SideCarCLI versus the arguments of the StartApp .

Full Projects

My first blog post in English is from 14 nov 2009 ( http://msprogrammer.serviciipeweb.ro/2009/11/14/jquery-learning/ ). It was on the time that Jquery was just integrated in VS 2010.

My first blog post about programming was from 13 March 2005 (http://serviciipeweb.ro/iafblog/2005/03/13/pentru-inceput/ ). I was working on “ log4Net, NUnit , C#, asp.net, VB.Net sai VB6” …..

From the old blog in Romanian, those are the projects that remains ok: http://serviciipeweb.ro/iafblog/2015/03/23/proiecte-codeplex/

From the new blog in English , those are the projects that I have created:  http://msprogrammer.serviciipeweb.ro/full-projects/

Enjoy!

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.