HTTPS SSH

TEAM.Commons is a set of libraries that extend the .NET framework with functionality I've found myself (initially) and then more people using in most of their projects.

This blog entry describes the motivations behind it and the functionality included: http://rodolfograve.blogspot.co.uk/2010/09/teamcommons-introduction.html.

In order to use it just install the NuGet packages you want.

The build is now automated thanks to the amazing AppVeyor service:

Build status


TEAM.Commons

Several general-purpose extensions, including:

Database querying

Very light database querying. No need to "import" the database schema or have code structures that match it. Useful for creating reports/views from the database and plays very well inside the query side of a CQRS implementation.

using (var connection = new SqlConnection(...))
{
    connection.Open();
    foreach (var item in connection.GetAllWithStreaming<MyDtoClass>("select * from Table1 inner join Table2 ...")
    {
        Console.WriteLine(item.PrettyFormat());
    }
}

Easy object formatting for logging

All properties and readonly fields are returned in a JSON-like string you can the just print to your log files, console, etc.

  • Saves you from having to override ToString().
  • It can handle collections.
  • Does its best to print as much useful information as possible, e.g. the DateTimeKind for DateTime properties.
  • You can control how many levels deep you want to go and even properties you want to include/exclude.
anyObject.PrettyFormat()

The output looks like:

SimpleClass {{ StringProperty='5qjODbOU5mynK', IntProperty='-899001614', DateProperty='2000-12-12 00:00:00 [DateTimeKind: Unspecified]', GuidProperty='9721617d-d9bb-4961-957c-0364615152f8', }}

Simple Excel file generation

An object model to generate an Excel sheet. Very limited in functionality but still very useful (and extensible) if all you need is a basic sheet with some colouring.

ExcelWorkbook sut = ExcelWorkbook.WithWorksheets
(
      ExcelWorksheet.WithRows("Testing",
         ExcelRow.WithCells(
            ExcelCell.String("This is first row, first column"),
            ExcelCell.String("This is first row, second column")
         ),
         null,
         null,
         ExcelRow.WithCells(
            ExcelCell.String("This is second row, first column"),
            ExcelCell.Empty(),
            null,
            ExcelCell.String("This is second row, fourth column")
         )
      )
);
sut.GenerateAsMsPropietaryXml(File.OpenWrite("Test.xml"), null);

Windows Service wrapping to support running as a console

After trying TopShelf and finding it overly complicated because it tries to solve the problem by providing its own executable and providing install/uninstall capabilities.

I just wanted to be able to hit F5 from Visual Studio to get the application running as a Console in a reliable way, i.e. doing exactly what it would do as a Windows Service (except for the service control events, of course).

The installation of my services is usually done by dedicated scripts or Octopus.

The proposed solution doesn't force any inheritance.

using (var host = new ServiceHost(new DelegateService(StartService, StopService), _log))
{
   host.Start(); // This call blocks until the service stops.
}

Strongly-typed access to configuration settings

var strValue = ConfigurationManager.AppSettings.GetOptionalValue<string>("StrSettingName");
var intValue = ConfigurationManager.AppSettings.GetRequiredValue<int>("IntSettingName");

You'll get nice error messages including the value found in the file if it couldn't be converted to the speficied type.

TEAM.Commons.Web: no magic strings. Strong-typing and build time verification

Minor tweaks to the ASP.NET MVC framework to enforce a Single Action Controller rule, and extensions methods to help reap the associated benefits:

  • Strongly-typed reference to actions. No magic strings.
  • Tests are easier to read and maintain.

No inheritance forced. All existing ASP.NET MVC default behaviours are unafected.

A Single Action Controller

public class DoEnable : Controller // No change. Inherit from the standard ASP.NET MVC Controller class.
{
   // Only one public ActionResult method, named Execute.
   public ActionResult Execute(DoEnableRequest request) // Strongly-typed request is optional but recommended
   {
      return this.RedirectToAction<ShowList>(); // Redirect to another action by using its type (no magic strings!).
   }
}

View

@(Html.ActionLink<DoEnable>("Link text", routeValues: new DoEnableRequest { Id = feature.Id })) // Render link to action
@(Html.Action<ShowListPartial>(routeValues: new ShowListPartialFilter { Name = feature.Name })) // Render a partial view

Tests

var underTest = new ShowList(...);
var result = underTest.Execute(new ShowListRequest(...));

result.AssertIsView().WithName("List").WithModelState(...); // Part of the test extension methods provided (some are useful even for non-SingleActionController projects).

result.AssertIsRedirectToRoute().WithSingleActionController<ShowList>(); // Referring to an action by its strong type, which facilitates refactoring and build-time checkd.

TEAM.Commons.Messaging: full control over your messaging

A very basic but production ready (and tested) MessageBus implementation with a lot of extension points. InProcess and MSMQ transports are provided as well as integration with Autofac.

Create a MessageBus

var builder = new ContainerBuilder(); // The Autofac container builder to register all dependencies and message handlers.
builder.RegisterMessageHandler<SomeMessageHandler>(x => new TestMessageHandler(...));
builder.RegisterMessageHandlerType<AnotherMessageHandler>();
var messageHandlersContainer = new AutofacMessageHandlersContainerAdapter(builder.Build());

var receivingTransport = new InProcessTransport(); // Could be an MsmqReceivingTransport;
var transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; // Optional

var map = new DictionaryMessageMap(); // Configure how to send/publish messages

object anEndpointId = "Some Endpoint id";
map.AddEndpoint(anEndpointId, new MessageRoutingInfo { SendingTransport = transportToSendMessagesToThisEndpoing });

map.AddMessageMap<SomeMessage>(anEndpointId); // When publishing messages of type SomeMessage, send them to endpoint with Id anEndpointId

var messageBus = new SingleThreadMessageBus("A name. Useful for debugging", receivingTransport, messageHandlersContainer, map, transactionOptions);
messageBus.Start(); // Starts a new thread that will process messages arriving into the receivingTransport.

Extensible

You can provide your own implementation of

  • IReceivingTransport and ISendingTransport: to support a messaging middleware other than MSMQ or InProcess.
  • IErrorHandlingStrategy: to customize what happens when a message cannot be processed.
  • IMessageMap: to customize how you map messages to endpoints.
  • IMessageSerializer: to customize how messages are serialized/deserialized.
  • IMessageHandlersContainer: to customize how message handlers are built.
  • IMessageBus: to provide a different implementation (multi-threaded, based on TPL Dataflow, etc).

TEAM.Commons.Logging: simplicity over everything else

The latest addition. Provides a simple logging framework that takes advantage of the new C# CompilerServices attributes (CallerMemberName, CallerFilePath and CallerLineNumber) to gather information about the location from where the log entry is created.

Log4net needs to use slow reflection in order to do the same.

Semantic logging

TEAM.Commons.Logging logs objects, not only strings. Whatever object you wnat to log is stored and you can then query your logs using the type and/properties of your objects.

More dependency injection friendly structure

Log4net promotes a style where each class creates its own instance of ILogger by calling the static LogManager.GetLogger method. This hinders testability and becomes a especial case in the structure of the application.

Additionally, the log4net.ILog interface is huge, with 34 methods and 5 properties to implement.

TEAM.Commons.Logging has a very simple ILog interface which makes it very easy to fake/mock:

void Log(object content, Exception exception = null, [CallerMemberName]string callerMemberName = "", [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0, params string[] tags);

Introducing Tags

No more arbitrary, fixed and exclusive categories for a log entry (Debug, Info, etc). Now you can tag your log entries with whatever you want, even more than one, making it much easier to query your log file in ways meaningful to your business/application.

log.Log("some message", tags: "Important to TechSupport")
log.Log("some message", tags: "Important to EndClient")
log.Log("some message", tags: "Important to Developer")
log.Log("some message", tags: new string[] { "Important to TechSupport", "Important to EndClient" })

You can use extension methods to standardize the tags in your application.

Minimum configurability

No magic config switches that can get the end user any output they want, even breaking your application. You control your logging from code and it's up to you if you want to provide an external config source.

Keep in mind that having "ultimate" configurability also means you cannot assume anything about your log file, making it really hard to process those files. Since processing those log files when something goes wrong is the most important use case, controlling the exact format of the output makes everything easier.

JSON output

The two ILog implementations provided (FileLog and DailyRollingFileLog) output JSON which means you can easily parse the log files using any JSON reader.

The output looks like this, which is human readable:

{"Timestamp":"2014-05-09T10:33:32.854+00:00","Tags":[],"Content":"Starting as Windows Service. Changing the Principal for the AppDomain.CurrentDomain to PrincipalPolicy.WindowsPrincipal","Exception":null,"EntryCreationTimeCost":"00:00:00.0054164","CallerMemberName":"Start","CallerFilePath":"d:\\BuildAgent2\\work\\1e3b62972c1a47c\\LogServer.Host\\Bootstrapper.cs","CallerLineNumber":68,"ThreadId":1,"ThreadName":null,"ThreadIsAlive":true,"ThreadIsBackground":false,"ThreadIsPoolThread":false,"ThreadState":0,"ProcessId":15032,"ProcessName":"LogServer.Host","ProcessMachineName":".","ProcessTotalProcessorTime":"00:00:00.2028013","ProcessUserProcessorTime":"00:00:00.1560010","ProcessVirtualMemorySize":118468608,"ProcessWorkingSet":11657216,"ProcessThreadsCount":3}

Lots of useful extra information

As you can see above, the provided implementations collect a lot of extra (and cheap) information, including how much time it took to create the entry itself (EntryCreationTimeCost).

Exceptions are also stored as an Exception and not as some string representation of it which means you can query the log for entries with exceptions of type 'X', InnerExceptions not null, etc.

Embeddable server to read and query with LINQ (alpha)

Because the output is JSON (assuming you don't create your own implementation that does something different) I've been able to implement a self-hosted web server that provides a LINQ-to-Log screen to query your log files.

This is still work in progress but it's currently in a working state. I'll try to publish it soon.

This server will be available as a nuget package you can install in your own project which will make your application serve its own logs, or as a standalone executable. It can be run as either a Windows Service or a Console application.

Here are some screenshots:

Main screen

MainEmpty.png

Query Results

QueryResults.png

Entry details

EntryDetails.png