---
title: "Saigkills Toolbox"
author: "Sascha Manns"
url: "https://writebook.saschamanns.de/4/saigkills-toolbox"
---

# Introduction

This is a collection of my personal tools and libraries.

* Firewall checker
* DateOnlyConverter
* DateTimeExtensions
* IEnumerableExtensions
* StringExtensions
* DataTableGenerator
* TemporaryDirectory Generator
* Hash Generator
* TemporaryFile Generator
* Pipeline pattern support
* Retry pattern support
* CSV Service
* Email Service
* WebDav Service

The project is splitted into several subprojects. Each subproject is a single NuGet package.

## CheckIpAndPort
That method checks, if a given IP and a given port is accesable.

### Usage

```csharp
bool isAvailable = Firewall.CheckIpAndPort("127.0.0.1", 80);
```

The result value is a Ardalis.Result, what represents if its available or not.

## PingIp

Checks if a given IP is pingable.

### Usage

```csharp
bool isAvailable = Firewall.PingIp("127.0.0.1");
```

The result value is a Ardalis.Result, what represents if its available or not.

# DateOnlyConverter

The DateOnlyConverter is an extension for any database context within the Entity Framework. If this is integrated, all DateOnly fields are mapped to DateTime.

# DateTimeExtensions

## ConvertDateToNumeric

This method converts DateTime to a purely numeric value in the format "yyyyMMdd". Example: 20240112

```csharp
var dt = DateTime.Now;
var myInt = dt.ConvertDateToNumeric(dt);
```

## ConvertDateTimeToString

This method converts the DateTime object to the format "yyyy-MM-dd HH:mm:ssZ"

```csharp
var dt = DateTime.Now;
var myInt = dt.ConvertDateTimeToString(dt);
```

## IsBetween

This method checks if a given DateTime is between two other DateTime values. Returns true if the date is between the start and end dates, inclusive.

```csharp
var date = new DateTime(2023, 10, 15);
var startDate = new DateTime(2023, 10, 1);
var endDate = new DateTime(2023, 10, 31);

var result = date.IsBetween(startDate, endDate);
```

## StartOfDay

This method returns the start of the day for a given DateTime, setting the time to 00:00:00. 

```csharp
var date = new DateTime(2023, 10, 15, 14, 30, 45);     
var result = date.StartOfDay();
```

## EndOfDay

This method returns the end of the day for a given DateTime, setting the time to 23:59:59.

```csharp
var date = new DateTime(2023, 10, 15, 14, 30, 45);      
var result = date.EndOfDay();
```

## IsWeekend

This method checks if a given DateTime falls on a weekend (Saturday or Sunday).

```csharp
var date = new DateTime(2023, 10, 14); // Saturday
var result = date.IsWeekend();
```

## NextBusinessDay

This method calculates the next business day after a given DateTime, skipping weekends.

```csharp
var date = new DateTime(2023, 10, 13); // Friday      
var result = date.NextBusinessDay();
```

# IEnumerableExtensions

## IsEmpty

This method checks, if a given IEnumerable is empty.

```csharp
var filledEnumeration = new IEnumeration<Model>();
filledEnumeration.IsEmpty<Model>(); // returns true or false
```

## IsNotEmpty

This method checks, if a given IEnumerable is not empty.

```csharp
var filledEnumeration = new IEnumeration<Model>();
filledEnumeration.IsNotEmpty<Model>(); // returns true or false
```

## IsNullOrEmpty

This method checks if a given IEnumerable is null or empty.

```csharp
IEnumerable<int>? collection = null;
var result = collection.IsNullOrEmpty();
```

## HasItems

This method checks if a given IEnumerable has any items.

```csharp
var collection = new List<int> { 1, 2, 3 };
var result = collection.HasItems();
```

## Foreach

This method iterates over each item in an IEnumerable and executes a specified action on each item.

```csharp
var collection = new List<int> { 1, 2, 3 };      
var result = collection.HasItems();
```

## WhereNotNull
This method filters an IEnumerable to include only non-null items.

```csharp
var collection = new List<string?> { "a", null, "b", null, "c" };      
var result = collection.WhereNotNull();
```

