The ChannelAdam Dispatch Proxies Library

Overview

An open source, .NET Standard 1.3 library implementation of disposable and retry-enabled dispatch proxies.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.DispatchProxies NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.DispatchProxies

Usage

An example of the RetryEnabledObjectDisposableDispatchProxy and a custom SimpleRetryPolicyFunction class:

1int retriesCount = 3;
2
3var myService = new MyService();
4
5var retryEnabledProxyOfMyService = RetryEnabledObjectDisposableDispatchProxy.Create<IMyService>(
6    myService,
7    new SimpleRetryPolicyFunction(this.retriesCount));

See the Behaviour Specifications for more examples, such as the TestObjectDispatchProxy.

Reference

The ChannelAdam Disposing Library

Overview

Have you ever thought that the .NET disposable pattern was complicated to implement or understand? Inherit from one of these classes and it’s easy!

This is open source .NET Standard 1.3 library with a correct implementation of the dispose/finalize pattern that is easily used and extended.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.Disposing NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Disposing

Usage

Simply inherit from Disposable or DisposableWithDestructor and override DisposeManagedResources() and/or DisposeUnmanagedResources().

Reference

The ChannelAdam Logging Library

Overview

An open source, .NET Standard 1.3 library that provides a very simple logging interface.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.Logging NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Logging

Usage

Implement the ISimpleLogger interface.

Reference

A very simple interface for logging or writing out to the console.

The ChannelAdam Primitive Extensions Library

Overview

An open source, .NET Standard 1.3 library with helpful extensions for primitive types - such as formatting strings with named placeholders.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.PrimitiveExtensions NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.PrimitiveExtensions

Usage

 1const string format = "Hello {Name} has a {@Cat}";
 2format.FormatNamedPlaceholdersWith("Adam", "burmese");
 3// "Hello Adam has a burmese";
 4
 5// How are nested curly brackets handled?
 6// Curly brackets must be escaped by doubling each curly bracket - otherwise there is a FormatException.
 7// Everything within the curly bracket, to the left of the innermost curly bracket pair, is removed.
 8// Everything to the right of the innermost curly bracket pair is kept.
 9const string format = "Hello {Name}, a {@Cat} ate my {{{{{ {this {is { removed {__{Homework}__}} fff }} ddd}} a}} }}}}"; 
10format.FormatNamedPlaceholdersWith("Adam", "burmese", "essay");
11// "Hello Adam, a burmese ate my essay__} fff } ddd} a} }}";

Reference

StringExtensions.cs

  • public static string FormatNamedPlaceholdersWith(this string format, params object[] args)
  • public static string FormatWith(this string format, params object[] args)

The ChannelAdam Reflection Library

Overview

An open source, .NET Standard 2.0 library that provides helpers for using reflection.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.Reflection NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Reflection

Usage

1
2var myString = EmbeddedResource.GetAsString(assembly, "My.Namespace.Folder.EmbeddedResource.txt");
3

Reference

Easily retreive embedded resources from their manifest resource stream.

  • Embedded Resource helper
    • public static Stream GetAsStream(Assembly assembly, string resourceName)
    • public static string GetAsString(Assembly assembly, string resourceName)
    • public static XElement GetXmlResourceAsXElement(Assembly assembly, string resourceName)
    • public static T DeserialiseFromXmlResource<T>(Assembly assembly, string xmlResourceName)
    • public static T DeserialiseFromXmlResource<T>(Assembly assembly, string xmlResourceName, XmlRootAttribute xmlRootAttribute)
    • public static T DeserialiseFromXmlResource<T>(Assembly assembly, string xmlResourceName, XmlAttributeOverrides xmlAttributeOverrides)

The ChannelAdam Test Framework Moq Library

Overview

This is an open source, .NET Standard 1.3 library that provides helpers for using Moq on top of the ChannelAdam Test Framework Library.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.TestFramework.Moq NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.TestFramework.Moq

Usage

This library is intended for use by other Test Framework implementation libraries that are then to be used by application developers, such as:

Reference

MoqTestFixture inherits from the TestEasy base class for tests and also provides a MyMockRepositoy property to access the Moq MockRepository.

The default constructor automatically creates a Moq “loose” MockRepository, but that can be specified in an overload of the constructor.

Please see the ChannelAdam Test Framework Library documentation for more information about TestEasy.

The ChannelAdam Test Framework MSTest Library

Overview

