Wiring up an event-message handling service

Recently, in a project I’m working on, I needed to create a service that would allow me to monitor what was going on in the application. In this case, log file info wasn’t rich enough for the type of analysis required. We wanted a contextualized view of what was going on at any moment within this application, but also to measure key aspects of its use. In a sense, it would be an implementation of some of the control patterns reffered to in Architecting Enterprise Solutions: Patterns for High-capability Internet-based Systems (Wiley Software Patterns Series)
, such as the System Monitor.

Lately I’ve been looking at and quite interested in CQRS. I like the concept and what it offers, especially when used with event sourcing. Unfortunately, I haven’t been able to apply it for many reasons, namely lack of experience with it and time to focus on learning how to do it, especially considering the need for features in a time constrained production application. For this particular case, though, I considered I could use some of the concepts to get to a solution that’ll do what I want.

The Requirement

I currently have an application that handles a specific business domain. I want to capture information about what is going on within the application – what business processes are running, etc – and also capture usage statistics – processing time, number of calls, etc – in order to identify bottlenecks and allows allow managers to focus our team’s sprints on the most used aspects (especially if there are problems with them).

Also, I find it very important not to polute my business logic code with monitoring concerns – I believe the business logic code should be clean and simple and as close to the domain as possible. Therefore, I consider that capturing this information should be somehow connected to an application-level service external do the domain code (possibly inserted through IOC-based interceptors), and the processing of this information should be in an external process.

The next diagram provides an overview of what I want:

High level design / context blocks

High level design / context blocks

CQRS includes a concept of event-handling mechanisms that can populate read models. Event processing services handle domain-emited events, and use that event information to update a model designed  to match the presentation layer’s requirements. In my case, I’m considering capturing events (both domain-specific or application-specific depending on what I need) that my application publishes . These events will be represented as messages passed through a comunication channel, with an endpoint that could be a web service (RPC style) or a subscriber on a message bus. The subscribing endpoint is a new context where the event messages will be consumed and processed to update the read model. The read model will be designed to optimize the reads by a GUI for dashboards and/or reporting. This data doesn’t need to be updated in real time, so the processing associated to the messages can be done asyncronously and throttled if necessary, although care may be needed in dealing with the order of the event-messages.

A high level view of the monitoring context is present in the next diagram.

High Level view of the monitoring event processing context

High Level view of the monitoring event processing context

The flow is quite simple, really. Event messages are published to the channel that our monitoring context is subscribed to. We’ll have an channel adapter on our endpoint to enable to correctly connect the service technology to the channel. The message is passed to a process manager that has a certain “saga” aspect to it, not so much for the state machine like nature, but because it controls the processing lifecycle or flow. The processor will request from the factory the handler objects that can handle whatever event type was passed in to the service. The factory will use a handler registry of some sort to figure out who can handle the request. The processor will then call each usable handler to handle the event. Each handler will do something to the information, updating the read model with some new state.

The handlers are, in this case, independent classes that can handle one or more event types. The handlers should be dedicated to some restricted aspect of the information we wan’t to capture, and only handle the event types that will be usefull to produce that information. The more independent the handlers are of each other, the better, as we’ll avoid concurrency details, and parralelism will be obtainable. Also, event message object should be immutable, to avoid state change within the handlers.

A great thing about this is since you can have more than one handler handle a specfic event type, each handler will only be concerned about some part of the event’s data and will do only a smaller, focused calculation. Algorithms and handling code should be simpler, even though there may be a large volume of these created in the context.

To cover the implementation, I’ve set up a sample solution, hosted at Github . It’s based on a spike I originally used to produce the solution. I recommend cloning and opening up the solution to follow along.

Domain Event Message Objects

First lets take a look at the domain event message objects. They are basicaly POCOS, all based on an abstract Event class, and grouped into a library that can be shared across applications / contexts, to simplify the code base. Note that it is not necessary to share this library – since we are passing information across bounded contexts (from the domain app to the monitoring app), our language between contexts can change. In that case, a seperate library ou message parser would be used to capture the data that is in a message. Nontheless, because our sample event classes are very simple, we’ll just share the library in the example project. Sharing would probably be done though NuGet packaging.

Here’s the code for the abstract base Event class:

[DataContract]
[KnownType("DerivedTypes")]
public abstract class Event
{
   ///<summary>
   /// Unique Id Event
   ///</summary>
   public Guid Id { get; private set; }

   ///<summary>
   /// DateTime the event was created
   ///</summary>
   public DateTime CreatedAt { get; private set; }

   ///<summary>
   /// Base constructor for Events. Initializes Id and creation time
   ///</summary>
   public Event()
   {
      Id = Guid.NewGuid();
      CreatedAt = DateTime.UtcNow;
   }

   //... type resolution for known types next ...
}

All it hase is a Guid and a DateTime that describes and distinguishes each individual event. They are set through the constructor when the object instance is created. Because event POCOs must be serializable, I’ve added the DataContract attribute to the class. Also, since Event is abstract, we actually need to be able to (de)serialize derived types, so the KnownType attribute was also added. Typically, you add a reference to specific known types, but since we need them to be discovered ar runtime, a method name is passed to KnownType, that is a private member of the Event class:

        #region Known types resolution

        //-Next block: known types resolution based on :
        //http://stackoverflow.com/questions/16220242/generally-accepted-way-to-avoid-knowntype-attribute-for-every-derived-class

        /// <summary>
        /// This method is used to scan assemblies and get all known types with
        /// Event as it's base, inorder for service deserialization to work
        /// correctly
        /// </summary>
        /// <returns></returns>
        private static Type[] DerivedTypes()
        {
            return GetDerivedTypes(typeof(Event), Assembly.GetExecutingAssembly()).ToArray();
        }

        /// <summary>
        /// Gets types -> can be moved to a utilizty class
        /// </summary>
        /// <param name="baseType"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        private static IEnumerable<Type> GetDerivedTypes(Type baseType, Assembly assembly)
        {
            var types = from t in assembly.GetTypes()
                        where t.IsSubclassOf(baseType)
                        select t;

            return types;
        }

        #endregion

DerivedTypes() searches and returns all types that derive from Event. The GetDerivedTypes() is reusable and can be moved to a framework level class.

Next, we have the ProcessStarted class, a sample domain event, that describes a (domain) process that was initiated, somewhat like a long-running process (but could be any type of process really).

[DataContract]
public class ProcessStarted : Event
{
   ///<summary>
   /// The Id of the process that was started
   ///</summary>
   public Guid ProcessId { get; private set; }

   ///<summary>
   /// The Id of the specific process type
   ///</summary>
   public Guid ProcessTypeId { get; private set; }

   /* Include any other relevant properties here like process name, user, etc, etc..*/

   ///<summary>
   /// Creates and object that describes an event related to some process being initialized
   ///<param name="processId">The processId for the process that was started</param>
   ///<param name="processTypeId">The type of process that was started</param>
   ///</summary>
   public ProcessStarted(Guid processId, Guid processTypeId)
      :base()
   {
      ProcessId = processId;
      ProcessTypeId = processTypeId;
   }
}

In this case, it adds a ProcessId guid and a ProcessTypeId guid to the event class. The ProcessId is an individual process identifier, and anything related to the process request will share this id. The ProcessTypeId is for categorizing the process types. Any other relevant properties could be added to the event POCO that describes the event. The source code also includes a ProcessEnded class that can represent an event to be emited at the end of the process, with details about how long the process ran and if it ended with errors.

