- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 759
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.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 799
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.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 988
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
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 1296
<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.