skip to content
Relatively General .NET

C#9 - init-only properties are not read-only at runtime

by Gérald Barré

posted on: November 04, 2020

C#9 adds the concept of init-only properties. These properties can be set when creating the object and become get only once object creation has been completed.C#copyclass Person { public string Name { get; init; } public string Username { get; init; } } void A() { var author = new Pers

Estimates Are Necessary

by Ardalis

posted on: November 03, 2020

This is the fifth and last of the 5 Laws of Software Estimates. I expanded on the fourth law of software estimates in my previous article…Keep Reading →

Domain model purity and lazy loading

by Vladimir Khorikov

posted on: November 02, 2020

I’m continuing the topic of domain model purity. Last time, we talked about domain model purity in the context of getting the current date and time. Today, we’ll discuss it with regards to lazy loading.

How to get ASP.NET Core logs in the output of xUnit tests

by Gérald Barré

posted on: November 02, 2020

Automated tests are very useful to validate that your application behaves correctly. When a test fails, this means something's wrong in your code. But this also means you'll have to debug your code… In this case, you need to get all the possible information to understand what happened.If your appli

The failure of a computer you didn't even know existed

by Oren Eini

posted on: October 30, 2020

The title of this post is a reference to a quote by Leslie Lamport: “A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable”.A few days ago, my blog was down. The website was up, but it was throwing errors about being unable to connect to the database. That is surprising, the database in question is running a on a triply redundant system and has survived quite a bit of abuse. It took some digging to figure out exactly what was going on, but the root cause was simple. Some server that I never even knew existed was down.In particular the crl.identrust.com server was down. I’m pretty familiar with our internal architecture, and that server isn’t something that we rely on. Or at least so I thought. CRL stands for Certificate Revocation List. Let’s see where it came from, shall we. Here is the certificate for this blog:This is signed by Let’s Encrypt, like over 50% of the entire internet. And the Let’s Encrypt certificate has this interesting tidbit in it:Now, note that this CRL is only used for the case in which a revocation was issued for Let’s Encrypt itself. Which is probably a catastrophic event for the entire internet (remember > 50%). When that server is down, the RavenDB client could not verify that the certificate chain was valid, so it failed the request. That was not expected and something that we are considering to disable by default. Certificate Revocation Lists aren’t really used that much today. It is more common to see OCSP (Online Certificate Status Protocol), and even that has issues.I would appreciate any feedback you have on the matter.

Putting JSON in a block chain? First decide what your JSON is…

by Oren Eini

posted on: October 29, 2020

RavenDB is a document database, as such, it stores data in JSON format. We have had a few cases of users that wanted to use RavenDB as the backend of various blockchains. I’m not going to touch on their reasoning. I think that a blockchain is a beautiful construct, but one that is searching for a good niche to solve. The reason for this post, however, is that we need to consider one of the key problems that you have to deal with the blockchain, how to compute the signature of a JSON document. That is required so we’ll be able to build a merkle tree, which is at the root of all blockchains.There are things such as JWS and JOSE to handle that, of course. And rolling your own signature scheme is not advisable. However, I want to talk about a potentially important aspect of signing JSON, and that is that there isn’t really a proper canonical form of JSON. For example, consider the following documents: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters // All of them are the same { "Name": "Discworld", "Rating": 5 } {"Name":"Discworld","Rating":5} { "Name": "Discworld", "Rating": 2, "Rating": 5 } { "Rating": 5, "Name": "Discworld" } { "Rating": 5, "Name": "Discworld" } { "Name": "D\u0069scworl\u0064", "Rating": 5 } view raw data.json hosted with ❤ by GitHub All of those documents have identical output. Admittedly, you could argue about the one using multiple Rating properties, but in general, they are the same. But if we look at the byte level representation, that is very far from the case.A proper way to sign such messages would require that we’ll:Minify the output to remove any extra whitespace.Error on multiple properties with the same key. That isn’t strictly required, but is going to make everything easier.Output them in a sorted order.Normalize the string encoding to a single format.Normalize numeric encoding (for example, whatever you support only double precision floats or arbitrary sized numbers).Only then can you actually perform the actual signature on the raw bytes. That also means that you can’t just pipe the data to sha256() and call it a day.Another alternative is to ignore all of that and decide that the only thing that we actually care about in this case is the raw bytes of the JSON document. In other words, we’ll validate the data as raw binary, without caring about the semantic differences. In this case, the output of all the documents above will be different. Here is a simple example of cleaning up a JSON object to return a stable hash: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters async function hash_json(obj) { async function digestMessage(message) { const msgUint8 = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } const replacer = (key, value) => value instanceof Object && !(value instanceof Array) ? Object.keys(value) .sort() .reduce((sorted, key) => { sorted[key] = value[key]; return sorted }, {}) : value; var msg = JSON.stringify(obj, replacer); return await digestMessage(msg); } view raw hash.js hosted with ❤ by GitHub That answer the above criteria and is pretty simple to run and work with. Including from other platforms and environments.

Webinar Recording

by Oren Eini

posted on: October 28, 2020

RavenDB is built to be your main database. It’s the system of record where you store all of your information. To minimize complexity, work, and cost, RavenDB also contains a fully-fledged full-text search engine. You can perform full text searches, but you don’t need a plugin or addon. This enables you to find interesting documents based on quite a lot of different criteria. In this Webinar, I show how you can run all sort of interesting queries and show off some of RavenDB’s full text search capabilities.