Wiki

Clone wiki

ElmahR / Architecture

ElmahR Architecture

General Architecture

Let's see how ElmahR is structured with a couple of diagrams.

Flows

The first one illustrates a scenario where 4 source applications are posting to a common dashboard:

ElmahR

When an error occurs on one of the monitored applications (red lightning bolt in the diagram), ELMAH traps it and, thanks to the ElmahR ErrorPostModule, posts it to the configured dashboard. There the error is unpacked and broadcast to all the connected client using SignalR, and it will pop up on the client side dashboard (or on the new simplified log page).

The second diagram is more about illustrating how an error flows from the source application where it happened down to a browser instance connected to the dashboard:

ElmahR

This diagram makes clearer how an error is packed in a JSON representation, where it get POSTed, and how is eventually broadcast to the dashboards.

Modules

ElmahR is made of modules, which we can see in the following pictures (ElmahR word has been removed from the modules names for brevity):

ElmahR

On the errors source side we use the ElmahR.Elmah module, and we do not need anything else. On the dashboard side, in order to build one we might need several modules, but the only mandatory one is ElmahR.Core (which by the way depends and requires ElmahR.Elmah because the latter shares a bunch of features). Every other dashboard module is built on top of ElmahR.Core.

Dashboard

Errors from monitored applications get posted to the configured dashboard, which is a regular ASP.NET application available here in source code, and packaged in a zipped files from the Downloads section. During the latest development iterations the dashboard has been deeply reorganized and structured in modules, which allowed to more easily reach the goal to distribute it through Nuget packages.

The dashboard is composed by several blocks, let's have a look at them

ElmahR.Core, features

This is the main and most important component of the dashboard architecture, and it's a "mixed" block because it supplies both server and client side features. As a regular .NET assembly it delivers:

  • basic contracts
  • error representation
  • basic HTTP handlers for error reception and YSOD mimicking
  • configuration management
  • modules loading
  • default in memory persistence mechanisms
  • default embedded IoC container
  • broadcasting through a SignalR Hub
  • plugins system
  • logging and auto-diagnostic
  • ...and more

At the same time it contains a couple of Javascript files which get distributed with the assembly and "sent" down to clients. They make use of quite common Javascript libraries (like jQuery), and such dependencies are managed through ASP.NET bundling and minification infrastructure. The most important Javascript file is elmahr.core.js which, along with the server side Hub, provides the main dashboard functionalities like:

  • applications advertising
  • errors notification and error details management
  • statistics computation and broadcasting
  • applications and error types broadcast (de)activation
  • client side extensibility
  • logging
  • plugins distribution

Finally, ElmahR.Core supplies a basic web page which implements a raw real time log listing errors as they occur. A more appealing dashboard, available on the demo web site, is not implemented inside the core, but in an additional module.

ElmahR.Core, extensibility

ElmahR.Core offers 3 ways to extend its behavior and enrich a dashboard with new features:

  • Modules: a module (implementation of ElmahR.Core.Modules.IModule) is a way to supply new client side libraries. It's a server side feature which basically allows to declare a Javascript bundle, but in a more "declarative" way which allows ElmahR.Core to optimize how to deploy Javascript files according to additional rules, like opt in CDN usage. Modules names are used to generate bundle names through a conventions based on full type names
  • Plugins: it's a different way to extend client side ElmahR through conventions on file names, and it's useful when the goal is to add new features through new SignalR hubs. A plugin is again a .NET assembly which contains one additional Hub-derived class, and it usually deploys client side files, which can be Javascript, CSS or HTML components
  • Computations: on first connection and at each error notification, ElmahR.Core allows us to calculate basic statistics; specific client side extension point are supplied to attach new statistic computations, and related rendering bits

These 3 extension mechanism can be mixed in different ways, and are used to implement the full-fledged dashboard available on the demo web site.

More specific and detailed documentation on extensibility will be soon made available.

ElmahR.Modules.Dashboard

