API Versioning and Swagger

28 June 2021

The Problem

API Versioning was added to a Microsoft C# Web API project .NET Core.

[ApiVersion("2.1")]
public class MyController: ApiController
{
}

The Swagger page for the API then did not list the API endpoints

The Solution

Simply add the [ApiController] attribute to the class

[ApiVersion("2.1")]
[ApiController]
public class MyController: ApiController
{
}

 

 

Android Srongswan Configuration I

14 March 2021

The Problem

I was trying to configure a Strongswan IPSec client on my Android phone to tunnel to StrongsWan/FreesWan on a linux server. It almnost worked but I got an error:

No trusted public RSA key found for XXXX

Where XXX was my X.509 certficate details.

Strange – as my client and server and CA certificates were all self generated and worked with Windows IPSec client talking to the same IPSec server.

The Solution

I searched and found this article

What it was suggesting was that the Android Strongswan client:

that the configured server address/hostname is contained
in the certificate as subjectAltName. 

If that's not the case you have to configure the server 
identity manually in the VPN profile, either to a 
subjectAltName that's actually contained in the certificate 
(if the server finds a config with that identity) 
or to the full subject DN of the server certificate

What does this mean in reality? (NB Thanks to the person who answered the question)

FIrst, get the Certifcate details via

 openssl x509 -noout -in certificate.pem -subject

The result will be something of the form

subject=C = GB, ST = YY, L = XX, O = ABCD Certificates, OU = ABCD CA, CN = ZZZ, emailAddress = info@dumphuc.com

edit this and remove spaces to

C=GB,ST=YY,L=XX,O=ABCD Certificates,OU=ABCDCA,CN=ZZZ,emailAddress=info@dumphuc.com

On the Android phone enter this into the “Server Identity” line of the VPN profile

 

Configure the other VPN settings in the Android client and, voila, the VPN will work

.Net Core WebAPI Request and Response Logging

6 July 2020

The Problem

In .NET 4.x it was straightforward to read the request body of an incoming HTTP request, log the information and also log the outgoing response back to the caller. I thought it would be just as easy in .Net Core, how wrong a I was as Microsoft do their utmost to hide the Request body from you.

The Solution

Accessing the Request and Response bodies must be done in HTTP Middleware, and, after reading much on StackOverflow I came up with the following solution (and my thanks to all the original authors and people who helped me). I cannot take credit for this code, I just adapted it from ideas on StackOverflow

Remember 

For .Net Core 2.1  use  context.HttpContext.Request.EnableRewind();
For .Net Core 3.1  context.HttpContext.Request.EnableBuffering();

 

/// <summary>
/// Want to be able to read the Request.Body to get the incoming JSON
/// In .net 4 this was more or less simple. In Core it has changed
/// Need to be able to "rewind" of Request.Body - have to do that
/// Thanks to
/// https://stackoverflow.com/questions/40494913/how-to-read-request-body-in-a-asp-net-core-webapi-controller
/// in request pipeline middleware
/// 
/// For ASP.NET 2.1
/// context.HttpContext.Request.EnableRewind();
/// For ASP.NET 3.1
/// context.HttpContext.Request.EnableBuffering();
///
/// See also https://stackoverflow.com/questions/43403941/how-to-read-asp-net-core-response-body/43404745
/// </summary>
public class LogRequestResponseMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;

private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
private const int ReadChunkBufferLength = 4096;

private bool LogRequest;
private bool logResponse;

public LogRequestResponseMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, bool requestLogging, bool responseLogging)
{
//--------------------------------------------------------------------
// Config |
//--------------------------------------------------------------------

this.LogRequest = requestLogging;
this.logResponse = responseLogging;

_next = next;
_logger = loggerFactory.CreateLogger<LogRequestResponseMiddleware>();

//--------------------------------------------------------------------
// Create stream to use in place of HttpContext.Response.Body stream |
// which is write-only |
//--------------------------------------------------------------------

_recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
}


public virtual async Task Invoke(HttpContext context)
{
//-----------------------------------------------------
// Request |
//-----------------------------------------------------

if (this.LogRequest)
{
//-------------------------------------------------
// Turn on Buffering/Rewind |
//-------------------------------------------------
context.Request.EnableBuffering();

//-----------------------------------------------------
// Log Request |
//-----------------------------------------------------
await this.LogRequestAsync(context);
}


//-----------------------------------------------------
// Response |
//-----------------------------------------------------
if (this.logResponse)
{
//-----------------------------------------------------
// Log Response |
//-----------------------------------------------------
await this.LogResponseAsync(context);
}
else
{
//-----------------------------------------------------
// Fire next in chain |
//-----------------------------------------------------
await _next.Invoke(context);
}

}


