Running ASP.NET Core together with Nancy

1. Introduction

Our current API runs on Nancy which in my opinion is past its prime. Recent news from the GitHub issue tracker seems to confirm that thesis, that is why we started looking for a migration path from Nancy based API to ASP.NET Core. Because the codebase is quite large we didn’t want to do a Big Bang Rewrite but instead of that, we wanted to gradually replace old API with a new one, so both of them can coexist next to each other.

2. Legacy API

Before I jump into implementation, here is a sample Nancy API with two endpoints – products and variants

The goal is to replace products endpoint with ASP.NET Core implementation while variants endpoint should still be served by Nancy

3. Combining Nancy with ASP.NET Core

The solution is based on branching the pipeline feature which is available starting from ASP.NET Core 2.1. Long story short – it is possible to configure different pipelines for different route paths thanks to

method. Having that in mind we can Map products path to run through ASP.NET Core pipeline whereas the rest would go through Nancy.

At this point we are almost there, however running request through Map pipeline will remove the path prefix, meaning that our controller would be accessible under / path instead of products. In order to bypass this limitation we have to restore original prefix with RewriteMiddleware. Once we put it all together, now we are able to replace multiple Nancy endpoints with ASP.NET Core ones using following piece of code


Source code for this post can be found here

Running ASP.NET Core together with Nancy

Introduce substitute refactoring comes to NSubstitute.Analyzers

I am glad to announce the newest version of NSubstitute.Analyzers comes with “introduce substitute” refactoring, which allows you to automatically create substitutes for constructor arguments as fields or local variables. As an image is worth a thousand words here is a quick demo of C# version

and VisualBasic one

Introduce substitute refactoring comes to NSubstitute.Analyzers

.NET Core – missing currency symbol in docker alpine image

During the process of moving a Scala-based API to .NET Core, we encountered an interesting localization issue when running our code in a docker container based on an alpine image. The code itself was doing a currency formatting based on some culture. It looked more or less as below

We also had some integration tests for that piece of logic

The tests were run during a CI build in a container with an image defined as below

At this point, we were sure that everything works fine, as the tests were green and everything was also working correctly on our local machines. However, after deployment to a testing environment, we started getting invalid currency symbols

As you can see the response contains ¤ (invariant currency symbol) instead of expected €. It took us some time to figure this out but finally, it turned out that aspnet:2.1.11-alpine image(the one we used for running the application) contrary to the SDK image(used for building and running tests) is missing icu-libs package. In default conditions, the application should throw the following exception during the startup

However, aspnet:2.1.11-alpine image has the DOTNET_SYSTEM_GLOBALIZATION_INVARIANT flag set to true by default, so the missing package was not validated during a startup. After all, in order to fix the issue, we had to install the icu-libs package and also set the DOTNET_SYSTEM_GLOBALIZATION_INVARIANT back to false. This was done by these two lines in Dockerfile

Once the lines were added the application started working as expected

Source code for this post can be found here

.NET Core – missing currency symbol in docker alpine image

MongoDB.Driver – class-based server side projection

1. Introduction

When working with NoSQL databases, your documents might be quite heavy and in some cases, you would like to get only a slice of original data. For instance, let’s assume we have an Account document which among other things contains a list of transactions

As there might be hundreds of transaction in the account object, you might want to occasionally work on a subset of original data, say for instance AccountSlim object to improve the performance

2.Exploring existing options

MongoDB.Driver has a couple of ways of defining projections so as you can operate on a slimmer object instead of a default one. For instance

Unfortunately, those are a client-side projection. This means that the entire object is returned from the database and we just serialized it to a different class. You can check it on your own by examining request and result commands sent to Mongo

In both cases requested query doesn’t contain “projection” section, so entire document is returned

Of course, there is a possibility to manually create a server-side projection, for instance

or with a strongly typed version

However, in my opinion, this is error-prone and it would be better to generate server-side projection automatically based on properties in a slim object. As I didn’t find anything like that in the official driver, here is my approach for handling this

3. Class-based server-side projection

In order to create a custom projection, all we have to do is to extend ProjectionDefinition<TSource, TResult> class and provide a RenderedProjectionDefinition with all properties which are in both “heavy” and “slim” object

As you can see we use MongoDB.Driver build-in projections to render our custom projection consisting of necessary properties. Note, that as we are using StringFieldDefinition instead of defining Bson document manually, the projection will take into account potential class mappings or attribute mappings applied to your object

