Author Archives: Berend de Jong

Validating objects at creation time

If we have more complex validation logic, we could introduce a factory method and a Result object to handle the validations better:

public record Result<T>
{
    public bool IsSuccess { get; private init; }
    public T? Value { get; private init; }
    public string? ErrorMessage { get; private init; }

    private Result(){}

    public static Result<T> Success(T value) => new() 
    {
       IsSuccess = true, Value = value
    };
    public static Result<T> Failure(string errorMessage) => new()
    {
        IsSuccess = false, ErrorMessage = errorMessage
    };
}

Here we declare the generic Result record, so now let’s see how to create the factory method for the Money value object:

public record Money
{
    private static readonly IReadOnlyCollection<string> SupportedCurrencies = new[]{"USD", "EUR"};

    public decimal Amount { get; }
    public string Currency { get; }
    
    private Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }

    public static Result<Money> Create(decimal amount, string currency)
    {
        if(string.IsNullOrWhiteSpace(currency))
            return Result<Money>.Failure($"{nameof(currency)} cannot be null or whitespace.");

        if(!SupportedCurrencies.Contains(currency.ToUpperInvariant()))
            return Result<Money>.Failure($"'{currency}' is not supported.");
        
        return Result<Money>.Success(new(amount, currency));
    }
}

Instead of throwing exceptions (or simply returning False), we return a Failure result (with a specific message), allowing the caller to handle this in a cleaner fashion.

Share

c# async in constructors

In C#, constructors cannot be declared as async because they are special methods used for object initialization and cannot be awaited. However, you can use an asynchronous factory method or an initialization method to perform asynchronous operations during object creation. Here’s an example:

public class MyClass
{
    private MyClass()
    {
        // Private constructor to enforce the usage of factory method
    }

    public static async Task<MyClass> CreateAsync()
    {
        var instance = new MyClass();
        await instance.InitializeAsync();
        return instance;
    }

    private async Task InitializeAsync()
    {
        // Perform asynchronous initialization tasks here
        await Task.Delay(1000); // Example asynchronous operation
    }
}

In the above example, the constructor for MyClass is marked as private to enforce the usage of the CreateAsync factory method. The CreateAsync method creates an instance of MyClass, calls the private constructor, and then asynchronously initializes the object by calling the InitializeAsync method. You can perform any necessary asynchronous operations within the InitializeAsync method.

To create an instance of MyClass, you would use the CreateAsync method as follows:

var myObject = await MyClass.CreateAsync();

By using this approach, you can achieve asynchronous behavior during object construction in C#.

Share

Bootstrap Image dropdown

Below is a bootstrap fragment to setup a dropdown input with images.

<html>