All in all, they are simple POCOS that can be serialized and transfered on the wire to the monitoring context. There, the data in them will be handled by event processors. Once again, serialization is a concern, and each derived type from Event will require the DataContract attribute.

Note: I believe that the DataContract / serialization atrributes are the only infrastructure concerns attached to these classes. Whether that is acceptable or not is up for debate. If it were possible to remove these, or better yet, move them to an infrastructure / application level, then the application could decide what type of serialization mechanisms and attribute types to use. This is really only to point out that, lets say, if I wanted to use MessagContract attributes, or XmlElement attributes for the serialization, I would have to change the domain classes or at least their decorators. Seems to me to be a bit os a violation of the Open-Closed Principle...

A Look at the Event Processors

The event processors are classes that are marked to handle specific groups of events. Each processor handles whatever event types it needs to get its job done, and this is done by implementing the open-generic interface IHandleEvent<TEvent>.

The source code for this part is made up by three projects. There is a very small and generic “EventProcessing.Framework“, that defines the previously mentioned IHandleEvent<> interface:

public interface IHandleEvent<TEvent> where TEvent : Event
{
 void Handle(TEvent @event);
}

The interface is very focused, and only demands the Handle() method. It also restricts handled types to Event derivatives. Our framework also contains a IProcessEvents marker interface and the Entity abstract base class. Entity here might not be a good name. I consider the inheriting classes to be a sort of aggregate roots withing my monitoring context (although my understanding of ARs might be hindered here by my lack of experience with correct DDD – please correct me if I am wrong). Entities, in this framework library, contain only an externally set id, passed in to its constructor. These three classes are grouped into their own library for reuse.

The other two projects associated to the monitoring  context are the DomainAEventProcessors library and the associated unit test library. This library has a DailyActivityEventProcessor that determines the number of active processes at the moment, and a ProcessTypeCounterEventProcessor that counts processes by type. Both can be used to update the read model used by a dashboard UI. Both retreive data of an entity (or AR), act on it by calling commands, and persist it through an IRepository<TEntity> implementation.

