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

NSubstitute.Analyzers 1.0.0 released

A while ago I’ve announced a release of the first beta package of NSubstitute.Analyzers. Now, 4 months later I am happy to say that the first stable version is available for download. As usual, analyzers comes with two flavors:

Both of them come together with 19 diagnostics, which will warn you against common misusages of NSubstitue API. Feel free to grab them from NuGet and try them in your project. In case of any issues don’t hestitate to report a bug via GitHub issue tracker.

NSubstitute.Analyzers 1.0.0 released

Announcing NSubstitute.Analyzers (beta)

1. Introduction

I am glad to announce that yesterday, together with NSubstitute team we released first beta version of Roslyn analyzers for NSubstitute – NSubstitute.Analyzers. The analyzers come in two flavors: NSubstitute.Analyzers.CSharp and NSubstitute.Analyzers.VisualBasic. Feel free to grab them from NuGet and try them in your project.

2. Diagnostics

As for today analyzers can detect two most common misusages of NSubstitute:

  • non-virtual call setup
  • Received used without following method call

Feels free to suggest additional diagnostic you would like to have in the package.

Announcing NSubstitute.Analyzers (beta)

 ASP.NET Web API 2 – missing swagger query parameters

Last week I’ve encountered an interesting bug in swagger documentation of our API. For some reason couple of Get operations were missing some of the query parameters. The issue itself was only visible in a couple of controllers, simplified version of one of them is shown below

As you can see the controller has a Get method which takes as an argument following class

If you run swagger for Get operation you will see that only two parameters are listed in a parameter list

After some digging I found the actual problem were basically [DataMember] and [DataContract] attributes randomly scattered in the models used in Get methods arguments. Even though these attributes are not used for model binding from the query string, swagger takes them into account either way. It happens basically because swagger under the hood uses JsonObjectContract (even for [FromUri] request classes) and by default it respects [DataContract] attribute – more info can be found here. Removing redundant [DataContract] and [DataMember] attributes from respective models solved the issue.

PS. This particular corner case is not an issue for ASP.NET Core swagger implementation.

 ASP.NET Web API 2 – missing swagger query parameters