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

Synology Docker MariaDb / .NET Core 6 / Homewizzard Electrical meter reading

HomeWizard P1 meter

Recently I came across a small device that can be connected to the Smart Energy Meter as it is used in the Netherlands, among other places:

HomeWizard.nl

This small device is connected to the P1 port of the smart meter. The HomeWizzard is then connected to the WiFi network.

The HomeWizzard device publishes a REST api at this endpoint https://[your-homewizzard-device-ip]/api/v1/data.

Continue reading
Share