## ToSafeList

This method converts an IEnumerable to a List, ensuring that it is not null. If the input is null, it returns an empty list.

```csharp
IEnumerable<int>? collection = null;      
var result = collection.ToSafeList();
```

# OptimisedLinqExtensions

## AnyFast

This method checks if any element in an IEnumerable satisfies a specified condition, optimized for performance.

```csharp
var collection = new List<int> { 1, 2, 3 };      
var result = collection.AnyFast();
```

## FirstOrDefault
This method retrieves the first element of an IEnumerable that satisfies a specified condition, or returns a default value if no such element exists. It is optimized for performance.

```csharp
var collection = new List<int>();
var result = collection.FirstOrDefault(0);
```

## TakeFast

This method retrieves a specified number of elements from the start of an IEnumerable, optimized for performance.

```csharp
var collection = new List<int> { 1, 2, 3 };
var result = collection.TakeFast(0);
```

# String Extensions

## GetSalutationText

This method returns the salutation based on a gender characteristic.

"Male" becomes "Herr" and "Female" becomes "Frau" (german words).

```csharp
var gender = "Male"
var salutation = gender.GetSalutationText();

```

## ReturnGenderId

This method returns a gender ID based on a gender characteristic.

"Male" becomes "1" and "Female" becomes "2."

```csharp
var gender = "Male"
var genderId = gender.ReturnGenderId();

```

## IsNullOrEmpty
This method checks if a given string is null or empty.

```csharp
var value = "Test";
var result = value.IsNullOrEmpty();
```

## ToSafeString

This method converts a string to a safe string, returning an empty string if the input is null.

```csharp
object? value = null;
var result = value.ToSafeString();
```

## Truncate

This method truncates a string to a specified length, appending an ellipsis ("...") if the string exceeds that length.

```csharp
var value = "This is a long string";
var maxLength = 10;
var result = value.Truncate(maxLength);
```

# ValidationExtensions

## IsValidEmail

This method checks if a given string is a valid email address using System.Net.Mail.

```csharp
var email = "test@example.com";
var result = email.IsValidEmail();
```

## IsValidPhoneNumber

This method checks if a given string is a valid phone number. Number must between 10 and 15 digits long.

```csharp
var phoneNumber = "+1234567890";
var result = phoneNumber.IsValidPhoneNumber();
```

## IsInRange

This method checks if a given integer is within a specified range. Can be usedwith int and decimal types.

```csharp
var value = 15;
var result = value.IsInRange(1, 10);
```

## ValidateRequired

This method checks if a given string is not null or empty, and throws an exception if it is.

```csharp
var value = "Test";
var fieldName = "Field";
var result = value.ValidateRequired(fieldName);
```

# DataTableGenerator

The DataTableGenerator is a generic class that creates a DataTable from any list model.

## Instantiation and call

```csharp
private void YourMethod()
{
List<SourceModel> yourModel = new();
var logger = new ILogger<DataTableGenerator>();
var dtg = new DataTableGenerator<SourceModel>(logger);
var yourDataTable = dtg.GenerateDataTablleFromModelList(yourModel, false);
}
```

## ID field
The method offers two modes. In the "withId = true" mode, a DataTable with an ID field is created. If false is set, a table without an ID field is generated.

# Hash

Simple hashing method. Just give him a string and it works for you.

# Temporary Directory

This method creates a randomly generated directory and returns the path.

## Usage

```csharp
var tempDirectory = TempTools.GetTemporaryDirectory();
```

# TemporaryFile

Generates and disposes a temporary file.

# Pipeline Pattern

This is a behavioral pattern where the main goal is to split a complex job into multiple steps, each with a specific functionality. It�s really good for several types of architectures. For a system composed of various microservices with numerous components, this is a way to keep things easier to read and maintain.
This pattern has several key concepts similar to the chain of responsibility one.

## IPipeline

```csharp
public interface IPipeline<T>
{
    public string Name { get; set; }
    public IReadOnlyCollection<IStep> Steps { get; }
    void WithStep(IStep step);
    Task<T> StartAsync(IData data);
}
```