ElmahR.Core is delivering the foundation of a fully functional dashboard, but the way error notifications are treated is very basic. This is also true for the supplied user interface, which is nothing more than a raw live log. If you ever tried the demo web site you might have seen a more attractive dashboard, which is supplied through an additional module called ElmahR.Modules.Dashboard. This module basically adds client site code and styling, which are then rendered by a specific page. This module builds a Single Page Application experience on top of what the Core part supplies, using Knockout to easily and effectively decouple the Javascript code from the rendering and styling logic.

ElmahR.Persistence.*

ElmahR main task is to receive errors and broadcast them in real time to connected clients. Storing errors somewhere is not its main goal, nevertheless it would be a shame to avoid leveraging its privileged central position and missing the opportunity to persist errors from several applications in a common place. ElmahR has been built with this idea in mind, which has been then developed over a consistent abstraction on top of which a default "in memory" implementation has been built. When persistent errors are needed, the default system can be replaced through ad hoc modules available through specific Nuget packages The available abstraction would also allow anybody to build new persistors supporting not implemented persistence systems.

A set of modules have been built to support EntityFramework in its different flavors. When adding persistence support to ElmahR, the focus was on providing support for a wide range of relational databases with a small effort, possibly delivering an automatic schema management. ElmahR does not really need any fancy data model, two unrelated flat table are just enough. EntityFramework fits quite well because it's easy to install, supports several relational databases, allows a "code first" approach and takes care of creating and upgrading tables automatically. It's an ORM, but that's incidental and it's not really the reason it's been chosen, it was simply the fastest way to fulfill the previously listed goals.

That said, during ElmahR development a new EntityFramework major version appeared, not to mention that a new .NET Framework (4.5) version came up. In order to support the different possible combinations of those components, 3 different compilations have been made available, along with 3 corresponding Nuget packages.

ElmahR might though have to work in environments where different approaches to persistence could be better. That's why persistence can be easily replaced implementing ElmahR.Core.Persistors.IApplicationsPersistor. In order to supply a sample alternative implementation ElmahR.Persistence.MongoDB has been added to the project, delivering a working implementation on top of the popular document database MongoDB, which proves how ElmahR is easily pluggable and extensible at this level. This module and the previous ones can be analyzed in case you have to build a new module in order to support a different persistence system.

Dependency Injection

SignalR supports dependency injection through its own IDepencencyResolver interface, therefore there was one more good reason to add an IoC library to ElmahR. ElmahR has a certain level of modularity, which allows you to build a dashboard even from inside an existing web application, but this requires a good abstraction from the concrete IoC library to be used.

ElmahR does not want to force any particular dependency injection library to its users, therefore it introduces an appropriate abstraction through an interface called ElmahR.Core.Dependencies.IDependencyKernel, which anybody can implement to abstract any dependency injection mechanism. Internally a basic implementation of that abstraction has been built embedding TinyIoC, nevertheless users might want to integrate that part with the IoC container they're already using. An additional implementation has been supplied with the ElmahR.IoC.NInject library, which uses NInject to concretely resolve the required dependencies. In the next months new implementations for different IoC libraries might be added, nevertheless you are free to implement the IDependencyKernel interface using your favorite one if that's not NInject. If you do not have any particular requirement from that point of view, you do not need to do anything special, the embedded implementation will be used.

How to use available modules

Modules are easy to use, especially through the new Nuget packages. Nevertheless modules use MEF as a composition system, so installing a module it's actually as simple as deploying it in the bin folder. Each module might need additional configuration bits, like connection strings, but most of the job is done by simply distributing the binaries with the rest of your dashboard application.

Monitored source application

A monitored application where ELMAH is already installed and properly configured will just need the ErrorPostModule to be properly hooked and configured, as explained here.

ElmahR is "augmenting" ELMAH

The integration with ELMAH is not based on binary dependencies, but on data exchange. ELMAH already defines a set of fields and collections which describe an error, and ElmahR borrows this data structure and builds its logic on top of it. This approach makes ElmahR virtually independent from ELMAH: whoever is able to craft an error description matching the data format from ELMAH can send errors to ElmahR and have them published.

This approach could be considered a way to enhance ELMAH itself, because allows you to hide the point were you usually check for errors (elmah.axd) and to move this check point in another centralized, and possibly less exposed from a security perspective, web application.

Updated