<head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <style>
        .img-dropdown {
            display: inline-block;
            vertical-align: middle;
            margin-right: 10px;
            width: 20px;
            height:20px;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="row">
            <div class="col">
                <div style="float:left">
                    <div class="dropdown">
                        <button class="btn btn-secondary" type="button" id="dropdownMenuButton"
                            data-bs-toggle="dropdown" aria-expanded="false">
                            <div id="languageButtonText">??</div>
                        </button>
                        <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton" id="ulLanguages">
                            <li>
                                <a class="dropdown-item" href="#" data-value="DE">
                                    <img src="img/de.svg" alt="Image 1" class="img-dropdown">
                                    German
                                </a>
                            </li>
                            <li>
                                <a class="dropdown-item" href="#" data-value="FR">
                                    <img src="img/fr.svg" alt="Image 2" class="img-dropdown">
                                    French
                                </a>
                            </li>
                            <li>
                                <a class="dropdown-item" href="#" data-value="GB">
                                    <img src="img/gb.svg" alt="Image 3" class="img-dropdown">
                                    English
                                </a>
                            </li>
                            <li>
                                <a class="dropdown-item" href="#" data-value="NL">
                                    <img src="img/nl.svg" alt="Image 4" class="img-dropdown">
                                    Dutch
                                </a>
                            </li>
                            <li>
                                <a class="dropdown-item" href="#" data-value="Frisian">
                                    <img src="img/frisian.svg" alt="Image 5" class="img-dropdown">
                                    Frisian
                                </a>
                            </li>
                        </ul>
                    </div>
                </div>
                <div style="float:left">
                    <div id="selected-image" style="align-items: center; display:flex;margin-left:5px"></div>
                </div>
            </div>
        </div>
    </div>
</body>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js"
    integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    crossorigin="anonymous"></script>
<script>
    $(document).ready(function () {

        // When a dropdown item is clicked
        $('.dropdown-item').click(function () {
            var lang = $(this).data('value');
            var id = 'Language';
            $('#' + id).val(lang);

            // Get the image source of the clicked item
            var selectedImageSrc = $(this).find('img').attr('src');

            // Set the selected image in the div
            $('#selected-image').html('<img src="' + selectedImageSrc + '" alt="Selected Image" width="51">');
            $("#languageButtonText").html(lang);
        });

        $("#ulLanguages li a").filter("[data-value=" + "Frisian" + "]").trigger("click");

    });
</script>

</html>
Share

Add syntax highlighting to ASP.NET site

To enable syntax highlighting on your ASP.NET site follow the steps below:

  1. Goto prismjs.com and press the Download button.
  2. Add the next items to the default languages: C#, ASP.NET (C#), Bash + Shell + Shell, C#, Razor C# and SQL.
  3. Also add the plugin “line-numbers”.
  4. At the bottom of the page download the prims.js and prism.css files.

In the Shared/_Layout.cshtml add both the prism.js and prism.css file.

In the Index.cshtml view add some code to test it out

<div class="row">
    <div class="col line-numbers">
<pre><code class="language-csharp">public class HelloWorld
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello, World!");
    }
}
</code>
</pre>
</div>
    <div class="col">
        <pre>
<code class="language-sql">
SELECT * FROM AspNetUsers u
LEFT JOIN AspNetRols on r.Id = u.Id
WHERE ID = 1;
</code>
    </pre>
    </div>
</div>

The resulting page will look like this

Share

VirtualMin error regarding can_use_gcloud_storage_creds 

After a fresh install of Ubuntu 22.04 and VirtualMin I tried to restore some WordPress sites to my new server. Created a backup on the old server. Next logged into the new server and in VirtualMin navigated to VirtualMin -> Backup and Restore -> Restore Virtual Servers. On this page I got the error as shown below.

HTTP/1.0 500 Perl execution failed Server: MiniServ/2.021 Date: Fri, 21 Apr 2023 07:11:21 GMT Content-type: text/html; Charset=utf-8 Connection: close

ERROR — PERL EXECUTION FAILED
Undefined subroutine &virtual_server::can_use_gcloud_storage_creds called at /usr/share/webmin/virtual-server/cloud-lib.pl line 304.

Not sure what causes this but it has something to do with the google cloud sdk not being installed on the server i suspect. I do not need this so I opend the cloud-lib.pl file in folder /usr/share/webmin/virtual-server/ and modified the perl code as a work around. Replace the function cloud_google_get_state with the definition below:

sub cloud_google_get_state
{
   return { 'ok' => 0 };
}

Next wait for a fix from VirtualMin.

Share

Use an in-memory database in EF Core 7

This is the minimal setup to use an in-memory datase in EF Core 7 with a Console program. C# solution can be found here.

After creating your C# Net Core 7 Console App project add two nuget packages to the project:

Install Package Microsoft.EntityFrameworkCore
Install Package Microsoft.EntityFrameworkCore.InMemory

Next add a class Person to your console project

internal class Person
{
    public int Id { get; set; }

    [Required]
    public string FirstName { get; set; } = string.Empty;
    [Required]
    public string LastName { get; set; } = string.Empty;
}

Next add your database context class, remember to derive it from DbContext.

internal class MyDatabaseContext : DbContext
{
    public DbSet<Person> Persons { get; set; }

    public MyDatabaseContext(DbContextOptions<MyDatabaseContext> options) : base(options)
    {
    }
}

Now we can use our database context in the main program as shown below