Lets look specifically at the DailyActivityEventProcessor class. Because it is an event processor, it implements the marker interface IProcessEvents, and also handles ProcessStarted and ProcessEnded event types:

 public class DailyActivityEventProcessor :
        IProcessEvents,
        IHandleEvent<ProcessStarted>,
        IHandleEvent<ProcessEnded>
    {
        private IRepository<DailyActivity> repository;

        public DailyActivityEventProcessor(
            IRepository<DailyActivity> repository
            )
        {
            Condition.Requires(repository, "repository").IsNotNull();

            this.repository = repository;
        }

        //...

The IRepository<DailyActivity> implementation is injected at construction, and the implementation will typically be associated to some storage type (SqlServer, MongoDb, etc.). The Handle() methods have straightfoward implementations, getting the current entity state from the repository, executing a command on it, and storing it again. There are obviously concurrency considerations to have, but I am not yet applying them here to simplify the example.

        public void Handle(ProcessStarted @event)
        {
            string id = DailyActivity.GetIdFrom(@event.CreatedAt);
            DailyActivity activity = GetOrCreateActivityEntity(id);

            //execute change / update
            activity.AddProcess(@event.ProcessId, @event.CreatedAt);

            //save - persist?
            repository.Save(activity);
        }

        public void Handle(ProcessEnded @event)
        {
            string id = DailyActivity.GetIdFrom(@event.CreatedAt);
            DailyActivity activity = repository.Get(id);   //should exist for this event

            if (activity != null)
            {
                //execute change / update
                activity.EndProcess(@event.ProcessId, @event.EndTime, @event.WithError);

                //save - persist?
                repository.Save(activity);
            }
        }

The DailyActivity class contains an internal dictionary to store process statuses keyed by id, and has a set of properties that determine, based on the dictionary’s data, the number of active processes. Because it is a daily record, the id for the entity is simply the date the process was executed, converted to string.

    public class DailyActivity : Entity
    {
        public int ActiveProcesses {
            get { return TotalProcessCount - CompletionCount; }
        }   //number of active work orders (snapshot count - could also be calculated if need be)

        public int TotalProcessCount {
            get { return statuses.Keys.Count; }
        }
        public int CompletionCount {
            get { return statuses.Values.Count(o => o.EndedAt.HasValue); }
        }

        public int CompletedWithErrorCount{
            get { return statuses.Values.Count(o => o.EndedWithError); }
        }

        private Dictionary<Guid, ProcessStatus> statuses = new Dictionary<Guid, ProcessStatus>();

        public DailyActivity(string id)
            :base(id) {
        }

        public void AddProcess(Guid processId, DateTime startTime)
        {
            statuses.Add(processId, new ProcessStatus(startTime));
        }

        public void EndProcess(Guid processId, DateTime endTime, bool withErrors)
        {
            if (statuses.ContainsKey(processId))
            {
                statuses[processId].Complete(endTime, withErrors);
            }
        }

        /// <summary>
        /// Creates Id's for the entity
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string GetIdFrom(DateTime date)
        {
            return date.ToString("yyyy-MM-dd");
        }
    }

Notice that the class has two methods that allow for command-sytle calls – AddProcess() and EndProcess(). These essentially update the process list, which alters the entities properties.

 Dispatching Events to Handlers

Now that we have events and event processors, it’s time to wire everything up. Alot of what needs to be done isn’t so much a domain specfic aspect of the monitoring context, but more of an infrastructure’s concern. Because of this, I’ve tried to do as much as possible with the IOC container (which in this case will be Castle Windsor). Also, to support the service, I’ll be using a WCF service, with the endpoint based on a HTTP binding for SOAP messages, but any other type of service could be used.

First thing I’ll add is the dispatcher, that will get handlers for a specific event type from the registry, and call Handle() on each of them with the event as an argument. I’ll add this to the framework since it is reusable. The dispatcher implements a very simple interface:

public interface IEventDispatcher
    {
        void DispatchEvent(Event @event);
    }

And has a quite a simple implementation:

    public class EventDispatcher : IEventDispatcher
    {
        private IHandlerFactory factory;

        public EventDispatcher(IHandlerFactory factory)
        {
            Condition.Requires(factory, "factory").IsNotNull();

            this.factory = factory;
        }

        public void DispatchEvent(Event @event)
        {
            IEnumerable<dynamic> eventHandlers = factory.GetHandlersFor(@event);

            if (eventHandlers != null && eventHandlers.Any())
            {
                Parallel.ForEach(eventHandlers, handler => handler.Handle((dynamic)@event));
            }
        }
    }

Do take note of a couple of things:

  • The EventDispatcher implementation gets a IHandlerFactory injected. The factory can be implemented in many ways, basing it on a static mapof types to handlers, or using IOC related functionality.
  • GetHandlersFor() returns an IEnumerable<dynamic>. The fact that we are using open generics (the IHandle<> interface), complicats things slightly, and requires us to use dynamics. Types will be resolved at runtime. This was one of the aspects where I got lost for the most part due to lack of use.
  • We are using a Parallel.ForEach to iterate through the handlers, because they are independant (or at least we implement them as such). This is an advantage of using simple, independent handler implementations.

The handler factory is also quite simple, and reinforces the dynamic nature of the handlers:

    public interface IHandlerFactory
    {
        IEnumerable<dynamic> GetHandlersFor(Event eventHandler);
    }

The dispatch mechanism is testable:

        [Test]
        public void DispatcherDispatchesEventsToHandlers()
        {
            Mock<IHandleEvent<EventThatHappened>> handler1 = new Mock<IHandleEvent<EventThatHappened>>();
            handler1.Setup(o => o.Handle(It.IsAny<EventThatHappened>())).Verifiable();

            Mock<IHandleEvent<EventThatHappened>> handler2 = new Mock<IHandleEvent<EventThatHappened>>();
            handler2.Setup(o => o.Handle(It.IsAny<EventThatHappened>())).Verifiable();

            Mock<IHandlerFactory> factory = new Mock<IHandlerFactory>();
            factory.Setup(o => o.GetHandlersFor(It.IsAny<EventThatHappened>()))
                .Returns(new List<dynamic>()
                {
                    handler1.Object as dynamic,
                    handler2.Object as dynamic
                });

            EventDispatcher dispatcher = new EventDispatcher(factory.Object);

            dispatcher.DispatchEvent(new EventThatHappened());

            handler1.Verify(mock => mock.Handle(It.IsAny<EventThatHappened>()), Times.Once);
            handler2.Verify(mock => mock.Handle(It.IsAny<EventThatHappened>()), Times.Once);
        }

Here, two mock handlers where created for a fake event. The factory returns both mocks when called, and we verify that each handle method was called.

Using Castle to Resolve Handlers

I only added the IHandlerFactory interface to the framework, but no implementation for it. We can implement this factory in a couple of ways, but a really clean and interesting one is to use the IOC container. Castle Windsor has an AsFactory() method that proxies factory classes and registers them in the container. The only extra work is to create a selector definition when the default selection method is not usefull.

I’ll start by adding the service application, which I mentioned is a WCF service (application) and that I’ll call MonitoringService. It’ll have a single service endpoint (MonitorService.svc) that implements the IMonitor ServiceContract:

    [ServiceContract]
    public interface IMonitor
    {
        [OperationContract]
        [ServiceKnownType("RegisterKnownTypes", typeof(ServiceKnownTypeRegister))]
        void ReceiveEvent(Event value);
    }

Because Event is abstract and we need to deserialize it’s derived types, the ServiceKnownType attribute was added, and known types are to be discovered via a RegisterKnownTypes() method on the ServiceKnownTypeRegister class:

    public class ServiceKnownTypeRegister
    {
        //-Next block: known types resolution based on :
        //http://stackoverflow.com/questions/16220242/generally-accepted-way-to-avoid-knowntype-attribute-for-every-derived-class
        // and http://stackoverflow.com/questions/3044078/provide-serviceknowntype-during-runtime

        /// <summary>
        /// This method is used to scan assemblies and get all known types with
        /// Event as it's base, in order for service deserialization to work
        /// correctly
        /// </summary>
        static public IEnumerable<Type> RegisterKnownTypes(ICustomAttributeProvider provider)
        {
            List<Type> types = new List<Type>();
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

            foreach(Assembly assembly in assemblies)
            {
                types.AddRange(GetDerivedTypes(typeof(Event), assembly));
            }

            return types;
        }

        /// <summary>
        /// Gets types -> can be moved to a utilizty class
        /// </summary>
        /// <param name="baseType"></param>
        /// <param name="assembly"></param>
        /// <returns></returns>
        private static IEnumerable<Type> GetDerivedTypes(Type baseType, Assembly assembly)
        {
            var types = from t in assembly.GetTypes()
                where t.IsSubclassOf(baseType)
                select t;

            return types;
        }
    }

Like what we did for the Event class DataContract, we’ll scan the assemblies and discover any and all registered Event derivatives as deserialization candidates for the @event argument of the ReceiveEvent() service method. GetDerivedTypes() is repeated here, but could be moved to some utility or framework level library.

Back to wire-up: we need to do a couple of things to get Castle to control object instanciation in the WCF application. First, we need to create the container, in order to have a composition root, which we’ll do in a ContainerManager static class:

    public static class ContainerManager
    {
        private static IWindsorContainer _container;

        static ContainerManager()
        {
            _container = new WindsorContainer()
                    .AddFacility<WcfFacility>()
                    .AddFacility<TypedFactoryFacility>();

        }

        public static void CallInstallers()
        {
            _container.Install(FromAssembly.InThisApplication());
        }

        public static IWindsorContainer Container
        {
            get
            {
                return _container;
            }

        }
    }

It needs to be instantiated in the global.asax:

        protected void Application_Start(object sender, EventArgs e)
        {
            ContainerManager.CallInstallers();
        }

The ContainerManager creates a new WindsorContainer and adds a couple of facilities we will need, namely the WcfFacility for WCF integration, and the TypedFactoryFacility to create factories. It is created once, at application start (right before we call the CallInstaller()s method), and then registers all the dependencies that need to be resolved by calling each available installer in the application (when the CallInstallers() method is calles). We create it in Application_Start() from the global.asax because we are using an HTTPversion of the service. In other scenarios the HttpApplication is not available. Still, somewhere at application start, the container should be created and items registered for resolution.

By considering our implementation for IMonitor, we can pretty much get to every component we will need to register.

    public class MonitorService : IMonitor
    {
        private IEventDispatcher dispatcher;

        public MonitorService(IEventDispatcher dispatcher)
        {
            Condition.Requires(dispatcher, "dispatcher").IsNotNull();

            this.dispatcher = dispatcher;
        }

        public void ReceiveEvent(Event @event)
        {
            dispatcher.DispatchEvent(@event);
        }
    }

MonitorService‘s ReceiveEvent() implementation does only one thing – call the dispatcher’s DispatchEvent() to pass the event to the handlers. The class will therefore require an IEventDispatcher to be injected. MonitorService will no longer work with a default constructor, so we need to change the .svc so that Castle can handle service instantiation:

<%@ ServiceHost Language="C#" Debug="true"
    Service="MonitoringService"
    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
     %>

The ServiceHost directive now has the Service attribute that names the service, and a Factory attribute that determines that Windsor will create the service intstances.

With this in mind, let’s consider the set of dependencies:

  • The container should resolve IMonitor as MonitorService.
  • MonitorService requires an IEventDispatcher, resolved to EventDispatcher.
  • EventDispatcher requires a IHandlerFactory, that will be based on Castle’s typed factories.
  • The handler factory will be creating IHandleEvent<> instances, so we will need to register all those that are available.
  • The handlers require IRepository<>, so we will need to register those available, and possibly consider conventions for selecting repository types.

I like to split the statements associated to Installers into diferent files, depending on their focus. In this case there are three. The first is the ServiceInstaller.cs that registers IMonitor, IEventDispatcher and IHandlerFactory:

        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<IMonitor>()
                    .ImplementedBy<MonitorService>()
                    .Named("MonitorService")
                    .LifeStyle.HybridPerWebRequestPerThread()
                );

            container.Register(
                Component.For<IEventDispatcher>()
                    .ImplementedBy<EventDispatcher>()
                );

            container.Register(
                Component.For<ITypedFactoryComponentSelector>()
                    .ImplementedBy<HandleEventFactorySelector>());

            container.Register(
                Component.For<EventProcessing.Framework.Tests.Dispatch.IHandlerFactory>()
                    .AsFactory(c => c.SelectedWith<HandleEventFactorySelector>())
                );
        }

