Let's see how ElmahR is structured with a couple of diagrams.
The first one illustrates a scenario where 4 source applications are posting to a common dashboard:
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:
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.
ElmahR is made of modules, which we can see in the following pictures (ElmahR word has been removed from the modules names for brevity):
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.
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
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
- applications advertising
- errors notification and error details management
- statistics computation and broadcasting
- applications and error types broadcast (de)activation
- client side extensibility
- 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 offers 3 ways to extend its behavior and enrich a dashboard with new features:
- Modules: a module (implementation of
- 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 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.
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.