milosev.com
  • Home
    • List all categories
    • Sitemap
  • Downloads
    • WebSphere
    • Hitachi902
    • Hospital
    • Kryptonite
    • OCR
    • APK
  • About me
    • Gallery
      • Italy2022
      • Côte d'Azur 2024
    • Curriculum vitae
      • Resume
      • Lebenslauf
    • Social networks
      • Facebook
      • Twitter
      • LinkedIn
      • Xing
      • GitHub
      • Google Maps
      • Sports tracker
    • Adventures planning
  1. You are here:  
  2. Home
  3. C#

Producer-Consumer Pattern

Details
Written by: Stanko Milosev
Category: C#
Published: 08 February 2025
Last Updated: 08 February 2025
Hits: 759
Hier is one my example of Producer-Consumer Pattern.

First I want to read all files from HDD and put them in the queue (producer):

private void SearchForAllFilesAndPutThemInQueue(BlockingCollection<string> fileQueue, string path)
{
	foreach (string file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
	{
		fileQueue.Add(file);
	}
}
Then I will read file names from queue and do something with (consumer):
private void ReadFileNamesFromQueue
(
	BlockingCollection<string>? fileQueue
	, BlockingCollection<(LatLngModel, string)>? gpsInfoQueue
)
{
	int i = 0;

	if (fileQueue is null) throw new ArgumentNullException(nameof(fileQueue));
	if (gpsInfoQueue is null) throw new ArgumentNullException(nameof(gpsInfoQueue));

	foreach (string file in fileQueue.GetConsumingEnumerable())
	{
		try
		{
			ExtractGpsInfoFromImageCommand extractGpsInfoFromImageCommand = new ExtractGpsInfoFromImageCommand();
			extractGpsInfoFromImageCommand.ImageFileNameToReadGpsFrom = file;
			extractGpsInfoFromImage.Execute(extractGpsInfoFromImageCommand);

			if (extractGpsInfoFromImageCommand.LatLngModel is not null)
			{
				gpsInfoQueue.Add((extractGpsInfoFromImageCommand.LatLngModel, file));
			}
		}
		catch (Exception ex)
		{
			Debug.WriteLine(ex.Message());
		}
	}
}
Here you can download my example, little bit complicated, where I get list of file in one queue, in second I try to extract GPS info, and from third queue I am saving to CSV file file name and longitude / latitude.

Tasks.Run vs Thread

Details
Written by: Stanko Milosev
Category: C#
Published: 02 February 2025
Last Updated: 12 March 2025
Hits: 799
Here is my example of reading records from Database using Tasks in background, and Threads.

As Jon Skeet wrote on Stack Overflow:

A task returned by Task.Run() really is saying "I want you to execute this code separately"; the exact thread on which that code executes depends on a number of factors.
So, here is first my method with async. First install Microsoft.Data.SqlClient here notice that old System.Data.SqlClient is deprecated.

Now the method:

return Task.Run(() => ThreadReadFromDatabaseAsync(connectionString, sql));

private async Task ThreadReadFromDatabaseAsync(string connectionString, string sql)
{
	DateTime start = DateTime.Now;
	try
	{
		await using SqlConnection connection = new SqlConnection(connectionString);
		await connection.OpenAsync();
		await using SqlCommand command = new SqlCommand(sql, connection);
		command.CommandTimeout = 3600;
		await using SqlDataReader reader = await command.ExecuteReaderAsync();
		int recdCnt = 0;
		while (reader.Read())
		{
			UpdateUi.Execute($"{start} Reading using tasks record {recdCnt++}", LblRecordCount, Form);

			object[] values = new object[reader.FieldCount];
			reader.GetValues(values);
		}
	}
	catch (Exception ex)
	{
		UpdateUi.Execute($"Error in task execution: {ex.Message}", LblError, Form);
	}
	finally
	{
		UpdateUi.Execute($"{DateTime.Now} Done with task execution", LblStatus, Form);
	}
}
Here notice line:
while (reader.Read())
That I am not using ReadAsync. The problem is that at ReadAsync will stuck on reading from DB after few hundert records, this looks like bug described here.

Now another example with thread:

var thread = new Thread(() => ThreadReadFromDatabase(connectionString, sql))
{
	Name = "ThreadReadFromDatabase",
	IsBackground = true
};
thread.Start();

private void ThreadReadFromDatabase(string connectionString, string sql)
{
	DateTime start = DateTime.Now;

	try
	{
		using SqlConnection connection = new SqlConnection(connectionString);
		connection.Open();
		using SqlCommand command = new SqlCommand(sql, connection);
		command.CommandTimeout = 3600;
		using SqlDataReader reader = command.ExecuteReader();
		int recdCnt = 0;
		while (reader.Read())
		{
			UpdateUi.Execute($"{start} Reading using threads record {recdCnt++}", LblRecordCount, Form);

			object[] values = new object[reader.FieldCount];
			reader.GetValues(values);
		}
	}
	catch (Exception ex)
	{
		UpdateUi.Execute($"Error in thread execution: {ex.Message}", LblError, Form);
	}
	finally
	{
		UpdateUi.Execute($"{DateTime.Now} Done with thread execution", LblStatus, Form);
	}
}
Full example download from here

UPDATE 2025-03-12: Avoid using Task.Run for long-running work that blocks the thread

Also from the book Concurrency in C# Cookbook by Stephen Cleary:

As soon as you type new Thread(), it’s over; your project already has legacy code

Also check this Stack Overflow answer.

Logger wrapper for Windows Forms

Details
Written by: Stanko Milosev
Category: C#
Published: 21 November 2024
Last Updated: 24 November 2024
Hits: 988
This is my example of logger wrapper from Steven van Deursen.

The part available in the Stack Overflow article will not be repeated here; instead, I will focus on the WinForms-specific implementation.

Since I often build different tools using Windows Forms, I aim to have a central place to display information or errors in a TextBox that is immediately visible. The problem is that I want to have constructor injection in Program.cs, which happens before any components in a form are created. To solve this, I added a TextBox property to my TextBoxLogger class:

namespace LoggerWrapper.Logger;

public class TextBoxLogger : ILogger
{
    public TextBox? TextBox { get; set; }
    public void Log(LogEntry entry)
    {
        TextBox?.AppendText(
            $@"[{entry.Severity}] {DateTime.Now} {entry.Message} {entry.Exception}");
        TextBox?.AppendText(Environment.NewLine);
    }
}
Notice:
public TextBox? TextBox { get; set; }

Later, I will connect this property to the actual TextBox in Form1. Here’s what my Program.cs looks like:

using LoggerWrapper.Logger;

namespace LoggerWrapper
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            ApplicationConfiguration.Initialize();

            var textBoxLogger = new TextBoxLogger();
            var someDiClassHandler = new SomeDiClassHandler(textBoxLogger);

            Form1 form1 = new Form1(someDiClassHandler);
            textBoxLogger.TextBox = form1.TbLogger;

            Application.Run(form1);
        }
    }
}
Notice:
textBoxLogger.TextBox = form1.TbLogger;
In Form1, I introduced a property named TbLogger:
namespace LoggerWrapper;

