Friday, September 28, 2018

NHibernate.MappingException: No persister for: Sample.Product

After creating a new mapping file using the code mapping feature in NHibernate, it didn’t work when I tried to persist an instance of the object. Instead I got the following error message:

NHibernate.MappingException: No persister for: Sample.Product

Here is the mapping file I’m using:

Do you notice what’s wrong? ….

I forgot to make my mapping class public:

public class ProductMapping: ClassMapping<Product>

Thursday, September 27, 2018

Visual Studio 2017–SQL Server Data Tools- Custom assemblies could not be loaded

On one of my SQL Server Reporting Services reports, I had to use some custom logic. Instead of embedding the code directly into the report, I decided to create a separate assembly which makes it easier to test and debug this code.

After importing the assembly in my Visual Studio 2017 Reporting Services project, I couldn’t load the Report Designer preview window anymore. Instead I got the following error message:

An error occured during local report processing.

The definition of the report ‘/samplereport’ is invalid.

Error while loading code module: ‘Sample.Barcode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’. Details: Could not load file or assembly ‘Sample.Barcode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

To fix this I had to copy the DLL to the following location:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\SSRS
Remark: Note that this DLL is loaded only once in Visual Studio. If you change something to this DLL, you have to close and open Visual Studio again.

Wednesday, September 26, 2018

Windows Identity Foundation - Using a machine key to encrypt/decrypt your session token

By default WIF uses a built-in SessionSecurityTokenHandler to serialize the session token to and from the cookie. Behind the scenes this tokenhandler uses the Data Protection API (DPAPI) to protect the cookie material. DPAPI uses a key that is specific to the computer on which it is running in its protection algorithms. For this reason, the default session token handler is not usable in Web farm scenarios because, in such scenarios, tokens written on one computer may need to be read on another computer.

As a solution you can switch the default SessionSecurityTokenHandler by a machine key based alternative:

After doing that, there is one extra step required. The default IIS configuration autogenerates a machine key per application pool.

image

To generate a specific key and copy it to all server instances on your web farm, remove the checkboxes next to the ‘Automatically generate at runtime’ option and choose Generate Keys from the action menu on the right.

image

Now you can copy and paste the generated keys to the other servers (or automatically let them replicate if you configured the IIS Web Farm feature).

Tuesday, September 25, 2018

F# 4.5–The ‘match!’ keyword

F# 4.5 introduces the match! keyword which allows you to inline a call to another computation expression and pattern match on its result. Let’s have an example.

Here is the code I had to write before F# 4.5:

Notice that I have to bind the result of callServiceAsync before I can pattern match on it. Now let’s see how we can simplify this using the ‘match!’ keyword:

When calling a computation expression with match!, it will realize the result of the call like let!. This is often used when calling a computation expression where the result is an optional.

Monday, September 24, 2018

Service Fabric Troubleshooting guides

“With great power comes great responsibility.” Although this quote had nothing to do with Service Fabric, it could be applicable there as well. Service Fabric brings the power of PaaS close to you, unfortunately it does come with its own set of problems and difficulties.

And once you get stuck there isn’t much information out there to help you find a solution (ask me how I know). One of the resources that helped me a lot were the Service Fabric Troubleshooting guides, these are the same guides used by the Azure Customer Support Services and Product Group Site Reliability Engineers. It’s a combination of guides, troubleshooting tips and scripts that can help you find the root cause of your Service Fabric related problems.

image

A must have for every Service Fabric administrator(and developer).

Friday, September 21, 2018

ASP.NET Web API–Batch requests

Did you know that ASP.NET Web API allows you to batch requests? Batching packs several API requests together and send them in one HTTP request. The responses will be grouped in one single HTTP response as well.

There isn’t much you need to do to configure this on the server, just add a specific route to your route table with batching enabled:

The important things to notice are the following:

  • The DefaultHttpBatchHandler executes each request sequentially, but in case you don’t have any dependency between requests, you can set a property to make execution non-sequential.
  • The MapHttpBatchRoute route template can contain parameters. So, in case you create your own batch handler, you can pass in parameters to it.