/// <summary>
/// Log the incoming request
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private async Task LogRequestAsync(HttpContext context)
{
using (var requestStream = _recyclableMemoryStreamManager.GetStream())
{
var origPosition = context.Request.Body.Position;
context.Request.Body.Position = 0;
await context.Request.Body.CopyToAsync(requestStream);
context.Request.Body.Position = origPosition;

_logger.LogInformation($"Http Request Information:{Environment.NewLine}" +
$"Schema:{context.Request.Scheme} " +
$"Host: {context.Request.Host} " +
$"Path: {context.Request.Path} " +
$"QueryString: {context.Request.QueryString} " +
$"Request Body: {ReadStreamInChunks(requestStream)}");
}
}


private async Task LogResponseAsync(HttpContext context)
{
//--------------------------------------------------------
// Keep reference to original body |
//--------------------------------------------------------
var originalBody = context.Response.Body;

using (var responseStream = _recyclableMemoryStreamManager.GetStream())
{
//-----------------------------------------------------
// Replace existing with read/write stream |
//-----------------------------------------------------
context.Response.Body = responseStream;

//-----------------------------------------------------
// Fire next in chain |
//-----------------------------------------------------
await _next.Invoke(context);

//-----------------------------------------------------
// Get Result Back |
//-----------------------------------------------------
string resp = ReadStreamInChunks(responseStream);

//------------------------------------------------------
// Write it back to original Response Body |
//------------------------------------------------------

byte[] response = Encoding.ASCII.GetBytes(resp);
await originalBody.WriteAsync(response, 0, response.Length);

//------------------------------------------------------
// Log It |
//------------------------------------------------------

_logger.LogInformation($"Http Response Information:{Environment.NewLine}" +
$"Schema:{context.Request.Scheme} " +
$"Host: {context.Request.Host} " +
$"Path: {context.Request.Path} " +
$"QueryString: {context.Request.QueryString} " +
$"Response Body: {resp}");
}

//-----------------------------------------------------------
// Restore |
//-----------------------------------------------------------
context.Response.Body = originalBody;
}


private static string ReadStreamInChunks(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
string result;
using (var textWriter = new StringWriter())
using (var reader = new StreamReader(stream))
{
var readChunk = new char[ReadChunkBufferLength];
int readChunkLength;
//do while: is useful for the last iteration in case readChunkLength < chunkLength
do
{
readChunkLength = reader.ReadBlock(readChunk, 0, ReadChunkBufferLength);
textWriter.Write(readChunk, 0, readChunkLength);
} while (readChunkLength > 0);

result = textWriter.ToString();
}

return result;
}

}

.NET Core WebAPI CORS

6 July 2020

The Problem

How hard can it be to configure CORS in a .NET Core 3.1 WebAPI? The answer…quite hard.

The Microsoft documentation shows how to configure CORS and it should be straightforward. However, my experience and the exeperience of many others on StackOverflow have shown me that all is far from simple….Although the solution, when finally found was remarkably simple.

Code

CORS can be configured on the ConfigureServices method in Startup.cs with more or less:

services.AddCors(options =>
{
options.AddPolicy(name: "myCORSPolicy",
builder =>
{
    builder.WithOrigins(this.ApiConfiguration.CorsOrigins.ToArray());

     builder.AllowAnyMethod();
     builder.AllowAnyHeader();
     builder.AllowCredentials();
});

});

and in the Configure method

 app.UseCors("myCORSPolicy");

First Problem

So..I’m on an internal development network and I want to allow all origins (i.e. “*”) and AllowCredentials (as I want to use Active Directory).

Wrong!

The combination of .WithOrigins(“*”) and AllowCredentials is expressly forbidden and will generate a run-time exception.

Second Problem – Trailing Slashes

The .WithOrigins takes a “list” of origins i.e. URLs which can access your API. These must not have trailing slashes, e.g.

http://mydomain.com  - works

http://mydomain.com/ - CORS will not allow access from this origin

Microsoft do mention this in their documentation. however, it is far from clear and easily overlooked.

 

 

NHibernate, Sybase, CHAR(10) Columns and Poor Performance

17 April 2020

The Problem