Notes about this installer:

  • IMonitor is registered with a name. The name is used by HostFactory to resolve the service implementation and should match the name in the .svc file.
  • IEventDispatcher registration is straightfoward
  • IHandlerFactory registration is two-step. We use the .AsFactory() extension method to create the factory. We also register an ITypedFactoryComponentSelector to be used by the factory to contain the logic required to select the types to be used.

Because we are using open generics, and because we need to do casting, we can’t rely on Castle’s default factory selectors to resolve the instances. HandleEventFactorySelector, a class we have defined, will be used as the selection mechanism for the factory:

    public class HandleEventFactorySelector : DefaultTypedFactoryComponentSelector
    {
        protected override Func<IKernelInternal, IReleasePolicy, object> BuildFactoryComponent(
            MethodInfo method,
            string componentName,
            Type componentType,
            IDictionary additionalArguments)
        {
            return (k, s) => k.ResolveAll(componentType).Cast<dynamic>(); // as IEnumerable<dynamic>;
        }

        protected override string GetComponentName(MethodInfo method, object[] arguments)
        {
            return null;
        }

        protected override Type GetComponentType(MethodInfo method, object[] arguments)
        {
            var message = arguments[0];
            var handlerType = typeof(IHandleEvent<>).MakeGenericType(message.GetType());
            return handlerType;
        }
    }

The selectors are quite an interesting piece of code. It inherits from DefaultTypedFactoryComponentSelector, so that you only need to override whatever part of the default selector needs to be channged. For our factory, three methods need to be changed: GetComponentName(), GetComponentType(), and BuildFactoryComponent(). The factory usually calls the three methods (in that order, which can be debugged), and gets the name and type of the components we want to resolve. Finally, it gets the anonymous function that resolves the types based on the input. I’ve added a few overrides:

  • Since we want to resolve IHandleEvent<> based on the event type, we won’t be resolving components by name. Therefore we force GetComponentName() to return null, forcing the name component to be ignored.
  • We do want to resolve by type, based on the event type. Therefore, GetComponentType() creates a Type of IHandleEvent<>, and makes it a generic of the event type.
  • Since our factory will be returning multiple instances, instead of a single instance, BuildFactoryComponent() returns a delegate that calls the container’s ResolveAll(), for the type we determined, and casts each one to dynamic. The cast is important, and without it, we’ll get null instances or runtime errors.

This bit of logic – the selector and the AsFactory() – allows us to use our IOC container as the handler registry, and it will take care of creating the instances of the handlers we need to handle the received events.

We still need to register the handlers though. The associated logic is in HandlerInstaller.cs:

        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            /// ref: http://simpleinjector.codeplex.com/wikipage?title=Castle%20Windsor

            container.Register(AllTypes.From(
                AppDomain.CurrentDomain.GetAssemblies()
                    .Where(a => !a.IsDynamic) //dynamic assemblys don't export types...
                    .SelectMany(a => a.GetExportedTypes()))
                .BasedOn(typeof (IHandleEvent<>))
                .Unless(t => t.IsGenericTypeDefinition)
                .WithService.Select((_, baseTypes) =>
                {
                    return
                        from t in baseTypes
                        where t.IsGenericType
                        let td = t.GetGenericTypeDefinition()
                        where td == typeof (IHandleEvent<>)
                        select t;
                }));
        }

I based this installer code on a bit I found in SimpleInjector’s documentation. Basicly, what it is doing is going through all the loaded assemblies and registering any IHandleEvent<> it finds, with some extra filtering and an added selection delegate. This code could be changed to load assemblies in a specific folder, as if they were plugins, and the app would not need to know about them at compile time.

Finally, because our handlers require repositories, we’ll install them.

        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For(typeof(IRepository<>))
                    .ImplementedBy(typeof(InMemoryRepository<>))
                );
        }

Castle in this case can automaticaly resolve the generic type, since we have been explicit about that in the handler constructors. We’ll use a very simple InMemoryRepository implementation added at the application level. In pretty much all of the installers, we’ve omitted lifestyle definitions. Castle by default creates singletons, which for our current setup is ok.

At this point , everything is setup and we can run the app and accept events.

Testing the WCF Service

A great way to create an acceptance test (or at least something that tests the deserialization mechanism) is to throw SOAP messages at a running instance of the service (debug mode works well for this). I like to use SOAP UI for this type of verification.

The most important aspect to consider in our requests is the message format and extra elements to include to support deserialization automatically, using WCFs deserialization mechanisms. A sample request for a ProcessStarted event looks like this:

<soapenv:Envelope
	xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:tem="http://tempuri.org/"
	xmlns:mon="http://schemas.datacontract.org/2004/07/DomainA.Events"
        xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
	>
   <soapenv:Header/>
   <soapenv:Body>
      <tem:ReceiveEvent>
        <tem:event i:type="mon:ProcessStarted">
                <mon:Id>c82e3c2a-0ae6-47f5-9306-fceeca08f029</mon:Id>
                <mon:CreatedAt>2014-07-07T12:00:00</mon:CreatedAt>
                <!--ProcessStarted specific:-->
         	<mon:ProcessId>f26278cc-19cc-4997-a507-a7af42d9793c</mon:ProcessId>
         	<mon:ProcessTypeId>00000001-0000-0000-0000-000000000000</mon:ProcessTypeId>
         </tem:event>
      </tem:ReceiveEvent>
   </soapenv:Body>
</soapenv:Envelope>

SOAP UI will generally create requests based on the WSDL, but won’t include specifc event type properties into the sampel request. I’ve highlighted lines 4 and 5 since they are the aditional namespaces that were added (:mon for the domain events and :i for the type attribute), and at line 11, where the event properties are defined, the type attribute specifies that it is a ProcessStarted event object. That will aid the deserialization process.

Executing the request will generate response with a SOAP envelope and a body, though the response object will have no content because the method has a void return type. Do note that since we are using an in-memory repository, with a singleton lifestyle, multiple calls with the same event (por at least the same processId) will generate an exception. Still, with this request you can debug and /or view the call lifecycle.

Concluding Notes

This pretty much wraps it up. We’ve made it quite far, with a complete implementation. We have created an architecture that suppports creating new event types, and handlers for those types, and automaticaly registering them in the application when the application starts up. Also, this architecture allows us to do multiple types of calculations and processing, in parrallel, based on the same set of events.

In my opinion, the various aspects are correctly segregated, and seperation of concerns is considered:

  • Event descriptions are in their own library and can be shared across projects;
  • Processors are seperated and can be organized in diferent libraries based on the events they handle or on what they are focused on;
  • Base classes and interfaces are in framework level libraries and can be reused across projects;
  • Infrastrutucure-classes are defined and attached at the application level.

Resharper’s architecture graph shows the following graph that describes the previes list of notes:

Architecture Graph For DomainEvents

Nonetheless, there are plenty of improvements that can be added. Some that occur to me are:

  • Out-of-order message handling (like getting a ProcessEnded event message before a ProcessStarted message for the same processId)
  • Handle repeated messages (what if a specific ProcessStarted message arrive twice?)
  • With calculations like those in DailyActivity, how do you handle processes that start in one day, and end on the next? (this is probably more a handler specfic concern then the framework’s concern…)

 Suggestions for Improvements?