This is an open source, .NET Framework 4.6 library that provides helpers for using MSTest (and Moq) on top of the ChannelAdam Test Framework Library.

Below are the main features of the library. See the linked code for details.

Please contact me if you have any questions.

Getting Started

NuGet Package Installation

To install the ChannelAdam.TestFramework.MSTest NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.TestFramework.MSTest

Usage

 1using ChannelAdam.TestFramework.MSTest.Abstractions;
 2...
 3    [TestClass]
 4    public class MyUnitTests : MoqTestFixture
 5    {
 6        Mock<IMyService> _mockMyService;
 7
 8        [TestMethod]
 9        public void MyTestMethodWithMockObjects()
10        {
11            // ARRANGE
12            _mockMyService = base.MyMockRepository.Create<IMyService>();
13            _mockMyService.Setup(...)
14                .Returns(...);
15
16            // ACT
17            ...
18
19            // ASSERT
20            LogAssert...
21
22            Logger.Log("Verifying all mock expectations were met");
23            MyMockRepository.VerifyAll();
24        }
25
26        [TestMethod]
27        public void MyTestMethod()
28        {
29            // ARRANGE
30            bool isOrderLateExpected = false;
31
32            // ACT
33            Logger.Log("About to do the ACT part of blah blah... so the test output reads like a story");
34            bool isOrderLateActual = true;
35
36            // ASSERT
37            LogAssert.AreEqual("isOrderLate", isOrderLateExpected, isOrderLateActual);
38            // Test Output: "Asserting isOrderLate is equal to: false"
39        }
40    }

Reference

MoqTestFixture inherits from the ChannelAdam Test Framework Moq Library MoqTestFixture class to provide Moq MockRepository functionality on top of its own extension of TestEasy.

Please see the ChannelAdam Test Framework Library documentation for more information about TestEasy.

The ChannelAdam Nancy Library

Overview

This is an open source (Apache License 2.0) .NET Standard 2.0 code library that provides some helpers and extensions for the lightweight Nancy web framework.

This library provides a foundation for the ChannelAdam Nancy SOAP Library.

Getting Started

NuGet Package Installation

To install the ChannelAdam.Nancy NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Nancy

Reference

NancyRequestHelper

The NancyRequestHelper static class provides a helper method for operating on a Nancy Request.

The NancyRequestHelper static class has one method:

  • string GetRequestBodyAsString(Request request) - to extract the body of the Nancy Request as a string

This is also surfaced as an extension method on the Nancy Request class for which you will need a using statement for ChannelAdam.Nancy.

NancyResponseHelper

The NancyResponseHelper static class provides a helper method for operating on a Nancy Response.

The NancyResponseHelper static class has one method:

  • string GetResponseContentAsString(Response response) - to extract the contents of the Nancy Response as a string

This is also surfaced as an extension method on the Nancy Response class for which you will need a using statement for ChannelAdam.Nancy.

NancyResponseFactory

The NancyResponseFactory static class provides helper methods for creating a Nancy Response.

The NancyResponseFactory static class has two methods:

  • Response CreateFromEmbeddedResource(string resourceName, HttpStatusCode httpStatusCode, string contentType) - to create a Nancy Response from an embedded resource

  • Response CreateFromString(string responseValue, HttpStatusCode httpStatusCode, string contentType) - to create a Nancy Response from a given string

The ChannelAdam Nancy Self-Hosting Library

Overview

This is an open source (Apache License 2.0) .NET Standard 2.0 code library that provides some helpers for self-hosting the lightweight Nancy web framework.

This library builds upon the official Nancy Self-Hosting Library.

Getting Started

NuGet Package Installation

To install the ChannelAdam.Nancy.Hosting.Self NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Nancy.Hosting.Self

Reference

NancySelfHostFactory

The NancySelfHostFactory provides functionality for creating and starting a self-hosted instance of Nancy.

