Using a library like log4net is surely helpful in your day to day app development. One of the most important cases where an entry should be logged is an application exception occurring on the production environment. It’s quite common to use Windows’ event logs as a storage for log entries and log4net has a special appender which is used in this cases called simply EventLogAppender. All it does by default is appending an entry to the Application event log using a parametrized event source name. It does not set an event id or a category of the entry, disabling a simple querying of entries by this param. There are imperative ways of adding one, like by adding an element EventID or Category to a dictionary log4net.ThreadContext.Properties. This makes you either wrap each call to log4net with a proxy (it’s useful and may be used in your project) or pollute your code with plenty of a logging logic. Can it be done in another way?
Filter to the rescue
It’s not quite hard to provide a better, separated way of enhancing your log entries on the information based on the exception object being thrown. One of them is using a filter, which has an ability to access an exception by a LoggingEvent instance. A simple code of doing it can be found in the following gist.
As you can see, the consts of EventID and Category are stored in the filter’s implementation as the original EventLogAppender uses inline consts to check them. Once their added they will be used by the mentioned EventLogAppender to mark the given entries with EventId and Category. The logic of determining them is up to you. You can hash the exception stacktrace, use an exception’s source property or something else. At the very end remember to add this filter to your appender. Happy logging!
Imagine, that you’re requested to allow adding additional validation in an ASP MVC application to properties of some models. The set of properties’ types is given and contains following types: string, int, DateTime, a reference to a glossary entity. The business (why?) scenario is irrelevant and will be not exposed here.
To allow MVC work nicely there are multiple ways to resolve this case. The following ways may be used:
- a custom ModelValidatorProvider implementation can be provided, which takes the validation information saved in some storage and applies to
- an extension to TypeDescriptor facilities, to add attributes to the specified properties
But how to store this information, being given a meta description (types and their properties already mapped to entities in a database). The first take was to provide an abstract class Validator and try to subclass it with a fully descriptive design, allowing saving any type of parameter, with any kind of operator. You can imagine how many enums, objects (not so strongly typed API) it created.
The “what for?” question arose. Being given a set of types and possibilities of their validation why not to provide validators tightly coupled to those types? If the set of validated types is frozen, the switches can be easily replaced with visitors (very stable hierarchy), which can easily transform the given data into sth which may be used by MVC.
Having your information about validators correlated with types, which should not be changed in a while, allows you for easier editing and storing (no more operators, objectly typed properties). The transformed values can be easily applied via ModelValidator or added as attributes to the TypeDescriptor of the given model. This approach creates a simple pipeline with a possibility of getting the procession result in any moment and inject it in the framework (ASP MVC) in a preferable way.
As it was described in the previous entry, the idea of the action providers is to allow to gather cross-cutting concerns into more generic (not in the C# terms, but functionalities/features) bag than a derivation from a generic controller. To provide a working example, a standard CRUD operations can be taken into the consideration. Let’s take a look into another gist.
I do hate static code, but for sake of a simplicity all the CRUD operations were moved to a static class, CrudActions. All of them are pretty simple, as they use an entity model binder introduced in the former blog entries. For instance, when an entity edit result is posted to the server, a model binder will take care of updating the entity, so the entity being passed to the [HttpPost]Edit will be already altered with the changes made by a user.
The very second step was discovering all of the CrudActions. It is made by a DetachedActionProvider which caches information in a ReadWriteCache taken from the MVC internals. To close the open generic of CrudActions, an entity type with an id’s type is needed. The entity type information is retrieved from a IEntityController, which is a simple markup convention (you can come up with a name convention, or delegate it somewhere else), for attaching to a controller a handled entity type. The id metadata are gathered from the NHibernate’s ISessionFactory. Once the data are retrieved, the CrudActions generic class definition can be turned into a closed generic and the specific method can be found.
Wait a second… how do we transform a MethodInfo into an ActionDescriptor? First, the method infos are wrapped with an ActionInfo instance (it caches attributes as well as the method info itself). Next, the ActionInfos, those who applies (HttpGet, HttpPost, etc.), are passed to the ReflectedMvc to create a ReflectedActionDescriptor.
At the end I left some bitterness about MVC internalization policy. I must admit, that I don’t understand internalizing types or constructors or any members which could be helpful for future app development. That case applies to the ReflectedActionDescriptor ctor, which (the public one) throws an exception if the method passed to it is a static method. The other, non-checking one, is of course internalized. I’m asking: why? The internalization should be used as a last resort, no as a ‘hide it, because I cannot predict if someone doesn’t want to crush MVC in his project’ rule.
Hope you like the action provider extension point and will use it for cross-cutting, ‘I can compose, not only derive from a generic class’ actions in your controllers.