MyDatabaseContext db = new MyDatabaseContext(
    new DbContextOptionsBuilder<MyDatabaseContext>().UseInMemoryDatabase("TEST").Options);

db.Persons.Add(new Person() {  FirstName = "Berend", LastName = "de Jong"});
db.SaveChanges();
db.Persons.ForEachAsync((person) => Console.WriteLine($"{person.Id}\t{person.FirstName}\t{person.LastName}"));

As an alternative you can use a parameterless constructor and override the OnConfiguring method of the DbContext class to configure your connection.

Remove the options parameter from the constructor and the call to the base constructor. Next override the OnConfiguring method of the DbContext as shown below.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseInMemoryDatabase("TEST");
}
Share

Using a test collection with test fixture in 5 steps

Sometimes you need some generic setup code for your tests. As you might know the constructor is called for every test Fact in your test class. For setup code that only needs to run once you can define a Test Fixture class. In the steps below is outlined how this can be accomplished in C#.

Define a collection definition by using the CollectionDefinition attribute

namespace XUnitTestProject
{
    using Xunit;

    [CollectionDefinition("MyTestCollection")]
    public class MyTestCollectionDefinition : ICollectionFixture<MyTestFixture>
    {
    }
}

Create the MyTextFixture class

public class EWCTestFixture
{
    public MyDbContext Context;

    public MyTestFixture()
    {
        MySqlConnection Connection = new MySqlConnection(connectionString);

        Context = new MyDbContext(userService, new DbContextOptionsBuilder<MyDbContext>()
            .UseMySql(Connection, ServerVersion.AutoDetect(Connection.ConnectionString)).Options);
        Context.Database.EnsureCreated();
        Connection.Open();
    }
}

Create a test collection for this fixture by using the Collection attribute (be sure you use the same name as used by the CollectionDefinition). The test framework takes care of injecting the MyTestFixture into the constructor.

[Collection("MyTestCollection")]
public class MyDbContextShould : IDisposable
{
    private MyTestFixture Fixture;

    private IDbContextTransaction transaction { get; }

    public MyDbContextShould(MyTestFixture fixture)
    {
        this.Fixture = fixture;
        this.transaction = Fixture.Context.Database.BeginTransaction();
    }
}

Use the test fixture in your test facts where needed.

[Fact]
public void MyObjectIsStoreInheDatabase()
{
    Fixture.Context.MyObjects.Add(new MyObject());
    Fixture.Context.SaveChanges();
    Assert.Single(Fixture.Context.MyObjects);
}

Finally define a dispose object to dispose the transaction created in the constructor.

public void Dispose()
{
    this.transaction.Dispose();
}
Share

Determine domain behind proxy in ASP.NET MVC controller

Sometimes you need to know the domain on which your app is running. If you are behind a proxy there is not a straightforward way to determine this.

To get the “real” domain name for your app check the “X-Forwarded-Host” HTTP header and use this as your host name when, for example, sending links in emails to your app.

First step is to get the host name:

public static string GetForwardedHost(HttpRequest Request)
{
   string host = Request.Headers["X-Forwarded-Host"];
   if (host == null)
   {
      host = Request.Host.ToString();
   }
   return host;
}

Next when you assemble a link for in example an email you want so sent use the code below

var host = Utils.GetForwardedHost(Request);

var callbackUrl = Url.Page(
                    "/Account/ResetPassword",
                    pageHandler: null,
                    values: new { area = "Identity", code },
                    protocol: Request.Scheme, host : host);

this.SendEmail(Input.Email, "Reset Password", $"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
Share

Cross-Site HTTP Requests

A request for data from a different server (other than the requesting page), are called cross-site HTTP requests.

Cross-site requests are common on the web. Many pages load CSS, images, and scripts from different servers.

In modern browsers, cross-site HTTP requests from scripts are restricted to same site for security reasons.

To allow Cross-site requests to your api, add the following package

Microsoft.AspNetCore.Cors

In program.cs add the line

builder.Services.AddCors();

Add add the next line after your app is build (var app = builder.Build())

app.UseCors(<br>options => options.WithOrigins("https://localhost:7219").AllowAnyMethod());

Share