public partial class Form1 : Form
{
    public TextBox? TbLogger { get; }

    private readonly SomeDiClassHandler _someDiClassHandler;

    public Form1(SomeDiClassHandler someDiClassHandler)
    {
        InitializeComponent();

        TbLogger = tbLogger;

        _someDiClassHandler = someDiClassHandler;
    }

    private void btnStart_Click(object sender, EventArgs e)
    {
        SomeDiClassCommand someDiClassCommand = new SomeDiClassCommand();
        _someDiClassHandler.Execute(someDiClassCommand);
    }
}
After creating Form1 I will assign TextBox to my TextBoxLogger, and in Form1 constructor I will assign TbLogger to real TextBox, in my case tbLogger:
        TbLogger = tbLogger;
Example download from here

Validating XML with XSL in .Net Core

Details
Written by: Stanko Milosev
Category: C#
Published: 16 October 2024
Last Updated: 17 November 2024
Hits: 1296
  • xml
  • xslt 2.0
Here I already explained once how it can be done in .Net Framework, with Saxon-Se, and now here is experimental example in .Net Core.

Install NuGet package SaxonHE12s9apiExtensions.

In .csproj add something like:

<ItemGroup>
	<PackageReference Include="IKVM.Maven.Sdk" Version="1.8.2"/>
	<MavenReference Include="net.sf.saxon:Saxon-HE" version="12.5"/>
	<PackageReference Include="SaxonHE12s9apiExtensions" Version="12.5.9.4"/>
</ItemGroup>
Use this method to return result as a string which later you can convert to XML as I already explained here:
using net.sf.saxon.s9api;
using net.liberty_development.SaxonHE12s9apiExtensions;
...
string ValidateXmlFile(string xmlFile, string xslFile)
{
    Processor processor = new Processor();
    DocumentBuilder builder = processor.newDocumentBuilder();

    XsltTransformer xsltTransformer = processor.newXsltCompiler().Compile(new Uri(xslFile)).load();
    var inputNode = builder.Build(new Uri(xmlFile));
    xsltTransformer.setInitialContextNode(inputNode);
    using var stringWriter = new StringWriter();
    Serializer serializer = processor.NewSerializer(stringWriter);
    xsltTransformer.setDestination(serializer);
    xsltTransformer.transform();
    return stringWriter.ToString();
}
Example download from here.
  1. Validating XML with Schematron
  2. Validating XML with XSL
  3. Master - Detail with DataGridView and DataTables example
  4. Simple MVVM example in Windows Forms

Subcategories

WPF

Beginning

Code snippets

NUnit

LINQ

Windows Forms

Page 4 of 39

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10