I was working on a C# ODATA WebAPI development that utilised NHibernate (version 4.1.1.4), Sybase, a Sybase ASE driver, .Net 4.7 etc. The tables being queried were from a legacy system and contain many char(1), char(10) and char(20) colums rather than varchar columns.

The performance of the API was not stunning.

Using an ODATA $filter against the API endpoints also did not achieve stunning performance – the response was the order of 10-20 Seconds. But why?

Investigation

NHibernate query logging was enabled so it was possible to see the queries being fired at the database – all looked fine. The queries were extracted from the log files and run directly against the database using TOAD – the queries ran quickly (a few hundred mS). So why was the API so slow?

The API code itself was quite simple – they controller method returned an IQueryable object and the magic of the Microsoft WebAPI infrastructure applied the $filter “WHERE CLAUSE” to the IQueryable and the results were returned as JSON to the caller.

However, many of the columns used in the WHERE clause were char(10) and char(20) columns rather than VARCHAR. In the NHIbernate XML mappings these fields were mapped to strings

 <property column="ExampleCharDBCol" type="String" name="ExampleModelPropertu" not-null="true" length="10"/>

From investiation it was surmised (NB surmised, I have no hard facts) that tomewhere in the NHibernate database communication the WHERE parameters were being transferred as some unicode encoded value which when, on the DB server, the query was “unpacked” and run the various indexes were ignored. Hence the slow querying

The Solution

I must give thans to B Boy and StackOverflow and Todd for pointing me in the right direction.

The answer is to use type=”AnsiString” in the NHibernate XML mappings:

 <property column="ExampleCharDBCol" type="AnsiString" name="ExampleModelPropertu" not-null="true" length="10"/>

Doing this made the queries run a factor 100 faster !!

Epilogue

I don’t think this solution is pertinent to only Sybase, I think it is valid for any database that NHibernate talks to.

VMWare Workstation Doesn’t Work on Windows 10

22 November 2019

The Problem

I recently updated my Windows 10 desktop to the latest “improved” version of Windows 10. I rarely install Windows updates due to my mantra of “if it ain’t broke don’t fix it”, however, I ignored my mantra and opened up a plethora of problems.

One of the big problems is that I run (ran) VMWare Workstation – and version 7 to be specific. This is an old version but my VMs work, I purchased the copy so why upgrade? After the Windows 10 updates VMWare workstation would not run:

VMware Workstation Pro can't run on Windows

It would appear that one (or more) of the Windows updates was prevening VMWare from running.

The Solution

I googled and found many articles recommending uninstalling verious Windows updates – this seems dangerous and can leave you machine unuseable (the voice of experience). I then found this article. Scroll down to

There is no need to replace the entire sysmain.sdb (this action could expose your machine to unpredicatble problems).