## IStep

```csharp
public interface IStep
{
    Task<IData> ExecuteAsync(IData data);
}
```

## Pipeline generic

```csharp
public class Pipeline<T> : IPipeline<T> where T : IData
{
    private readonly List<IStep> _steps = new();
    public string Name { get; set; }
    public IReadOnlyCollection<IStep> Steps => _steps;

    public Pipeline(string name)
    {
        Name = name;
    }

    public void WithStep(IStep step)
    {
        _steps.Add(step);
    }

    public async Task<T> StartAsync(IData input)
    {
        IData result = input;
        foreach (var step in Steps)
        {
            try
            {
                result = await step.ExecuteAsync(result);
            }
            catch (Exception)
            {
                throw;
            }
        }
        return (T)result;
    }
}
```

## Example Usage

```csharp
var pipeline = new Pipeline<OutputData>("MyFirstPipeline");

pipeline.WithStep(new ToUpperStep());
pipeline.WithStep(new TextLengthStep());

var input = new InputData
{
   Text = "Hello World!"
};

var output = await pipeline.StartAsync(input);

Console.WriteLine($"Starting pipeline {pipeline.Name}...");
Console.WriteLine($"Input text: '{input.Text}'");
Console.WriteLine($"Length of text is: {output.Result}");
```

Idea from [Tiago Martins](https://medium.com/@martinstm/pipeline-pattern-c-e01e2dd7238c).

# Result pattern

## Result

This class can be used for using the result pattern.

### Usage

```csharp
public Result<string> GetUserNameById(int userId)
{
    if (userId <= 0)
    {
        return Result<string>.Failure("Invalid user ID");
    }

    // We simulate obtaining a username
    string userName = "John Doe"; // This would be the actual logic to get the name

    return Result<string>.Success(userName);
}

public void ProcessUserName()
{
    var result = GetUserNameById(1);

    if (result.IsSuccess)
    {
        Console.WriteLine($"User name: {result.Value}");
    }
    else
    {
        Console.WriteLine($"Error: {result.ErrorMessage}");
    }
}
```

### More
More about that on: [David May](https://medium.com/@davisaac8/an-alternative-to-try-catch-in-c-b0e5dfafa910)

# CsvService

The CsvService offers the possibility to pass any list model in order to generate a CSV file from it.

## Usage

### DependencyInjection (Program.cs)
```csharp
Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, configuration) =>
    {
        configuration.Sources.Clear();
        configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        IConfigurationRoot configurationRoot = configuration.Build();
        Configuration = configurationRoot;              
	}).ConfigureServices((services) =>
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);        
        services.AddSingleton<ICsvWriterService, CsvWriterService>();
    });
```

### Usage after Dependency Injection
```csharp
private void DeineMethode()
{
   var model = new SomeModel();
   await _service,Write(model, pathWithFilename);
}
```

# EmailService

A service for sending emails. This implementation is for usecases where the mailserver is reachable internal without authentification.

## Usage

### Configuration

You need to configure the follwing in the sppsettings.json:

```json
{
  "EmailServer": {
    "DefaultEmailAddress": "x@y.com",
    "DefaultSenderName": "My Bot or My Name",
    "ServerIP": "Servers IP or Hostname",
    "Host": "Hostname",
    "Port": 587
}
```

### DependencyInjection (Program.cs)
```csharp
Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, configuration) =>
    {
        configuration.Sources.Clear();
        configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        IConfigurationRoot configurationRoot = configuration.Build();
        Configuration = configurationRoot;              
	}).ConfigureServices((services) =>
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);
        services.AddSingleton<IEmailService, EmailService>();
    });
```

### Usage

```csharp
private void AMethod()
{
var email = new MimeMessage
		{
			Subject = "Subject",
			Body = new TextPart("plain") { Text = @$"Lorem ipsum dolor Saschas Bot :-)" },
			To =
			{
				new MailboxAddress("recipient1", "Emailaddress"),
				new MailboxAddress("recipient2", "Emailaddress")
			}
		};

		await _emailService.SendMessageAsync(email);
}
```

# EmailServiceWithAuth

A service for sending emails. This implementation is regular scenarios with authentification.

## Usage

### Configuration

You need to configure the follwing in the sppsettings.json:

```json
{
  "EmailServer": {
    "DefaultEmailAddress": "x@y.com",
    "DefaultSenderName": "My Bot or My Name",
    "Host": "Hostname",
    "Port": 587,
    "User": "anything@example.de",
    "Password": "password"
}
```

### DependencyInjection (Program.cs)
```csharp
Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, configuration) =>
    {
        configuration.Sources.Clear();
        configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        IConfigurationRoot configurationRoot = configuration.Build();
        Configuration = configurationRoot;              
	}).ConfigureServices((services) =>
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);
        services.AddSingleton<IEmailService, EmailServiceWithAuth>();
    });
```

### Usage

```csharp
private void AMethod()
{
var email = new MimeMessage
		{
			Subject = "Subject",
			Body = new TextPart("plain") { Text = @$"Lorem ipsum dolor Saschas Bot :-)" },
			To =
			{
				new MailboxAddress("recipient1", "Emailaddress"),
				new MailboxAddress("recipient2", "Emailaddress")
			}
		};

		await _emailService.SendMessageAsync(email);
}
```


# EmailServiceWithAuth

A service for sending emails. This implementation is regular scenarios with authentification. It returns Rasult.Success or Result.Error with an error message instead of throwing an exception. This can be used to handle errors more gracefully in the calling code.

## Usage

### Configuration

You need to configure the follwing in the sppsettings.json:

```json
{
  "EmailServer": {
    "DefaultEmailAddress": "x@y.com",
    "DefaultSenderName": "My Bot or My Name",
    "Host": "Hostname",
    "Port": 587,
    "User": "anything@example.de",
    "Password": "password"
}
```

### DependencyInjection (Program.cs)
```csharp
Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, configuration) =>
    {
        configuration.Sources.Clear();
        configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        IConfigurationRoot configurationRoot = configuration.Build();
        Configuration = configurationRoot;              
	}).ConfigureServices((services) =>
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);
        services.AddSingleton<IEmailService, EmailServiceWithAuth>();
    });
```

### Usage

```csharp
private void AMethod()
{
var email = new MimeMessage
		{
			Subject = "Subject",
			Body = new TextPart("plain") { Text = @$"Lorem ipsum dolor Saschas Bot :-)" },
			To =
			{
				new MailboxAddress("recipient1", "Emailaddress"),
				new MailboxAddress("recipient2", "Emailaddress")
			}
		};

		await _emailService.SendMessageAsync(email);
}
```

# WebDavService

The WebDavService offers the possibility to upload or download files to a WebDavServer.

## Instantiation
The service is integrated via dependency injection:
```csharp
Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, configuration) =>
    {
        configuration.Sources.Clear();
        configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        IConfigurationRoot configurationRoot = configuration.Build();
        Configuration = configurationRoot;              
	}).ConfigureServices((services) =>
    {
        services.AddSingleton<IConfigurationRoot>(Configuration);
        services.AddSingleton<IWebDavService, WebDavService>();
    });
```

## Configuration
As a minimum configuration we need the following settings:
The respective values ​​are for demo purposes only and must be adjusted.

```json
{
   "WebDavServer": {
	"Password": "Password",	
	"Url": "Webdav Server Url",
	"Username": "Username"
   }
}
```

The "WebDavServer:Password" is the password for the WebDav server, the "WebDavServer:Url" is the URL of the WebDav server. The "WebDavServer:Username" is the login username.

## Call
The following methods can be called:

### `DownloadFileAsync(string remotefilepath, string localfilepath)`
The method downloads a file (remotefilepath) and saves it in the localfilepath.

**IMPORTANT**: Both paths contain both the path to the file and the file name itself.

### `DeleteFileAsync(string remotefilepath)`
The method deletes a file.

**IMPORTANT**: The remotefilepath contains the path to the file and also the file name itself.

### `UploadFileAsync(string localfilepath, string remotefilepath)`
The method uploads a file to a WebDav path.
**IMPORTANT**: Both paths include the path to the file as well as the file name itself.
