Wednesday, March 26, 2025

Tests in the very same console app - compilation error in .NET Core

Having unit tests in the very same console app causes a compilation error:

Program has more than one entry point defined. Compile with /main to specify the type that contains the entry point.

Kind of unexpected, there's definitely a single Main.

There problem seems to be there for all these years, despite being first described back in 2017

The solution is alread provided in the link above, just add

<GenerateProgramFile>false</GenerateProgramFile>

to the *.csproj

A brave little cookie-footer

One of our apps contains a page and the page has a div. The div's class name is cookie-footer.

The div itself has nothing to do with actual cookies, it contains a content that user is supposed to see.

And what? Turns out Brave doesn't show that div. It just adds:

// user agent stylesheet
.cookie-footer {
    display: none !important;
}

What's bizzare, Brave doesn't add this always. We have the app on multiple domains, the user agent style is added on most of domains but not all of them!

Tried other variants:

  .cookie-footer  - blocked
  .cookiefooter   - blocked
  .cookie--footer - works
  .cookiee-footer - works
  .coookie-footer - works

Great times. It's not only the legal regulation that can block your content, it's also your browser heuristic.

Monday, March 17, 2025

A fairy tale of misusing the C# typesystem

Once upon a time in a kingdom far far away someone wrote a code that required two string arguments:

    public class Worker
    {
        public void DoWork( string name, string surname )
        {
            Console.WriteLine( $"{name} {surname}" );
        }
    }

All the people used the code for years without any issues:

    new Worker().DoWork( "john", "doe" );

Then, someone in a hurry did something bad which should never happen. Arguments were swapped in a call:

    new Worker().DoWork( "doe", "john" );

Consequences were severe.

The culprit was tried and expelled from the kingdom. The king called for his best wizards and asked them to do something so that it never ever happens in the future.

One of the wizards suggested that introducing types would make it clear of what real intentions of arguments are:

    public class Name
    {
        public Name( string value )
        {
            this.Value = value;
        }

        public string Value { get; set; }

        public override string ToString()
        {
            return this.Value;
        }
    }

    public class Surname
    {
        public Surname( string value )
        {
            this.Value = value;
        }

        public string Value { get; set; }
        public override string ToString()
        {
            return this.Value;
        }
    }


    public class Worker
    {
        public void DoWork( Name name, Surname surname )
        {
            Console.WriteLine( $"{name} {surname}" );
        }
    }

Initially people complained a bit but then started to get used to the new calling convention:

    new Worker().DoWork( new Name( "john" ), new Surname( "doe" ) );

The problems were gone. Everyone was happy.

Years passed, some wizards were gone, new wizards came to the kingdom. One of new wizards reviewed the code and came up with an idea.

- Why this convention is that awkward, why wrap strings in auxiliary types? - thought the wizard.

And he came up with an idea to add implicit conversion operators:

    public class Name
    {
        public Name( string value )
        {
            this.Value = value;
        }

        public string Value { get; set; }

        public override string ToString()
        {
            return this.Value;
        }

        public static implicit operator Name( string value )
        {
            return new Name( value );
        }
    }

    public class Surname
    {
        public Surname( string value )
        {
            this.Value = value;
        }

        public string Value { get; set; }
        public override string ToString()
        {
            return this.Value;
        }

        public static implicit operator Surname( string value )
        {
            return new Surname( value );
        }
    }
 

The new wizard was very proud of himself. He barely told anyone of his conversion operators so everyone else was still using the well established convention:

   new Worker().DoWork( new Name( "john" ), new Surname( "doe" ) );

But, since the conversion was now implicit, the wizard was able to make his own code shorter:

   new Worker().DoWork( "john", "doe" );

Years passed, new people arrived and then, someone in a hurry did something bad which should never happen. Arguments were swapped in a call:

    new Worker().DoWork( "doe", "john" );

Consequences were severe.

Was the culprit tried and expelled from the kingdom, same as last time?

Not really, the Wizard Council blamed the new wizard, the one who introduced both implicit conversion operators.

He was tried and expelled from the kingdom. His changes were reverted forever and everyone lived happily ever after.


This is based on a (almost) true story.

But can it run DOOM?

I barely repost news from elsewhere but this time this is extremely impressive.

It was announced that Dimitri Mitropoulos from the TypeScript team was able to build a WebAssembly interpreter in the TypeScript typesystem and then make it run DOOM, still inside the type system. Well, not quite "run", just render the first frame which took 12 days.

Anyway, it's inspiring to hear such news. Congratulations to the team!

Sunday, March 16, 2025

XNADash ported to .NET8/Monogame