Having the projection ready we can make it a bit easier to use by introducing some extensions. The first one looks as follows

which allows you to use this projection similarly like others – so by accessing Builders class

The second method will extend IFindFluent<TDocument, TProjection> interface

and thanks to it we will end up with an even better syntax

One way or another we will end up with proper projection definition which will result in a smaller document returned from the database

Source code for this post can be found here

MongoDB.Driver – class-based server side projection

Performance improvements in NSubstitute.Analyzers 1.0.11

1. Introduction

I am glad to announce that the latest release of NSubstitute.Analyzers (apart from some bugfixes) brings a lot of performance and memory usage improvements for most of the analyzers. The benchmark results shown below should give you enough information about the speed and memory consumption of the newest version of the library. If you are interested in actual changes behind these results please take a look at this pull request.

2. Benchmark comparision of NSubstitute.Analyzers.CSharp

AnalyzerMean (us)Error (us)StdDev (us)Gen 0Gen 1Allocated (KB)
CallInfoAnalyzer1,897.05.6465.2814136.718811.7188424.54
ConflictingArgumentAssignmentsAnalyzer554.21.0180.952433.20311.9531103.47
NonSubstitutableMemberAnalyzer2,466.99.3178.2596179.687515.6250560.33
NonSubstitutableMemberReceivedAnalyzer644.42.2801.903931.25006.835996.27
NonSubstitutableMemberWhenAnalyzer995.92.3201.937037.10947.8125116.74
ReEntrantSetupAnalyzer57,979.0196.824174.47942333.33337175.61
SubstituteAnalyzer1,960.48.1977.266689.843819.5313343.67
UnusedReceivedAnalyzer524.01.6711.563029.29691.953192.45
Benchmark results of NSubstitute.Analyzers.CSharp 1.0.11
AnalyzerMean (us)Error (us)StdDev (us)Gen 0Gen 1Allocated (KB)
CallInfoAnalyzer1,828.85.5994.963123.046911.7188379.78
ConflictingArgumentAssignmentsAnalyzer510.31.9731.84633.20311.9531102.76
NonSubstitutableMemberAnalyzer766.02.7982.33639.06258.7891122.27
NonSubstitutableMemberReceivedAnalyzer600.63.4113.19127.34385.859485.82
NonSubstitutableMemberWhenAnalyzer866.03.1442.94134.17979.7656107.87
ReEntrantSetupAnalyzer7,442.034.06731.866281.250015.6250870.18
SubstituteAnalyzer1,870.229.78727.86387.890623.4375346.09
UnusedReceivedAnalyzer482.11.7051.51125.87891.953180.96


3. Benchmark comparision of NSubstitute.Analyzers.VisualBasic

MethodMean (ms)Error (ms)StdDev (ms)Gen 0Gen 1Allocated (KB)
CallInfoAnalyzer3.4590.01370.0121156.250011.7188484.15
ConflictingArgumentAssignmentsAnalyzer1.2790.01030.008621.48441.953169.15
NonSubstitutableMemberAnalyzer1.9750.01080.009035.15637.8125108
NonSubstitutableMemberReceivedAnalyzer1.2870.00700.006513.67191.953147.46
NonSubstitutableMemberWhenAnalyzer1.5890.01030.009225.39065.859482.72
ReEntrantSetupAnalyzer54.1310.23200.19373600.000011139.45
SubstituteAnalyzer3.6150.01680.0149105.468823.4375393.13
UnusedReceivedAnalyzer1.3060.02580.052813.67191.953143.3
Benchmark results of NSubstitute.Analyzers.VisualBasic
1.0.11
AnalyzerMean (ms)Error (ms)StdDev (ms)Gen 0Gen 1Allocated (KB)
CallInfoAnalyzer3.7370.08780.1110152.343811.7188471.79
ConflictingArgumentAssignmentsAnalyzer1.4020.02660.028521.48441.953168.36
NonSubstitutableMemberAnalyzer1.5430.02640.024725.39065.859481
NonSubstitutableMemberReceivedAnalyzer1.2130.00510.004813.67191.953145.43
NonSubstitutableMemberWhenAnalyzer1.4750.00550.005127.34387.812585.25
ReEntrantSetupAnalyzer7.0440.02360.0209265.62507.8125837.14
SubstituteAnalyzer3.3330.09120.1186101.562523.4375377.16
UnusedReceivedAnalyzer1.1020.00670.006211.718840.24
Performance improvements in NSubstitute.Analyzers 1.0.11