If you don’t need the sequential behavior you can create your own HttpBatchHandler and override the execution order property:

That’s all that is required to enable batching on the server. Let’s now see how to use this on the client:

This is a little known feature but can have a big impact on the performance of your web api. Use it wisely Smile

Thursday, September 20, 2018

Error when building Reporting Services project

After opening an ‘old’ Reporting Services project, we got the following exception message when we tried to build the report:

Custom parameter layout was detected in the report. SQL Server 2014 Reporting Services and earlier do not support custom parameter layout. Either reduce the error level to a value less than 3 or change the TargetServerVersion to a version that supports custom parameter layout.

To fix this error, you have to go to the Report properties:

  • Right click on your Reporting Services Project, and choose Properties.

image

  • Change the TargetServerVersion to SQL Server 2016 or later

image

Wednesday, September 19, 2018

Postman–Generate code from your requests

One nice feature I discovered recently in Postman is the ability to generate code from your API requests.

Here are the steps:

  • Open Postman

image

  • Select a collection and click on a specific request

image

  • Click on Code on the right. The generate code snippets window is loaded.

image

  • Choose the language you want to use and click Copy to clipboard
    • If you are using C#, the code snippets are generated using the RestSharp library

image

    Tuesday, September 18, 2018

    Postman–Import OpenAPI specification for your API

    Postman makes it easy to create a collection of requests based on your OpenAPI specification. So if you are using Swagger (through Swashbuckle in .NET) importing your API specification is just a few steps:

    • Open Postman

    image

    • Click on the 'Import' button in the top left corner. The import window is loaded.

    image

    • Select the import from link option and paste the url of your swagger documentation file. Click on Import.

    image

    • A new collection is generated and available:

    image

    Monday, September 17, 2018

    The Implicit bias

    Everyone’s opinion is influenced by education, media, earlier experiences, … Do you want to know how biased you are?

    Try some of the tests on Project Implicit:

    image

    The Implicit Association Test (IAT)may be especially interesting because it can reveal that you have an implicit attitude that you did not know about.

    More information on https://www.projectimplicit.net/index.html.

    Friday, September 14, 2018

    Reduce your Serilog log files using Serilog.Formatting.Compact

    All our log data is centralized using a combination of Serilog and Seq.

    Last week we got a warning that our disks were filling up. We first cleaned up some old log data but than started to look at other ways to decrease our log size.

    One of the solutions we found was Serilog.Formatting.Compact.

    From the documentation:

    A simple, compact JSON-based event format for Serilog. CompactJsonFormatter significantly reduces the byte count of small log events when compared with Serilog's default JsonFormatter, while remaining human-readable. It achieves this through shorter built-in property names, a leaner format, and by excluding redundant information.

    Seq starting from version 3.3 accepts this more compact format. To use this, configure the sink with compact: true:

        .WriteTo.Seq("http://localhost:5341", compact: true)

    Thursday, September 13, 2018

    Angular–Run code on startup

    Before our Angular application we first have to load some user profile data before the application can be used. First we used some observable magic to do this in our AppModule but there is a much better way; hook into the Angular initialization process using the APP_INITIALIZER token.

    Here is a simplified example on how to use it:

    Some things to notice:

    • You can specify multiple APP_INITIALIZER injection tokens.
    • The factory function should return a function that returns a promise

    More information: https://hackernoon.com/hook-into-angular-initialization-process-add41a6b7e

    Wednesday, September 12, 2018

    Bye bye TFS/VSTS, welcome Azure DevOps (Server)!

    2 days ago Microsoft announced Azure DevOps, the new incarnation of VSTS and TFS. Instead of one big mothership, we’ll get 5 smaller vessels that integrate perfectly with each other(of course!) but also with other tools and products.

    Here are the 5 building blocks:

    Azure PipelinesAzure Pipelines

    CI/CD that works with any language, platform, and cloud. Connect to GitHub or any Git repository and deploy continuously. Learn More >

    Azure BoardsAzure Boards

    Powerful work tracking with Kanban boards, backlogs, team dashboards, and custom reporting. Learn more >

    Azure ArtifactsAzure Artifacts

    Maven, npm, and NuGet package feeds from public and private sources. Learn more >

    Azure ReposAzure Repos

    Unlimited cloud-hosted private Git repos for your project. Collaborative pull requests, advanced file management, and more. Learn more >

    Azure Test PlansAzure Test Plans

    All in one planned and exploratory testing solution. Learn more >

    More information about the Azure DevOps launch can be found on Channel 9; https://channel9.msdn.com/Events/Microsoft-Azure/Azure-DevOps-Launch-2018.

    Tuesday, September 11, 2018

    MassTransit–Change Exchange naming strategy

    When you publish a message through MassTransit to RabbitMQ, a default naming strategy is used to create a corresponding exchange. The default naming convention is the fully qualified name of the message class, so if you have a class named HelloWorldMessage in a namespace MyCompany.Messages.V1, you’ll end up with an exchange named MyCompany.Messages.V1:HelloWorldMessage.

    This is ok if you are running RabbitMQ locally(through Docker for example), but it gets quite annoying if you are publishing to a shared infrastructure during development. The problem is that you start receiving messages from other developers which makes debugging a lot more difficult.

    To solve this problem I created a custom EntityNameFormatter that allows you to specify an extra environment setting that can be set to for example to a specific username. Doing this in MassTransit 5 is not that hard as you can set this for the whole MessageTopology(something that was not easily done in previous versions).

    Here is the required code:

    • First, we have to create a custom formatter by implementing the IEntityFormatter interface(note that I’m passing in the original formatter):
    • Second, we have to apply this formatter. As I want to do this for all messages, I specify it on the MessageTopology setting:

    Now we can specify a different name in our configuration and only receive the messages that we want.

    Remark: You have to apply this code both on the send and receive side of your application

    Monday, September 10, 2018

    Impress your colleagues with your knowledge about... RecyclableMemoryStream.

    Sometimes when working with C# you discover some hidden gems. Some of them very useful, other ones a little bit harder to find a good way to benefit from their functionality. One of those hidden gems that I discovered some days ago is the RecyclableMemoryStream class. For this one I’m cheating a little bit as it is not part of the .NET Framework directly but released as a separate NuGet package by the Bing team.

    What is it?

    Microsoft.IO.RecyclableMemoryStream is a drop-in MemoryStream replacement with superior behavior for performance-critical systems. In particular it is optimized to do the following:

    • Eliminate Large Object Heap allocations by using pooled buffers
    • Incur far fewer gen 2 GCs, and spend far less time paused due to GC
    • Avoid memory leaks by having a bounded pool size
    • Avoid memory fragmentation
    • Provide excellent debuggability
    • Provide metrics for performance tracking

    The code looks kinda boring as it uses the same semantics as the built-in MemoryStream class:

    More information: http://www.philosophicalgeek.com/2015/02/06/announcing-microsoft-io-recycablememorystream/

    Friday, September 7, 2018

    Enabling dynamic compression in IIS

    A few years ago I blogged about enabling gzip compression for ASP.NET MVC applications; https://bartwullems.blogspot.com/2013/03/enable-dynamic-compression-for-aspnet.html.  I ended my blogpost with the following remark:

    ‘Maybe it should work too if you add this to your web.config, but I couldn’t get this working’

    This week I had to configure dynamic compression again, so I decided to search for a solution(again).

    When scrolling through the applicationHost.config file I noticed the following section:

    <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />

    Notice that there are 2 attributes defined on the httpCompression section; overrideModeDefault and allowDefinition.

    From the documentation:

    The overrideModeDefault attribute is an optional attribute that defines the locked state of a section. Its available values are either Allow or Deny. The default value is "Allow". All IIS sections that are related to any performance, security or critical aspect of the server are locked with this attribute set to "Deny". If the overrideModeDefault attribute is set to "Deny", then any configuration files at a lower level (i.e. web.config files) that set a value for a property for the specific configuration section are not able to take effect and override the global values. This incurs in a lock violation and an error occurs.

    The allowDefinition attribute is another optional attribute that defines the level of the hierarchy in which the section can be defined and properties can be set. If its value is MachineOnly, then the section can be set only in applicationHost.config or machine.config. If its value is MachineToRootWeb, then the section can be set either in the MachineOnly files or also in the root web.config. If its value is MachineToApplication, then the section can be either set in all the previous three files or also in web.config files in the application root folder. And lastly, if its value is Everywhere (which is the default) it can be set in any configuration file, whether the ones that affect configuration globally or in web.config files that apply to a given site, application or virtual directory.

    This explains why setting this configuration in the web.config file didn’t work. This specific section is locked at IIS level.

    If you still want to override it in your web.config, you can alter this section to:

    <section name="httpCompression" allowDefinition="Everywhere" overrideModeDefault="Allow" />

    Thursday, September 6, 2018

    Reset your keyboard bindings after disabling Resharper

    As Visual Studio was getting really slow, I decided to disable Resharper (again). If I really wanted the power of Resharper, I could always open up Rider and continue coding there.

    After disabling Resharper I noticed that some of my keyboard shortcuts no longer worked. The Resharper functionality was gone but it was not replaced by the Visual Studio keyboard binding.

    Time to fix it:

    • Open Visual Studio and type ‘keyboard’ in the Quick search

    image

    • Click on Environment –> Keyboard to go to the Visual Studio options

    image

    • Select a Keyboard mapping scheme from the drop down menu and click Reset to activate it.

    image

    Wednesday, September 5, 2018

    ValueTuple magic for Equality checks

    Until we have record types in C# we’ll have to use classes or structs for our Value objects. What makes this annoying is that we have to override the Equals and GetHashCode methods to get correct equality checks.

    Until I stumbled over the following blog post by James Montemagno: https://montemagno.com/optimizing-c-struct-equality-with-iequatable/. In this post he explains how we can use ValueTuples in combination with the new tuple syntax to get cleaner Equals and GetHashCode checks.

    Here is the code before:

    Here is the code after introducing ValueTuples:

    Tuesday, September 4, 2018

    SonarQube–Configure coverage exclusions

    Code reviews are one of my daily activities. To help me streamline the process, I like to use the help of static code analysis tools like NDepend and SonarQube.

    While looking through the SonarQube logs for a specific project I noticed a large list of issues in a set of Javascript files. These Javascript files were external libraries (like jQuery) that were imported into the project and not created by the dev team. Fixing these issues would only be possible by sending a pull request to the library maintainers.

    To stop the pollution of our SonarQube logs, I decided to exclude these files from the log analysis.

    Here are the steps:

    • Browse to your SonarQube dashboard.
    • Login as an administrator.

    image

    • After being logged in, you can go to the Administration tab on the project level.

    image

    • Select Analysis Scope from the Category list.

    image

    • Go to the Files tab and add one or more Source File Exclusions.
      • In our case we want to exclude the Scripts folder in our web project, so we add Scripts/** to the Source File Exclusions
      • IMPORTANT: Source File Exclusions are case sensitive. First time I entered scripts/** which had no effect.

    image

    • Source File Exclusions are executed on the project level and applied for each csproj file individually:

    2018-09-03T06:55:30.4158415Z INFO: -------------  Scan MTIL.Web
    2018-09-03T06:55:30.4158415Z INFO: Base dir: D:\b\4\agent\_work\35\s\MTIL.Web
    2018-09-03T06:55:30.4168180Z INFO: Working dir: D:\b\4\agent\_work\35\.sonarqube\out\.sonar\MTIL_MTIL_C301B249-2F5F-4264-B23F-FC169C8E7397
    2018-09-03T06:55:30.4207240Z INFO: Source encoding: UTF-8, default locale: en_US
    2018-09-03T06:55:30.4207240Z INFO: Index files
    2018-09-03T06:55:30.4207240Z INFO: Excluded sources:
    2018-09-03T06:55:30.4207240Z INFO:   Scripts/**
    2018-09-03T06:55:30.4431835Z INFO: Analyzer working directory contains 5 .pb file(s)
    2018-09-03T06:55:30.5886820Z INFO: 40 files indexed
    2018-09-03T06:55:30.5886820Z INFO: 14 files ignored because of inclusion/exclusion patterns
    2018-09-03T06:55:30.5964940Z INFO: Quality profile for cs: Sonar way
    2018-09-03T06:55:30.6238360Z INFO: Sensor Lines Sensor
    2018-09-03T06:55:30.6248125Z INFO: Sensor Lines Sensor (done) | time=1ms
    2018-09-03T06:55:30.6248125Z INFO: Sensor SCM Sensor
    2018-09-03T06:55:30.6736375Z INFO: SCM provider for this project is: git
    2018-09-03T06:55:30.6746140Z INFO: 1 files to be analyzed
    2018-09-03T06:55:31.7077510Z WARNING: WARN: Missing blame information for the following files:
    2018-09-03T06:55:31.7116570Z INFO: 0/1 files analyzed
    2018-09-03T06:55:31.7184925Z INFO: Sensor SCM Sensor (done) | time=1034ms
    2018-09-03T06:55:31.7184925Z INFO: Sensor C#
    2018-09-03T06:55:31.7194690Z INFO: Importing analysis results from D:\b\4\agent\_work\35\.sonarqube\out\6\output-cs
    2018-09-03T06:55:31.7194690Z WARNING: WARN:   * D:/b/4/agent/_work/35/s/MTIL.Web/ErrorHandler/AiHandleErrorAttribute.cs
    2018-09-03T06:55:31.7194690Z WARNING: WARN: This may lead to missing/broken features in SonarQube
    2018-09-03T06:55:31.7809885Z INFO: Importing Roslyn report
    2018-09-03T06:55:31.8151660Z INFO: Sensor C# (done) | time=155ms
    2018-09-03T06:55:31.8151660Z INFO: Sensor C# Unit Tests Coverage Report Import
    2018-09-03T06:55:31.8151660Z INFO: Sensor C# Unit Tests Coverage Report Import (done) | time=0ms
    2018-09-03T06:55:31.8161425Z INFO: Sensor C# Integration Tests Coverage Report Import
    2018-09-03T06:55:31.8161425Z INFO: Sensor C# Integration Tests Coverage Report Import (done) | time=0ms
    2018-09-03T06:55:31.8161425Z INFO: Sensor C# Unit Test Results Import
    2018-09-03T06:55:31.8161425Z INFO: Sensor C# Unit Test Results Import (done) | time=0ms
    2018-09-03T06:55:31.8171190Z INFO: Sensor Zero Coverage Sensor
    2018-09-03T06:55:31.8415315Z INFO: Sensor Zero Coverage Sensor (done) | time=14ms
    2018-09-03T06:55:31.8415315Z INFO: Sensor Code Colorizer Sensor
    2018-09-03T06:55:31.8415315Z INFO: Sensor Code Colorizer Sensor (done) | time=2ms
    2018-09-03T06:55:31.8425080Z INFO: Sensor CPD Block Indexer
    2018-09-03T06:55:31.8425080Z INFO: DefaultCpdBlockIndexer is used for cs
    2018-09-03T06:55:31.8718030Z INFO: Sensor CPD Block Indexer (done) | time=1ms

    Monday, September 3, 2018

    Marten–Nullreference exception after updating Npgsql

    After updating Npgsql, Marten started to throw exceptions:

    [NullReferenceException: Object reference not set to an instance of an object.]
       Marten.Util.TypeMappings.ToDbType(Type type) +93
       Marten.Schema.DuplicatedField..ctor(EnumStorage enumStorage, MemberInfo[] memberPath) +141
       Marten.Schema.DocumentMapping.DuplicateField(MemberInfo[] members, String pgType, String columnName) +195
       Marten.Events.EventQueryMapping.duplicateField(Expression1 property, String columnName) +94
       Marten.Events.EventQueryMapping..ctor(StoreOptions storeOptions) +485
       Marten.Storage.StorageFeatures.PostProcessConfiguration() +364
       Marten.DocumentStore..ctor(StoreOptions options) +259
       Marten.DocumentStore.For(Action1 configure) +60
    A quick search through the issues list on Github, brought me to the following page: https://github.com/JasperFx/marten/issues/1044
    Good news, the issue is already resolved and closed in Marten v3(alpha 2 version is available).