The ChannelAdam Commands Library

Overview

An open source, .NET Standard 1.1 library implementation of the Command Pattern - including reversible commands.

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.Commands NuGet package run the following command in the Package Manager Console:

1PM> Install-Package ChannelAdam.Commands

Usage

An example of the ReversibleCommandManager, using the ExecuteSetPropertyCommand and UndoPreviousCommand methods:

 1var testObject = new ClassWithProperty
 2{
 3    MyProperty = 1
 4};
 5
 6var commandManager = new ReversibleCommandManager();
 7
 8commandManager.ExecuteSetPropertyCommand(testObject, p => p.MyProperty, 100);
 9commandManager.ExecuteSetPropertyCommand(testObject, p => p.MyProperty, 200);
10
11commandManager.UndoPreviousCommand();
12// MyProperty is now back to 100

Reference

Command Action

A Command Action has an Execute method with a void return parameter.

Command Function

A Command Function has an Execute method with a specified return parameter.

Reversible Commands

Need to execute some commands and be able to undo them? This Reversible Command implementation is for you!

Use the Reversible Command Manager to manage the stack of commands that can be reversed.

Set Property - Command Implementation

A command implementation for setting a property on an object.

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.

Background

ChannelAdam WCF Library — Version 1 Documentation

Background

The Issues

The issues faced by .NET developers are explained in depth in the article How To Call WCF Services Properly, where I researched and highlighted the typical problems with using WCF clients (such as memory and connection leaks), and concluded that the most correct solution for consuming WCF services would:

  • Perform the Close/Abort pattern without a race condition;
  • Handle the situation when the service operation throws exceptions;
  • Handle the situations when both the Close and Abort methods throw exceptions; and
  • Handle asynchronous exceptions such as the ThreadAbortException.

Below is the verbose sample code that is required for correctly using a .NET WCF client, performing exception handling and correctly performing the Close/Abort pattern. Unfortunately, due to the way Microsoft designed WCF, if you want to use a WCF service client cleanly without connection or memory leaks, this is the type of extensive code that must be written for every service operation call.

  1SampleServiceClient client = null;
  2
  3try
  4{
  5    client = new SampleServiceClient();
  6
  7    var response = client.SampleOperation(1234);
  8
  9    // Do some business logic
 10}
 11catch (FaultException<MyCustomException>)
 12{
 13    // Do some business logic for this SOAP Fault Exception
 14}
 15catch (FaultException)
 16{
 17    // Do some business logic for this SOAP Fault Exception
 18}
 19catch (CommunicationException)
 20{
 21    // Catch this expected exception so it is not propagated further.
 22    // Perhaps write this exception out to log file for gathering statistics...
 23}
 24catch (TimeoutException)
 25{
 26    // Catch this expected exception so it is not propagated further.
 27    // Perhaps write this exception out to log file for gathering statistics...
 28}
 29catch (Exception)
 30{
 31    // An unexpected exception that we don't know how to handle.
 32    // Perhaps write this exception out to log file for support purposes...
 33    throw;
 34}
 35finally
 36{
 37    // This will:
 38    // - be executed if any exception was thrown above in the 'try' (including ThreadAbortException); and
 39    // - ensure that CloseOrAbortServiceChannel() itself will not be interrupted by a ThreadAbortException
 40    //   (since it is executing from within a 'finally' block)
 41    CloseOrAbortServiceChannel(client);
 42
 43    // Unreference the client
 44    client = null;
 45}
 46
 47
 48private void CloseOrAbortServiceChannel(ICommunicationObject communicationObject)
 49{
 50    bool isClosed = false;
 51
 52    if (communicationObject == null || communicationObject.State == CommunicationState.Closed)
 53    {
 54        return;
 55    }
 56
 57    try 
 58    {
 59        if (communicationObject.State != CommunicationState.Faulted)
 60        {
 61            communicationObject.Close();
 62            isClosed = true;
 63        }
 64    }
 65    catch (CommunicationException)
 66    {
 67        // Catch this expected exception so it is not propagated further.
 68        // Perhaps write this exception out to log file for gathering statistics...
 69    }
 70    catch (TimeoutException)
 71    {
 72        // Catch this expected exception so it is not propagated further.
 73        // Perhaps write this exception out to log file for gathering statistics...
 74    }
 75    catch (Exception)
 76    {
 77        // An unexpected exception that we don't know how to handle.
 78        // Perhaps write this exception out to log file for support purposes...
 79        throw;
 80    }
 81    finally
 82    {
 83        // If State was Faulted or any exception occurred while doing the Close(), then do an Abort()
 84        if (!isClosed)
 85        {
 86            AbortServiceChannel(communicationObject);
 87        }
 88    }
 89}
 90
 91
 92private static void AbortServiceChannel(ICommunicationObject communicationObject)
 93{
 94    try
 95    {
 96        communicationObject.Abort();
 97    }
 98    catch (Exception)
 99    {
100        // An unexpected exception that we don't know how to handle.
101        // If we are in this situation:
102        // - we should NOT retry the Abort() because it has already failed and there is nothing to suggest it could be successful next time
103        // - the abort may have partially succeeded
104        // - the actual service call may have been successful
105        //
106        // The only thing we can do is hope that the channel's resources have been released.
107        // Do not rethrow this exception because the actual service operation call might have succeeded
108        // and an exception closing the channel should not stop the client doing whatever it does next.
109        //
110        // Perhaps write this exception out to log file for gathering statistics and support purposes...
111    }
112}

ChannelAdam WCF Library Makes It Easy

The ChannelAdam WCF Library is an API for working with WCF clients, that significantly reduces the amount of that code that developers have to write. It allows you to forget about the complex subtleties of WCF clients, channels and communication states, and lets you just use your service client in a way that is very similar to how you probably are doing it now - but without the leaks!