The NancySelfHostFactory static class has nine methods:

  • public static HostConfiguration CreateHostConfiguration() - creates a Nancy HostConfiguration with the RewriteLocalhost property set to false to ensure that elevated permissions are not required to start Nancy.

  • public static NancyHost CreateAndStartNancyHost(params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy using the host configuration created by CreateHostConfiguration().

  • public static NancyHost CreateAndStartNancyHost(HostConfiguration hostConfig, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy using the specified host configuration.

  • public static NancyHost CreateAndStartNancyHost(INancyBootstrapper bootstrapper, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy using the specified bootstrapper.

  • public static NancyHost CreateAndStartNancyHost(INancyBootstrapper bootstrapper, HostConfiguration hostConfig, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy using the specified bootstrapper and host configuration.

  • public static NancyHost CreateAndStartNancyHostInBackgroundThread(params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy - in a background thread - using the host configuration created by CreateHostConfiguration().

  • public static NancyHost CreateAndStartNancyHostInBackgroundThread(HostConfiguration hostConfig, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy - in a background thread - using the specified host configuration.

  • public static NancyHost CreateAndStartNancyHostInBackgroundThread(INancyBootstrapper bootstrapper, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy - in a background thread - using the specified bootstrapper.

  • public static NancyHost CreateAndStartNancyHostInBackgroundThread(INancyBootstrapper bootstrapper, HostConfiguration hostConfig, params Uri[] baseUris) - creates and starts a self-hosted instance of Nancy - in a background thread - using the specified bootstrapper and host configuration.

The ChannelAdam Nancy SOAP Library

Overview

This is an open source (Apache License 2.0) .NET Standard 2.0 code library that provides functionality for working with SOAP 1.1 and SOAP 1.2 payloads in the lightweight Nancy web framework.

This library builds upon the foundational ChannelAdam Nancy Library and is complemented by:

Getting Started

NuGet Package Installation

To install the ChannelAdam.Nancy.Soap NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Nancy.Soap

Usage

Example Hello World SOAP Nancy Module

Below is a simple example of a Nancy Module that defines a handler for a SOAP action.

 1public class HelloWorldSoapNancyModule : NancyModule
 2{
 3    public HelloWorldSoapNancyModule(INancySoapAdapter soapAdapter)
 4    {
 5        const string helloWorldSoapServiceRoutePattern = "/HelloWorldSoap11Service";
 6
 7        // Define the route pattern in Nancy
 8        DefineSoapRoute(helloWorldSoapServiceRoutePattern, soapAdapter);
 9
10        // Register SOAP action handlers for that route pattern
11        soapAdapter.RegisterSoapActionHandler(helloWorldSoapServiceRoutePattern, "urn:HelloWorldSoap11Service#HelloWorldSoapAction",
12            (request, routeArgs) =>
13                Soap11NancyResponseFactory.Create(
14                    SoapBuilder.CreateSoap11Envelope().WithBody.AddEntry("<root>Hello SOAP World!</root>"),
15                    HttpStatusCode.OK));
16
17        // And register more SOAP action handlers for the same route pattern:
18        // soapAdapter.RegisterSoapActionHandler(helloWorldSoapServiceRoutePattern, "urn:HelloWorldSoap11Service#AnotherSoapAction", ...
19    }
20
21    private void DefineSoapRoute(string routePattern, INancySoapAdapter soapAdapter)
22    {
23        Post[routePattern] = args => soapAdapter.ProcessRequest(routePattern, base.Request, args);
24    }
25}

There are three important things going on here:

  1. The ChannelAdam.Nancy.Soap.INancySoapAdapter is injected into the constructor of the Nancy Module class. Nancy’s default bootstrapper will automatically resolve the INancySoapAdapter soapAdapter parameter in the constructor, so you don’t need to be concerned about the constructor injection.

  2. As one normally would do, the route is defined. For a SOAP action, typically that would be done with a HTTP Post. Here is where it gets interesting. For a given route pattern, the action argument to specify is the INancySoapAdapter.ProcessRequest method. This ProcessRequest method on the SOAP Adapter conveniently extracts the SOAP action from either the HTTP header or the SOAP header and then dispatches the request to the corresponding SOAP action handler method that has been registered with it (see the next point).

  3. A SOAP action handler for the same route pattern is registered with the SOAP Adapter. We use the Soap11NancyResponseFactory.Create() method to convert the result of the SoapBuilder (or any string) into a Nancy Response with the appropriate content type for the version of SOAP you are using. Of course, there is also a Soap12NancyResponseFactory helper class for SOAP 1.2 responses.

Example of Self-Hosting Nancy in an Automated Test

Sometimes you want to mock out your actual SOAP services so you can perform Unit Testing instead of Integration Testing. With the ChannelAdam Nancy SOAP Adapter, it is possible to self-host Nancy in the same process as your test case, and just like a mock object, configure it to respond with a specific payload for the current Unit Test.

Below is some dirty automated test code (meant only for this purpose of demonstrating the simplest usage).

Note: I highly recommend following Behaviour-Driven Development practices and the usage of SpecFlow for automated testing.

Step 1 - Identify the Routes and SOAP Actions

The first step is to identify the routes patterns and SOAP actions. Maybe you have these already defined in some constant classes somewhere and if so that’s perfect. For the purpose of this example though, I am putting them into the following static classes.

1public static class TestCaseRoutes
2{
3    public static readonly string MySoap11Service = "/MySoap11Service";
4}
5
6public static class TestCaseSoapActions
7{
8    public static readonly string MySoap11ServiceTestAction = "urn:MySoap11Service#TestAction";
9}

Step 2 - Define a Nancy Module

The next step for an automated test is to create a Nancy Module and define a route.

Unlike the example Hello World Nancy Module above, the difference for an automated test is that within the Nancy Module you would not register the SOAP action handler with the SOAP Adapter (as that will be done later in the test code). The only thing you need to do in the Nancy Module is define the routes.

 1public class TestCaseNancyModule : NancyModule
 2{
 3    public TestCaseNancyModule(INancySoapAdapter soapAdapter)
 4    {
 5        DefineSoapRoute(TestCaseRoutes.MySoap11Service, soapAdapter);
 6    }
 7
 8    private void DefineSoapRoute(string routePattern, INancySoapAdapter soapAdapter)
 9    {
10        Post[routePattern] = args => soapAdapter.ProcessRequest(routePattern, base.Request, args);
11    }
12}

Step 3 - Write the Test Code

Finally the last step is to write the test code.

 1private const string NancyBaseUrl = "http://localhost:8087";
 2
 3private NancySoapAdapter nancySoapAdapter;
 4private NancyHost nancyHost;
 5
 6private string expectedSoapBodyEntryXml;
 7
 8public void SimpleDirtyTestCode()
 9{
10    //------------
11    // Set up
12    //------------
13
14    // Self host Nancy
15    this.nancySoapAdapter = new NancySoapAdapter();
16    this.nancyHost = NancySelfHostFactory.CreateAndStartNancyHostInBackgroundThread(
17        new NancySoapAdapterBootstrapper(this.nancySoapAdapter), 
18        new Uri(NancyBaseUrl));
19
20    //------------
21    // Arrange
22    //------------
23    this.expectedSoapBodyEntryXml = "<root>Whatever you need for this test</root>";
24
25    // Register SOAP action handler for the route pattern
26    soapAdapter.RegisterSoapActionHandler(TestCaseRoutes.MySoap11Service, TestCaseSoapActions.MySoap11ServiceTestAction,
27        (request, routeArgs) =>
28        {
29            // Return a Nancy Response with whatever this specific test case requires...
30            // A SOAP body entry or Soap11NancyResponseFactory.CreateFault()... 
31            return Soap11NancyResponseFactory.Create(
32                SoapBuilder.CreateSoap11Envelope().WithBody.AddEntry(this.expectedSoapBodyEntryXml),
33                HttpStatusCode.OK);
34        });
35    
36    //------------
37    // Act
38    //------------
39    /// TODO - Invoke your System Under Test that will call the Nancy route with the specified SOAP action
40
41    //------------
42    // Assert
43    //------------
44    // TODO - assert the actual response equals this.expectedSoapBodyEntryXml
45    //      - or that a FaultException occurred...
46
47    //------------
48    // Tear Down
49    //------------
50    this.nancyHost.Stop();
51}

The important things to understand are:

  • With the help of the ChannelAdam.Nancy.SelfHosting.NancySelfHostingFactory class, we are self-hosting Nancy in the same process as the test case. Because of this, we specifically create and start it in a background thread so that if the main thread of the test case performs a HTTP request to the route, then everything will respond and be processed as expected.

  • We explicitly create the NancySoapAdapter in the test case and bootstrap it with the NancySoapAdapterBootstrapper into the factory method that creates and starts Nancy. This ensures that the Nancy Module constructor receives the SOAP Adapter instance that we created.

  • Using the NancySoapAdapter, we then register a SOAP action handler specifically returning the response required by the test case.

Reference

NancySoapAdapter & INancySoapAdapter

The ChannelAdam.Nancy.Soap.NancySoapAdapter class which implements the ChannelAdam.Nancy.Soap.Abstractions.INancySoapAdapter interface makes all the magic happen for adapting SOAP payloads to work easily in Nancy.

There are four methods in the interface:

  • Response ProcessRequest(string routePattern, Request request) - this is the action to specify in the Nancy route definition to dispatch the HTTP request to the registered handler for the SOAP action named in the HTTP request header or SOAP header.

  • Response ProcessRequest(string routePattern, Request request, dynamic requestRouteArgs) - this is the action to specify in the Nancy route definition to dispatch the HTTP request to the registered handler for the SOAP action named in the HTTP request header or SOAP header. This overload allows the requestRouteArgs from the route pattern to be provided.

  • void RegisterSoapActionHandler(string routePattern, string soapAction, NancyRequestHandler handler) - registers a handler for the specified route pattern and SOAP action.

  • Request TryWaitForRequest(string routePattern, string soapAction, int retryCount, TimeSpan sleepDuration) - Waits for a specified amount of time for a HTTP request to be received on the specified route with the given SOAP action.

NancySoapAdapterBootstrapper

The NancySoapAdapterBootstrapper is a custom bootstrapper for Nancy.

Normally you don’t need to be concerned with this, but it is especially useful in automated tests.

There are two constructors:

  • public NancySoapAdapterBootstrapper() - which will create a NancySoapAdapter instance for you.

  • public NancySoapAdapterBootstrapper(INancySoapAdapter soapAdapter) - which allows you to specify your own instance of the NancySoapAdapter (which is especially useful in automated tests).

Soap11NancyResponseFactory

The Soap11NancyResponseFactory static class allows you to create a Nancy Response with the correct content type for SOAP 1.1.

There are five methods on the static class:

  • public static Response Create(ISoap11EnvelopeBuilder envelopeBuilder, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified ISoap11EnvelopeBuilder with the correct content type for SOAP 1.1 and with the specified HttpStatusCode.

  • public static Response Create(XContainer soap11Envelope, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified SOAP 1.1 envelope in the XContainer with the correct content type for SOAP 1.1 and with the specified HttpStatusCode.

  • public static Response Create(string soap11EnvelopeXml, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified SOAP 1.1 envelope XML string with the correct content type for SOAP 1.1 and with the specified HttpStatusCode.

  • public static Response CreateFault(ISoap11EnvelopeBuilder envelopeBuilder) - to create a Nancy Response with a SOAP 1.1 fault, as specified by the ISoap11EnvelopeBuilder, with an HttpStatusCode.InternalServerError.

  • public static Response CreateFault(XContainer envelope) - to create a Nancy Response with a SOAP 1.1 fault, as specified by the SOAP 1.1 envelope in the specified XContainer, with an HttpStatusCode.InternalServerError.

Soap12NancyResponseFactory

The Soap12NancyResponseFactory static class allows you to create a Nancy Response with the correct content type for SOAP 1.2. This is the SOAP 1.2 equivalent of the Soap11NancyResponseFactory.

There are five methods on the static class:

  • public static Response Create(ISoap12EnvelopeBuilder envelopeBuilder, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified ISoap11EnvelopeBuilder with the correct content type for SOAP 1.2 and with the specified HttpStatusCode.

  • public static Response Create(XContainer soap12Envelope, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified SOAP 1.2 envelope in the XContainer with the correct content type for SOAP 1.2 and with the specified HttpStatusCode.

  • public static Response Create(string soap12EnvelopeXml, HttpStatusCode httpStatusCode) - to create a Nancy Response from the specified SOAP 1.2 envelope XML string with the correct content type for SOAP 1.2 and with the specified HttpStatusCode.

  • public static Response CreateFault(ISoap12EnvelopeBuilder envelopeBuilder) - to create a Nancy Response with a SOAP 1.2 fault, as specified by the ISoap11EnvelopeBuilder, with an HttpStatusCode.InternalServerError.

  • public static Response CreateFault(XContainer envelope) - to create a Nancy Response with a SOAP 1.2 fault, as specified by the SOAP 1.2 envelope in the specified XContainer, with an HttpStatusCode.InternalServerError.

SoapNancyRequestHelper

The SoapNancyRequestHelper static class provides helpful functionality that operates on a Nancy Request.

There is one method on the static class:

  • public static string GetSoapAction(Request request) - to retrieve the SOAP action from either the HTTP header or the SOAP envelope header. The HTTP header takes precedence.

This functionality is also surfaced as an extension method on the Nancy Request class for which you will need a using statement for ChannelAdam.Nancy.Soap.