You can simply run the Compatibility Administrator Toolkit (https://docs.microsoft.com/it-it/windows-hardware/get-started/adk-install), and disable the entry under the “System Database/Applications/VMware Workstation Pro” path. That’s all.

Here it explains about installing the Compatability Administrator Toolkit (downloadable from Microsoft). Then run the “Compatability Administrator” (this will have been installed as part of the toolkit) by click taskbar search, type “Compatability Administrator”. Within the tool search for “VMWare Workstation” under System Databases-> Application

Right click vmware.exe and click “Disable Entry”. Repeat for VMWare Workstation Pro.

VMWare Workstation should then run

Thanks MicroSoft.

Docker Hello World on Windows 10 Fails

12 September 2019

The Problem

I was attempting to follow the Docker “Getting Started” documentation and tried to run the “Hello World” Example and I got

C:\>docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
docker: no matching manifest for windows/amd64 10.0.16299 in the manifest list entries.
See 'docker run --help'.

What does this mean ?

After much head-scratching and searching (mostly unhelpful posts about using Linux containers or “experimental mode”) I came across this article about docker manifests. It did not make much sense but after some more head-scratching I worked out what the error message meant.

I ran

C:\>docker manifest inspect hello-world:latest

And got (not all the file is listed):

{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 524,
"digest": "sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},

..... text chopped out for this post....

{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1357,
"digest": "sha256:f9fea6a66184b4907c157323de7978942eab1815be146c93a578b01a3a43ad6d",
"platform": {
"architecture": "amd64",
"os": "windows",
"os.version": "10.0.17134.1006"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1046,
"digest": "sha256:2bff08b2d77710d0a0a1608b35ea4dfdc28f698f6da86991c3da755968fa56d6",
"platform": {
"architecture": "amd64",
"os": "windows",
"os.version": "10.0.17763.737"
}
}
]
}

The Answer

All the error means is that the docker image repository (the place on the internet where the docker hello world image is stored) does not have a version built for your version of windows. i.e. it has one for Windows 10.0.17134.1006 and Windows 10.0.17763.737 but not for my version of windows: Windows 10.0.16299

How hard would an error message to that effect be?

NHibernate – Generate All Columns in Update SQL

9 July 2019

The problem

NHibernate maintains internal state of the entities that it has loaded from the database. When saving an entity back to the DB you may want some properties (columns) included in the UPDATE SQL generated although the property value hasn’t changed. Why ? Because the update on a particular column might force a database trigger to run.

Or, to put it another way:

Database triggers are not really compatible with Object Relationship Mappers

 

In my naievety I had assumed that NHibernate would contain a “simple” option to turn on “please generate all columns in UPDATE SQL”, but, alas, no.

The Solution

I consulted StackOverflow – many posts, all leading nowhere. Then I stumbled across one post which spoke of NHibernate IInterceptors. I then consulted the NHibernate documentation – to say the documentation on interceptors is brief and concise does not do it justice.

After much messing about I worked out how interceptors work and got a working implementation so that my UPDATE SQL now includes all the columns that I require.

To make an interceptor work you need

  • Interceptor code (which implements FindDirty method)
  • Plug interceptor into NHibernate Session Create

Interceptor

The “documentation” recommends deriving your interceptor from the NHibernate EmptyInterceptor. The FindDirty method must be overriden in your interceptor, it returns an array [] of ints, the value represent the index of the propertyNames parameter of the FindDirty method – which is a list of the properties of the entity being saved. In my case I returned all items – so that all UPDATE SQL columns were included

Plug Into NHibernate

In your code (in my case, UnitofWork/Repo pattern code) you need to pass the interceptor as a parameter to the SessionFactory.OpenSession() method – this registers the interceptor with NHibernate and it will be called for all Saves

Code Example

Interceptor

public class MyInterceptor : EmptyInterceptor
{
	/// <summary>
	/// Interceptor method
	/// Return array of indices into propertyNames of columns that will be maked
	/// as dirty i.e. SQL will be generated from them
	/// </summary>
	/// <param name="entity"></param>
	/// <param name="id"></param>
	/// <param name="currentState"></param>
	/// <param name="previousState"></param>
	/// <param name="propertyNames"></param>
	/// <param name="types"></param>
	/// <returns></returns>
	public override int[] FindDirty(object entity, object id, object[] currentState,
	object[] previousState, string[] propertyNames, IType[] types)
	{
		List<int> dirty = new List<int>();

		//---------------------------------------------
		// Mark as dirty for all except for ....      |
		//---------------------------------------------
		for (int i = 0; i < propertyNames.Length; i++)
		{
			if (propertyNames[i] != "ColumnIDontwantInSql" && propertyNames[i] != "AnotherColumnIDontwantInSql")
			{
				dirty.Add(i);
			}
		}
		return dirty.ToArray();
	}
}

Wiring Up

CODE SNIPPET FROM UNIT OF WORK



 public UnitOfWork(INHibernateContext context, ISaveInterceptor interceptor)
 {
     this.context = context;
     this.Interceptor = interceptor;

     // See here for why dummy session
     ISession dummy = context.SessionFactory.OpenSession(this.Interceptor);
     this.Session = context.SessionFactory.OpenSession(dummy.Connection, this.Interceptor);
 }

NHibernate – the given key was not present in the dictionary

29 May 2019

The Problem

Using Hibernate on a (.Net/C#) project and came to delete a record from a “collection” and this threw an error

the given key was not present in the dictionary

After much head scratching it was determined that the problem was down to a subtle interaction between NHibernate and a DataBase C# entity class.The class overrode the GetHashCod() method

 

public override int GetHashCode()

{
   ...
}

Originally the underlying database table has a composite key utilising two integer columns, the GetHashCode() method used both of these columns to generate the (unique) hash code. A database modification moved from a composite key to a single key, however, the GetHashCode() method was not updated.

Everything worked fine for read but Delete threw an exception. So what was going on?

Upon investigation it was found that, as part of NHibernate initialisation or lazy-loading, when reading the data the primary key column was populated but the defunct key column was zero, but the GetHashCode() method was called. Later on in the lifecycle all the properties of the Db class were populated and this meant a different hash code was generated (as the defunct column’s value was populated and the GetHashCode() method used this value as well as the primary key value – see earlier). So it looks like that, initially, items were read by NHibernate and added to it’s internal “collection” with hash-codes from partially loaded data, whereas the delete was being made for an item with a hash-code generated from fully populated data – and NHibernate could not find that item in the collection. It looked like NHibernate was using the hash-code to identify individual items.

The solution

Generate a hash-code (GetHashCode() method) using only the primary key.

 

Unit Testing Protected and Private Methods

6 February 2019

The problem

You write a class in true SOLID tradition, and then you want to write the unit tests (or you do true TDD and do the reverse).

All well and good until you want to test some “internal” protected or private methods.

Purists would say you only need to test the external public interface. My response is that this is rubbish, you should test bite-sized pieces of fuctionality, especially if you are writing base classes (and no I don’t want to get into a discussion of programming against interfaces only and not using inheritance)

The Solution

After some googling and manipulation I discovered the Microsoft PrivateObject class (in the Microsoft.VisualStudio.QualityTools.UnitTestFramework assembly). This allows the “wrapping” of the class to be tested and then it’s protected or private methods can be invoked.

I discovered a wrapper to this PrivateObject class which makes unit testing straightforward e.g. if class ClassToTest has a protected method with signature ProctedMethod(int,string) then it can be invoked for testing as:

var x = new ClasstoTest();
dynamic target = new DynamicAccessor(x, typeof(ClassToTest));
target.ProtectedMethod(1,"abcd");

 

This has worked fine and dandy until trying to test a class with generic methods. I found some information on StackOverflow (this article, and this one)  I modified the class to use reflection and it works for most generic methods (it’s still not perfect).

The Code

 

  /// <summary>
    /// DynamicAccessor
    ///
    /// Class to be utilised in Unit Tests to allow protected and private
    /// members and properties to be called from external tests
    ///
    /// Not perfect and based on someone else's hard word along with
    /// a bit of hot-rod magic
    /// 
    /// </summary>
    public class DynamicAccessor : DynamicObject
    {
        public PrivateObject privateObject;
        private object parentObject;

        public DynamicAccessor(object d)
        {
            this.privateObject = new PrivateObject(d);
        }

        public DynamicAccessor(object d, Type t)
        {
            this.parentObject = d;
            this.privateObject = new PrivateObject(d, new PrivateType(t));
        }


        /// <summary>
        /// The try invoke member.
        ///
        /// Doesn't work as is with Generic<T> methods
        ///
        /// so use a combination of
        /// https://stackoverflow.com/questions/5492373/get-generic-type-of-call-to-method-in-dynamic-object
        /// to get type params and
        ///  https://stackoverflow.com/questions/42006662/testing-private-static-generic-methods-in-c-sharp
        /// to invoke
        ///
        /// Hot Rod Programming (DJ)
        /// 
        /// </summary>
        /// <param name="binder">
        /// The binder.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        /// <param name="result">
        /// The result.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            try
            {
                // https://stackoverflow.com/questions/5492373/get-generic-type-of-call-to-method-in-dynamic-object
                var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
                var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList<Type>);

                //------------------------------------
                // if typeargs then a generic method |
                //------------------------------------
                if (typeArgs.Any())
                {
                    //----------------------------------------------------------------------------------------------------
                    // Use reflection to get to method                                                                   |
                    // https://stackoverflow.com/questions/42006662/testing-private-static-generic-methods-in-c-sharp    |
                    //----------------------------------------------------------------------------------------------------


                    MethodInfo fooMethod = this.parentObject.GetType().GetMethod(binder.Name, BindingFlags.NonPublic | BindingFlags.Instance);
                    if (fooMethod == null)
                    {
                        result = null;
                        return false;
                    }
                    //-------------------------------------------
                    // Turn Into Generic and invoke with params |
                    //-------------------------------------------
                    MethodInfo genericFooMethod = fooMethod.MakeGenericMethod(typeArgs.ToArray());
                    result = genericFooMethod.Invoke(this.parentObject, args);
                }
                else
                {
                    //-----------------------------
                    // Non Generic so just invoke |
                    //-----------------------------
                    result = privateObject.Invoke(binder.Name, args);
                }

                return true;
            }
            catch (MissingMethodException)
            {
                result = null;
                return false;
            }
        }

        public void SetProperty(string propName, object o)
        {
            this.privateObject.SetProperty(propName, o);
        }
    }