I wanted to post this article and solution for a couple of reasons. First, it was kind of tough to get this setup, especially due to the use of dynamics, open generics, and some of Castle’s features that I wasn’t used to using. Once it is put together, though, everything makes sense. It did help me get a better understaning of how Castle works, and also some good uses for C# features.

Still, this is a type of design that is kind of new to me, especially from a usage point of view (I’ve been looking in to it a lot lately, just this is the first time I’m actually using it). Therefore, any suggestions and improvements are highly apreciated and welcome.

The source code for what I have presented here is on GitHub (https://github.com/MiguelAlho/C–Event-Processors-Example) and can naturally be cloned for use.

 

Passwords “insonsas”

Um dos pontos fulcrais na segurança de um site é a gestão de passwords dos utilizadores.Sempre que nós como programadores implementamos um sistema de autenticação que recorre a nome de utilizador e password, temos de ter cuidados especiais. Vulnerabilidades que desconhecemos nos nossos sistemas podem comprometer a base de dados e tornar o seu conteúdo acessível.

Se considerar-mos os hábitos de utilizadores, nomeadamente a reutilização frequente de palavras passe, a descoberta de uma palavra passe num local poderá facilitar o acesso a dados do utilizador noutros locais e sistemas. Agentes maliciosos utilizam ataques para obter este tipo de informação devido ao seu valor. Ainda recentemente houve o ataque ao Linkedin, e a publicação da informação de passwords dos utilizadores. É portanto necessário tomar medidas, não só para preservar a segurança dos dados, mas garantir que o acesso a elas não crie novas vulnerabilidades.

Em circunstância alguma devemos armazenar a palavra passe do utilizador na base de dados num formato legível! Se considerar-mos o funcionamento de websites e aplicações, as únicas situações que necessitaria-mos de ter a password original do utilizador numa aplicação seria para reutiliza-la na autenticação a um serviço externo, caso utilizássemos o serviço em representação do utilizador. Mas o risco associado não justifica a prática – a troca de outro tipo de chaves de autenticação é mais seguro para o utilizador. Um exemplo são as autorizações em aplicações de sites como o Facebook: a passe do utilizador não é transmitida, apenas uma chave complexa que autoriza o acesso pela aplicação.

Técnicas para ofuscar a password

Mas e a autenticação no próprio site?! A autenticação no site é efectuado através da comparação da password do utilizador, inserido no formulário de autenticação, e a password armazenada. Recorrendo a um exemplo simples, para ver o funcionamento, imagina que o nosso user José Silva utiliza uma password simples e comum “qwerty”. No formulário ele introduz o username e password, e quando clica para fazer o login, procuramos o registo dele na base e comparamos as passes. Se coincidirem:

if(formData["password"] == dbData["password"]){ ...

o utilizador passa a ter acesso ao site/aplicação. No (semi-pseudo)código, o formData representa os dados vindos do formulário e o dbData os dados provenientes da base de dados.

O erro que alguns programadores inconscientes destes problemas têm é não compreenderem que esta comparação não tem de ser efectuada com as versões originais da passe. Na verdade, podemos e devemos usar a versão codificada da passe, conhecida por “hash” (ou escrutínio, mas a palavra em inglês é bem mais agradável). Ou seja, a partir do momento que o utilizador regista a sua conta, o que deve ser armazenado é uma versão codificada da passe, e utilizando o um algoritmo que permita apenas a codificação num sentido (impedido recuperar o original por processamento inverso). Se recorrermos a um algoritmo como o MD5 ou o SHA-1 a password fica armazenado num formato críptico e bem mais difícil de descodificar. (Nota: o SHA-1 e MD5 hoje em dia não são suficientemente seguros, já que com a capacidade de processamento disponível, a descodificação por ataques de dicionário ou força bruta são viáveis).

Vejam a mesma passe em ambos os formatos:

MD5: "qwerty" => d8578edf8458ce06fbc5bb76a58c5ca4
SHA-1: "qwerty" => b1b3773a05c0ed0176787a4f1574ff0075f7521e

A comparação no método de autenticação passa então a ser entre versões codificadas da mesma palavra, em vez da versão original da palavra:

if(MD5.codificar(formData["password"]) == dbData["password"]){ ...

Apesar de ser muito melhor, e mais seguro que o armazenamento em texto livre da password, não é suficientemente seguro. Existem tabelas com as palavras codificadas pré-calculadas (lookup tables e rainbow tables) que permitem comparação para obter os valores originais, e mesmo a capacidade de processamento actual do hardware disponível permite efectuar o cálculo por força bruta (este a todas as combinações possíveis) em tempo útil.

Um pouco de sal

Uma técnica importante para contrariar o uso de tabelas de lookup consiste em adicionar um pouco de texto adicional à palavra passe, conhecido por um “salt” (daí o trocadilho do sal insonso…enfim…). O facto de acrescentar mais caracteres no inicio e/ou no fim tornará a palavra a codificar mais complexa e comprida, tornando a sua descodificação também mais complexa.

Voltando ao exemplo, imagina que acrescentamos o texto “p@$$wordComSal” no início da password do utilizador, antes de a codificar. Teriamos então:


MD5: "p@$$wordComSalqwerty" => cd17413e25e513690f7c53fbab394e25

O facto de acrescentarmos um termo incomum no inicio da password do utilizador faz com que o uso de dicionários fique inutilizado, uma vez que o dicionário (e as hashes associadas) não terão o salt em consideração. A base de dados terá armazenado a passe codificada com o salt, e a comparação a efectuar será do tipo:

if(MD5.codificar(salt + formData["password"]) == dbData["password"]){ ...

Ainda estou a considerar um salt fixo e geral para o sistema. E mais uma vez, apesar de ser mais seguro que as anteriores, ainda não é o suficiente. Se o salt é descoberto, ataques de dicionário e força bruta passam a ser novamente possíveis, necessitando apenas de recalcular as hashes com o salt.

Aleatoriedade

A melhoria neste processo é possível garantindo que o salt para cada user seja distinto e, preferencialmente, aleatório. Se cada passe tem um salt diferente, a descoberta de um (por força bruta) impossibilita a criação de tabelas de lookup gerais – apenas serviriam para o registo em que foi descoberto. Além disso, as hashes devem ser geradas usando algoritmos mais seguros (SHA256, SHA512, RipeMD, WHIRLPOOL, SHA3) e a criação deverá ser lenta, recorrendo a estratégias de key-streching ( PBKDF2, bcrypt, and scrypt).

A crackstation tem um excelente artigo sobre o tema.

Recomendo a escolha do bloco adequado de código e a integração em frameworks pessoais core para que possa ser usado facilmente.A validação da passe continua com o mesmo processo (apenas escrito de forma adequada às classes fornecidas) :

if(PasswordHash.ValidatePassword(formData["password], dbData["password"])){ ...

O campo de password do utilizador na base de dados passa a ter uma concatenação do número de iterações PBKDF2, o salt, e a hash gerada, separados pelo caracter “:”. O método validate separa as componentes armazenado, aplica a salt à passe submetida (o salt é especifico do utilizador) e compara a hash gerada com a armazenada. O cálculo é demorado (centenas de milissegundos) tornando ataques de força bruta pouco úteis.

É naturalmente importante não esquecer que esta não é a única técnica, e outros métodos devem ser empregues na construção do site / aplicação para anular todos os “buracos” existentes, reduzindo ao máximo e sempre que possível as falhas de segurança.

Beginner’s Guide to PostgreSQL

Acabei de publicar um novo curso de iniciação às bases de dados relacionais em PostgreSQL no Udemy, um site de formação on-line. O curso está dividido em 3 módulos – introdução, criação e manipulação das estruturas de dados, e SQL. Actualmente, tem 18 lições em vídeo disponíveis, e muitas em produção.

O curso está em inglês, e espero que venha a ser bastante útil a muita gente de modo a entrar no mundo desta excelente base de dados.

http://www.udemy.com/beginners-guide-to-postgresql/

I just finished publishing a new beginner’s course on PostgreSQL at Udemy, an online platform for learning. The course has 3 modules – an introduction to relational databases, data structures and manipulation finally SQL. Currently, the course has 18 vídeo lessons and the missing ones are currently in production.

The course is in english, and I hope it becomes very usefull to anyone wanting to enter the world of this amazing database system.

Conferência SerFreelancer

Dia 2 de Abril vou ter o prazer de participar como orador na “Conferência – Ser Freelancer em Portugal”, no IPJ de Aveiro. vai ser certamente um dia muito interessante em que vamos reunir freelancers de diversas áreas, especialmente quem está a começar, para falar dos vários aspectos inerentes ao trabalho como freelancer.

Vou estar na conferência a representar área da programação web e desenvolvimento de software. Tem piada que vem numa altura em que preparo-me para dar o salto do freelancing para a estrutura de empresa. De qualquer forma, não deixarei de partilhar os diversos aspectos da minha experiência como tal. Há sempre muito para dizer, e muitas questões a responder. Até lá, tenho que recuperar a voz!

Espero ver muito pessoal por lá. Se houver tópicos que alguem gostaria que abordasse em especial, deixa um comment!

Mais info em http://freelancerportugal.com/

FATAL: could not reattach to shared memory (key=…, addr=…): 487

FATAL: could not reattach to shared memory (key=276, addr=01F20000): 487

Este é um erro que aparenta aparecer em algumas instalações PostgreSQL em Windows, em especial depois de existir algum update do OS. Uma instalação minha teve este problema, com o erro a ser registado periodicamente nos logs do PostgreSQL. Infelizmente o erro é problemático para aplicações dependentes da base de dados, uma vez que ele interrompe conecções entre a aplicação e a base de dados. É causador de um tipico erro de .NET com mensagem pouco esclarecedora:

[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) +232

Poderia ser de uma coneção externa, mas o pilha de chamadas tinha claramente a biblioteca NpgSQL – o provider PostgreSQL para .NET na lista. Não era uma conecção entre cliente e servidor, mas sim entre a aplicação e o serviço de base de dados (que é efectuado sobre TCP, mesmo estando na mesma máquina).

A solução é a actualização da instalação do serviço de base de dados – este caso passei do 8.4.0 para o 8.4.6. (a correcção deve ter sido introduzido no 8.4.1). Esta versão terá o patch para a correcção deste erro. A actualização é simples: para o serviço e correr o instalador mantendo os dados e configurações intactas (poderá ser necessário recolocar o serviço a arrancar pelo sistema utilizador LOCAL SYSTEM, se necessário).

Info sobre o erro ou patch:
http://blog.hagander.net/index.php?url=archives/149-Help-us-test-a-patch-for-the-Win32-shared-memory-issue.html#feedback
http://www.postgresql.org/docs/8.4/static/release-8-4-1.html

Recuperação de arranque em Windows Server 2008

Pois. Este é um post que representa o meu dia de ano novo. A passagem foi excelente. O tarde após a passagem foi bastante assustador. Aproveitei a “paragem” para fazer uma limpeza ao meu servidor e introduzir uns discos novos. E assim se fez o caos! Passo a explicar…

O meu servidor é relativamente simples e construído às necessidades. É um setup simples com dois discos de ITB em RAID 1 para sistema e repositórios de ficheiros importantes, e mais 3 discos de 640GB para “tralha”. Decidi fazer um upgrade, e acrescentar algum espaço – Ia juntar um disco de 640GB que estava na prateleira parada com uma das existentes num RAID 1 dedicado a backups, e acrescentar um disco de 1TB para mais tralha. Assim, ficaria com um total de 7 discos, representando cerca de 3TB de espaço, estando metade montado em RAID1. Uma unidade separada e dedicada a backups parece-me uma boa aposta, e quero implementar uma forma mais automatizada de os fazer, quer do servidor, da minha máquina e a dos meus colaboradores.

Portanto abri e limpei algum (pouco, felizmente) pó do servidor, e reorganizei a barra de discos que agora ficou completamente cheia. Introduzi o disco antigo que esteve parado (e que ainda tinha uma instalação de OS anterior do servidor, como backup), arranquei a máquina, criei um novo RAID e… O servidor entrou no OS antigo em vez da instalação actual. Arrancou pelo segundo disco em vez do primeiro. E assim o caos começou.

Obviamente não era isso que eu queria. Queria o arranque pelo mesmo OS que deveria estar intacto no DISCO 0. Infelizmente esta troca alterou o esquema de letras de unidades e o sector de arranque do disco principal., Não compreendi porque, infelizmente, mas tornou-se impossível arrancar pela partição de sistema do disco original, mesmo sendo a única unidade fisicamente ligada. Algo… assustador!

Para corrigir tive que arranjar algum método de corrigir, que não envolvê-se reinstalar. Felizmente encontrei alguns comandos que se podem executar para reconstruir o o sector e informação de arranque que passo a explicar. Há “ordem”, de certa forma, nos passos a executar q passo a descrever. Este foi o meu caso e raciocínio, mas obviamente pode mudar caso a caso.

O primeiro passo é introduzir e arrancar o servidor com o disco de instalação do Windows Server 2008. Ele tem ferramentas de recuperação, que podem ser executadas a partir da linha de comandos. Depois de arrancar, deve escolher a opção de reparação. Surge uma janela de escolha de unidade de sistema a recuperar. Infelizmente no meu caso, pelo menos inicialmente, não reconhecia nenhuma partição com uma instalação de sistema. De qualquer forma, escolhendo “NEXT” permite chegar às opções seguintes e nas opções de ferramentas, escolhi a linha de comandos para abrir uma consola. Foi interessante verificar que, mesmo n conseguindo arrancar pelo OS, na consola, o windows ainda reconhecia a estrutura de partições e unidades presente no disco. Escolhendo a unidade C do sistema (>c:) executei o seguinte comando:

bootrec.exe /fixmbr

O comando repara o Master boot record. Em muitas situações este comando ou a combinação com o seguinte:

bootrec.exe /fixboot

Deveria ser suficiente para reparar o arranque. Infelizmente no meu caso não o foi, pois o /fixboot respondeu com a mensagem de erro “Element Not Found”. Este erro significa, essencialmente, que a partição de sistema não está “activa”, e portanto deve ser activado, para o recuperador o encontrar. para tal, uso o DISKPART:


>diskpart
DISKPART>list disk
...
DISKPART>select disk 0
...
DISKPART>list partition
...
DISKPART>select partition 1
...
DISKPART>active
DISKPART exit

Esta sequência demonstra alguns comandos do diskpart. os “list” listam os discos ou partições disponíveis no disco seleccionado. O “select” permite seleccionar e disco e partição desejada. “Active” activa a selecção. Depois de executar estes comandos, e com a partição activa, o bootrec.exe /fixboot executa correctamente e pode ser executado ainda o comando

bootrec.exe /rebuildbcd

Se tudo correr bem, deverá ser suficiente. Infelizmente, no meu caso, não o foi. Isto porque, no arranque, sugiu nova mensagem de erro, mas desta vez a indicar que o BOOTMGR estava em falta : “BOOTMGR IS MISSING”. Mais uma volta… desta vez foi suficiente executar o reparador de arranque no CD de instalação. Infelizmente, e ao contrario do Vista, esta opção não aparece na lista de ferramentas. Para aceder é necessário entrar na consola de comandos e executar:

X:\sources\recovery\StartRep.exe

Este foi o toque final necessário para ficar tudo OK. Pude finalmente concluir e ligar os restantes discos sem problemas dentro do servidor.

Refs:
http://www.lancelhoff.com/how-to-fix-vista-mbr-repair-broken-vista/
http://www.pcstats.com/articleview.cfm?articleid=2264&page=8
http://www.networksteve.com/forum/topic.php/VPN_created_using_modem_-_unable_to_modify/?TopicId=9937&Posts=2

Vulnerabilidade de Segurança em Aplicações ASP.NET

Foi anunciado ontem pela Microsoft uma vulnerabilidade no ASP.Net, associado a códigos de erro enviados pelo servidor para o cliente, e que poderiam servir para o utilizador aceder a ficheiros como o web.config.

No blog do Scott Guthrie, ele refere como funciona a vulnerabilidade e como prevenir. Essencialmente, é necessário reeditar os ficheiros web.config, e configurar de modo a ter os “custom errors” activos. Ele recomenda ainda ter apenas uma página de erro, e injectar algum código no Page_load dessa página:

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="System.Security.Cryptography" %>
<%@ Import Namespace="System.Threading" %>





    


    
An error occurred while processing your request.

O detalhe completo em: http://weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx

Internacionalização de ficheiros de JavaScript

Os últimos posts no meu blog têm sido acerca do tema da internacionalização de aplicações, nomeadamente:

O post de hoje contínua o sobre o método alternativo com ASP.NET, recorrendo a ao GetText do GNU. Como vimos, a aplicação do método _() para substituir texto localizável tornava-se um recurso simples e eficiente na internacionalização de ASP.NET. Em especial, é um método adoptado pela restantes linguagens e evita o esforço extra necessário para introduzir o texto em ficheiros .resx.

Procurei uma solução semelhante para Javascript, uma vez que a aplicação que estou a internacionalizar recorre muito a funcionalidade em javascript. Em especial, há mensagens de erro específicos e mensagens de confirmação contextualizadas. Especifico a ASP.Net, não encontrei nada de útil. Até achei muito estranho não detectar nada de muito útil nesse campo.

De qualquer forma, há alguns métodos genéricos a aplicar, incluíndo plugins em jQuery (http://plugins.jquery.com/project/gettext), mas gostei da descrição dada em 24ways.org. Simplesmente introduzi a função para _() no meu ficheiro core de javascript (é uma pequena biblioteca e funções e abstracções comuns a todas as páginas das minhas aplicações, e incluído em todas as páginas):

function _(s) {
	if (typeof(i18n)!='undefined' && i18n[s]) {
		return i18n[s];
	}
	return s;
}

Com isto é esperado existir uma variável i18n definido com a lista de traduções em pares chave-valor em JSON, do tipo:

var i18n = {
"" : "",
"Hello" : "Olá",
"Goodbye" : "Adeus",
//(...)
}

O método em 24ways.oprg refere ainda funções para formatar strings que podem ser uteis. Eu no entanto já tinha uma implementação de string.format para javascript (http://www.geekdaily.net/2007/06/21/cs-stringformat-for-javascript/).

Portanto, com a função no core, e a variável i18n adicionada, nos diversos ficheiros de javascript, onde fosse usado uma string, este deveria ser englobado por _():

if (confirm(_('Confirma a alteração de estado nos processos seleccionados?') )) {
//...
}

Assim, quando executado, e porque o método _() está sempre presente, o texto será substituído pelo existente no dicionário ou se não encontrado, o próprio texto usado como argumento da função.

Resta apenas dois passos – gerar os ficheiros .po, que deve seguir um esquema semelhante ao mencionado no artigo de ASP.Net, usando instruções póst-build e o gettext, e depois transformar os registos dos ficheiros .po em json. O primeiro dos passos é relativamente directa, apenas necessitando de construir uma nova lista de ficheiros (apenas de .js) e adicionar as entradas envolvidas em _() no .pot.

O segundo passo é mais “dificil”. Não há nada para o fazer directamentem senão um script em perl (http://jsgettext.berlios.de/doc/html/po2json.html), e como não me servia, decidi construir um script T4 simples, para usar no processo.

O script assume alguns pressupostos, pelo que, se utilizar, deve de os ter em conta e alterar consoante o necessário. O primeiro é que os ficheiros resultantes, quer os .po, quer os .js vão estar cada um numa pasta dedicada à língua específica como por exemplo:

/Scripts/locale/xx/messages.po
/Scripts/locale/xx/i18n.js

Também, considero que o ficheiro .po será gerado e unido com recurso a msgmerge, e portanto apenas devo transformar os ficheiros .po em ficheiros .js

Assim, o po2json.tt, colocado na pasta (/Scripts/locale/) pode ser executado após o build. Ele procurará o ficheiro .po de cada língua no array, e transformarará em um ficheiro i18n.js. Eu decidi definir as linguas manualmente, mas com pequenas alterações, podem ser detectadas automáticamente.

O T4 é o seguinte:

<#@ Template Language="C#v3.5" Hostspecific="True" #>
<#@ Output Extension=".js" #>
<#@ Import Namespace="System.IO" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ Import Namespace="System.Text.RegularExpressions" #>
<#@ Include File="MultiOutput.t4" #>
var i18n = {
<#
    string localeFolderPath = @"D:\Codigo\ProjectoWeb\Scripts\locale\";
    string[] suportedLang = {"pt"};
    string pofileName = "messages.po";
    string msgid = "msgid";
    string msgstr = "msgstr";
    string txtREGEX = "\"(.*)\"";
      
    foreach (string lang in suportedLang)
    {
        string[] lines = File.ReadAllLines(localeFolderPath + "\\" + lang + "\\"  + pofileName);
        List> entries = new List>();
        int currentLine = 0;

        while (currentLine < lines.Length)
        {
            string line = lines[currentLine];
            if (line.StartsWith(msgid))
            {
                string keyString = "";
                keyString += Regex.Match(line, txtREGEX).Groups[1].Value;
                
                //iterate while still a msgid
                line = lines[++currentLine];
                while(line.StartsWith("\""))
                {
                    keyString += Regex.Match(line, txtREGEX).Groups[1].Value;
                    line = lines[++currentLine];
                }

                if (line.StartsWith(msgstr))
                {
                    string valueString = "";
                    valueString += Regex.Match(line, txtREGEX).Groups[1].Value;
                    
                    if (++currentLine < lines.Length)
                    {
                        line = lines[currentLine];
                        while (line.StartsWith("\""))
                        {
                            valueString += Regex.Match(line, txtREGEX).Groups[1].Value;
                            line = lines[++currentLine];
                        }
                    }
                    //add pair to entries list
                    entries.Add(new KeyValuePair(keyString, valueString));
                }     
            }

            currentLine++;
        }
        
        //build outoput
        for( int i = 0; i< entries.Count; i++)
        {
            KeyValuePair entry = entries[i];
        
#>
"<#=  entry.Key #>" : "<#= entry.Value #>"<#=    i
<#
        }  
    SaveOutput(localeFolderPath + "\\" + lang + "\\"  + "i18n.js"); 
    
    }
#>
};

Procura cada “msgid” e processa as línguas seguintes convenientemente. Se houver erros, o processo será abandonado. O tt recorre ainda a um MultiOutput.t4, para gerar mais que um ficheiro a partir do .tt, convenientemente localizado. Não necessita de estar incluído no projecto (para não obrigar a incluir as dependências de TextTempleting).

Para incluir o ficheiro na lista de scripts a puxar, basta regista-lo no ScriptManager, no Page_Load da MasterPage :

ScriptManager.RegisterClientScriptInclude(this, typeof(string), "i18n", Page.ResolveUrl("~/Scripts/locale/" + lang + "/i18n.js"));

onde a variável lang é uma string com as letras da língua, para identificar a pasta onde será armazenado. Eu obtenho a a língua para a aplicação (transversal), mas outra possibilidade seria definir a língua pelas preferências do utilizador. Também, o caminho poderia ser proveniente de uma chave de configuração no web.config, se necessário.

Creio que está é uma solução simples, que pode, se necessário ser melhorado com mais funções (especialmente de formatações e plural / singular) como descrito no artigo do 24ways.org. Para já, esta é me suficiente.

Download po2json t4

ASP.Net – Método alternativo de internacionalização (i18n)

A internacionalização de aplicações (internationalization – i18n) para posterior localização (localization – l10n) é um processo multi-passo, que envolve a detecção de texto que deve ser apresentado em múltiplas línguas, bem como a preparação da base de código para que o texto possa ser correctamente traduzido.

Cada tecnologia tem a sua própria forma de implementar mecanismos que auxiliam a tradução. .Net recorre a recursos compilados na forma de ficheiros .resx . Os ficheiros .resx são de uma forma geral pares chave-valor, estruturados em XML, que são compilados para dlls carregados no inicio da aplicação.

Apesar de uma solução interessante, é extremamente tediante usa-los em ASP.Net. Com as bibliotecas de uma API, ok. O suporte a nível de código C# (ou VB ) torna o uso relativamente simples. Já com ASP.Net, não é possível dizer o mesmo. As razões estão bem descritas em “Why Internationalization is hopelessly Broken in ASP.Net“, mas resumindo, tudo tem de ser controlos ASP.Net com o runat=”server”, não há suporte simplificado a texto estático (escrito directamente na página), a referência de chaves das strings obriga a inserir meta:resoursekey=”” em todas os controlos, e os ficheiros .resx não são facilmente legíveis por pessoal não técnico.

A alternativa? Seguir o método do “resto do mundo” e usar ficheiros de strings em formatos simplificados, nomeadamente os ficheiros .po. Quem já explorou um projecto open-source ou projectos aplicacionais com add-ins linguísticos, muito provavelmente já se cruzaram com este formato de ficheiros. São ficheiros de texto simples, com texto assoiado a uma chave (msgid) e texto associado à tradução (msgstr). Por exemplo:

msgid "Pesquisar Candidatos"
msgstr "Search Candidates"

De notar neste exemplo que a chave está em PT e a tradução em EN. Não é recomendado esta abordagem, uma vez que as línguas latinas tem acentos que não são óptimos para chaves.

Continuando, o uso de ficheiros .PO, noutras frameworks, é suportado por por uma função gettext(), onde é passo a chave (geralmente o próprio texto, na língua base) e retorna a versão traduzida, conforme as preferências de utilizador. Melhor, há geralmente uma forma simplificada da função escrito _(). Assim, cada string a analisar chama a função gettext(), obtendo a versão traduzida do texto. Bem mais simples que os .resx e meta:resourcekey do .NET.

Usando Fairlylocal

O FailyLocal é um projecto opensource iniciado por Jason Kester, e que implementa a funcionalidade do gettext e ficheiros PO para ASP.Net. Como descrito no link do projecto, para pedir a tradução, na página basta utilizar:

<%= _("texto a traduzir") %>

ou no codebehind:

controlo.InnerHtml = _("texto a traduzir");

Tão simples e eficaz. Em termos de biblioteca, basta adicionar os ficheiros ao projecto da aplicação (têm de ser um projecto de aplicação web, em vez de um projecto de website, uma vez que o segundo não permite evento post-build, que o primeiro permite, e que constrói dinamicamente os ficheiros PO).

Em termos de execução, os ficheiros PO são carregados no arranque da aplicação, para um dicionário estático em memória, onde depois são realizadas as consultas do gettext(). Neste caso, todas as paginas devem herdar de InternationalPage ou InternationalMaster (ou a página base da aplicação derivar destas) em vez de Page directamente, para que _() fique disponível.

Para as minhas necessidades, efectuei pequenas alterações. Primeiro, para facilitar o uso em mutlipos projectos, adicionai os ficheiros ao projecto da minha framework, para que tenha sempre disponível. Segundo, porque necessito de aceder aos métodos, quer para a página instanciada, quer quando estou a usar WebMethods, tornei a propriedade LanguageCode e o método _() static. Finalmente, porque necessito de definir a língua ao nível da aplicação e não para cada utilizador, modifiquei o getter de LanguageCode para obter o código de lingua directamente da thread, em vez da sessão do utilizador:

public static string LanguageCode
{
   get
   {
       if (_languageCode == null)
       {
           _languageCode = System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToLower();
	}
	return _languageCode;
    }
    set
    {
	_languageCode = value;
    }
}

Incluíndo os scripts post-build, os ficheiros .PO são actualizados após cada build, podendo ser traduzidos de seguida, ou directamente ou recorrendo a programas como o Poedit. Ferramentas como o Pepipopum permitem traduzir automaticamente (via Google translate API) o ficheiro PO. As chaves devem estar em inglês para funcionar correctamente.

Finalmente, convém referir que o sistema tem fallback automático para o texto da própria chave – se o testo não estiver traduzido no ficheiro .po, o texto a usar é o próprio argumento do _(), o que ajuda muito se tiver a internacionalizar uma aplicação já existente.

Uma macro util

Ainda assim, com esta simplificação, internacionalizar uma aplicação existente não deixa de ser um trabalho tediante. Localizar o texto a traduzir e envolver no método _() é “chato”.

Para ajudar, criei uma macro:

Public Module GetTextSurrond

    '' surround text with <%= _(" and ") $>
    ''
    Sub ASPXSurround()
        Dim textSelection As EnvDTE.TextSelection

        textSelection = DTE.ActiveDocument.Selection()
        textSelection.Text = "<%= _(""" + textSelection.Text + """) " ''%>"
    End Sub

End Module

Associando esta Macro a um atalho de teclas, por exemplo Ctrl+G, Ctrl+T, ajudará a usar a macro, bastando seleccionar o texto e executar o comando (nos ficheiros .aspx).

Conclusão

Pela curta experiência que tenho com esta alternativa de tradução, não deixa de me parecer N vezes mais vantajoso que o uso de ficheiros .resx no ASP.Net. Os ficheiros .PO são apenas strings, portanto para recursos binários outra estratégia deve ser adoptada.