Years ago, in 2011, I've blogged about an old DOS game I've ported to XNA. This weekend I've found the code and spent a while to make sure it works.

The new version targets .NET8/Monogame and is available on my Github.

Monday, March 10, 2025

OldMusicBox.ePUAP.Client 1.25.3

Bumped the OldMusicBox.ePUAP.Client to 1.25.3.

For some unknown reason that doesn't seem to be announced, the TpSiging5::GetSignedDocument changed the format of natural person's data (givenname, surname, personal identification number).

From the very beginning of the old TpSigning service, the document contained user signatures in the PodpisZP node. Later on, when TpSigning5 was introduced, they changed the signature to EPSignature node (different node with different model).

And guess what, starting from somewhere between 07-03-2025 and 10-03-2025, the new service (TpSigning5) returns the natural person's data in the old format (back to PodpisZP). Be aware of this and update your code accordingly.

Sunday, November 24, 2024

Yet another ASP.NET Core JWT tutorial?

Why would you need yet another ASP.NET Core JWT tutorial?

Well, becuse most of them are unnecessarily complicated. Some involve unnecessary APIs like the Identity API. Some try to introduce an OAuth2/OpenID Connect stack. There are ocassional cases where false assumptions are used to justify the need of JWT tokens.

An example of the latter is an argument that "cookies are bad since they require data stored in server's session container", given here. Of course, cookies do not require that anything is stored in the container session, a cookie can just contain a username and this is how authentication cookies are often used. Anyone using .NET cookie authentication for years would be surprised to hear that instead of just a username, an ASP.NET authentication cookie would contain a session ID and the server would only lookup user data at the server's session container.

It's not that unnecessarily elaborated demo or a demo that fails at some subtle reasons is bad. It's just harder to follow.

Why would you prefer JWT from cookies then?

There's only one valid argument: JWT tokens work crossdomain, cookies don't. In a setup where an authentication token is issued at domain A and is required at domain B, cookies don't work. JWT tokens on the other hand, are usually put in custom headers in web browser calls and thus can be easily sent anywhere.

What would I personally expect from a JWT tutorial?

Well, I'd expect following:

  • a web app that authenticates users somehow, could even be an endpoint that accepts a username/password pair but an easy approach would be a cookie-based authentication with a usual login page. An advantage of the latter is that I expect a good demo to show how to have both in a single app: a cookie-based authentication on some endpoints and JWT based authentication on other endpoints
  • I want to see an endpoint that is set up to issue JWT tokens then. The endpoint could assume the user is authenticated (e.g. with an already issued cookie) and would just create JWT containing the username
  • I want to see a data endpoint that is authenticated only with a JWT token, a cookie should not be accepted. The endpoint could be exposed on the very same app but I'd easily think of any other app (a different domain) exposing it
  • I don't want any extra frameworks, APIs, anything, just bare minimum

And what? And there it is, https://github.com/wzychla/AspJwtBearerDemo. A complete demo. Here's an overview:

  • the demo contains both MVC and WebAPI controllers
  • there are two MVC controllers, the Home controller is only accessible by users authenticated with a cookie, the Account controller is used as a default redirect for unauthenticated calls and uses SignInAsync to issue the cookie
  • as long as the cookie is issued, the Home::Index view is rendered
  • there are two active endpoints
  • first, the Token::Acquire is used to get the JWT token. Note how easy it is: the used should be authenticated somehow (= cookie in my demo) and the code just creates a plain JWT with just the username
  • then, the Data::Get WebAPI endpoint is secured with the JWT token. Note that by configuring the JWT stack to recognize the JWT name claim as username I can access this.User.Identity.Name in a WebAPI code and still have the username. The this.User.Identity.Name is then used in the very same way in both MVC cookie secured controllers and WebAPI JWT secured controllers. The key point of this JWT config is
    cfg.TokenValidationParameters = new TokenValidationParameters()
    {
       ValidateAudience = false,
       ValidateIssuer   = false,
       IssuerSigningKey = signingKey,
       NameClaimType    = "name"     // map JWT's name claim to NET's IPrincipal::IIdentity::Name
    }; 
    

What is actually really nice in ASP.NET Core is the idea of authentication scheme - we define multiple authentication schemes (in this demo, there are two: cookie based and JWT based) and then each time Authorize is used on an action (both MVC and WebAPI) we specify which authentication scheme should is accepted. Thus, having some endpoints secured with a cookie and other secured with JWT tokens is easy and clean.

That's it. Clone the Github demo, follow the flow, take a look how both schemes are configured in AddCookies and AddJwtBearer. Enjoy.