When you use the ChannelAdam WCF Library’s ServiceConsumer, you know that you can keep calling service operations through the ServiceConsumer and it will ‘just work’ and not leak connections or memory - no matter what happens!

The ChannelAdam WCF Library’s ServiceConsumer hides the inner complexity of service channels. For example, if a service channel / communication object / service client moves into a Fault state, the ServiceConsumer will correctly perform the Close/Abort pattern and dispose of the channel. The next time a request is made through the ServiceConsumer, a new channel is created under the covers to seamlessly process the request.

Background

ChannelAdam WCF Library — Version 2 Documentation

Background

The Issues

The issues faced by .NET developers are explained in depth in the article How To Call WCF Services Properly, where I researched and highlighted the typical problems with using WCF clients (such as memory and connection leaks), and concluded that the most correct solution for consuming WCF services would:

  • Perform the Close/Abort pattern without a race condition;
  • Handle the situation when the service operation throws exceptions;
  • Handle the situations when both the Close and Abort methods throw exceptions; and
  • Handle asynchronous exceptions such as the ThreadAbortException.

Below is the verbose sample code that is required for correctly using a .NET WCF client, performing exception handling and correctly performing the Close/Abort pattern. Unfortunately, due to the way Microsoft designed WCF, if you want to use a WCF service client cleanly without connection or memory leaks, this is the type of extensive code that must be written for every service operation call.

  1SampleServiceClient client = null;
  2
  3try
  4{
  5    client = new SampleServiceClient();
  6
  7    var response = client.SampleOperation(1234);
  8
  9    // Do some business logic
 10}
 11catch (FaultException<MyCustomException>)
 12{
 13    // Do some business logic for this SOAP Fault Exception
 14}
 15catch (FaultException)
 16{
 17    // Do some business logic for this SOAP Fault Exception
 18}
 19catch (CommunicationException)
 20{
 21    // Catch this expected exception so it is not propagated further.
 22    // Perhaps write this exception out to log file for gathering statistics...
 23}
 24catch (TimeoutException)
 25{
 26    // Catch this expected exception so it is not propagated further.
 27    // Perhaps write this exception out to log file for gathering statistics...
 28}
 29catch (Exception)
 30{
 31    // An unexpected exception that we don't know how to handle.
 32    // Perhaps write this exception out to log file for support purposes...
 33    throw;
 34}
 35finally
 36{
 37    // This will:
 38    // - be executed if any exception was thrown above in the 'try' (including ThreadAbortException); and
 39    // - ensure that CloseOrAbortServiceChannel() itself will not be interrupted by a ThreadAbortException
 40    //   (since it is executing from within a 'finally' block)
 41    CloseOrAbortServiceChannel(client);
 42
 43    // Unreference the client
 44    client = null;
 45}
 46
 47
 48private void CloseOrAbortServiceChannel(ICommunicationObject communicationObject)
 49{
 50    bool isClosed = false;
 51
 52    if (communicationObject == null || communicationObject.State == CommunicationState.Closed)
 53    {
 54        return;
 55    }
 56
 57    try 
 58    {
 59        if (communicationObject.State != CommunicationState.Faulted)
 60        {
 61            communicationObject.Close();
 62            isClosed = true;
 63        }
 64    }
 65    catch (CommunicationException)
 66    {
 67        // Catch this expected exception so it is not propagated further.
 68        // Perhaps write this exception out to log file for gathering statistics...
 69    }
 70    catch (TimeoutException)
 71    {
 72        // Catch this expected exception so it is not propagated further.
 73        // Perhaps write this exception out to log file for gathering statistics...
 74    }
 75    catch (Exception)
 76    {
 77        // An unexpected exception that we don't know how to handle.
 78        // Perhaps write this exception out to log file for support purposes...
 79        throw;
 80    }
 81    finally
 82    {
 83        // If State was Faulted or any exception occurred while doing the Close(), then do an Abort()
 84        if (!isClosed)
 85        {
 86            AbortServiceChannel(communicationObject);
 87        }
 88    }
 89}
 90
 91
 92private static void AbortServiceChannel(ICommunicationObject communicationObject)
 93{
 94    try
 95    {
 96        communicationObject.Abort();
 97    }
 98    catch (Exception)
 99    {
100        // An unexpected exception that we don't know how to handle.
101        // If we are in this situation:
102        // - we should NOT retry the Abort() because it has already failed and there is nothing to suggest it could be successful next time
103        // - the abort may have partially succeeded
104        // - the actual service call may have been successful
105        //
106        // The only thing we can do is hope that the channel's resources have been released.
107        // Do not rethrow this exception because the actual service operation call might have succeeded
108        // and an exception closing the channel should not stop the client doing whatever it does next.
109        //
110        // Perhaps write this exception out to log file for gathering statistics and support purposes...
111    }
112}

ChannelAdam WCF Library Makes It Easy

The ChannelAdam WCF Library is an API for working with WCF clients, that significantly reduces the amount of that code that developers have to write. It allows you to forget about the complex subtleties of WCF clients, channels and communication states, and lets you just use your service client in a way that is very similar to how you probably are doing it now - but without the leaks!

When you use the ChannelAdam WCF Library’s ServiceConsumer, you know that you can keep calling service operations through the ServiceConsumer and it will ‘just work’ and not leak connections or memory - no matter what happens!

The ChannelAdam WCF Library’s ServiceConsumer hides the inner complexity of service channels. For example, if a service channel / communication object / service client moves into a Fault state, the ServiceConsumer will correctly perform the Close/Abort pattern and dispose of the channel. The next time a request is made through the ServiceConsumer, a new channel is created under the covers to seamlessly process the request.