пятница, 8 июля 2011 г.

Presentation - The Art of CQRS

Presentation from my talk about CQRS on .NET Practice Leaders Group in Ciklum.

пятница, 1 июля 2011 г.

The Art of CQRS Practice Leaders in Ciklum


I welcome to invite people who interest in building flexible, scalable system with the help of CQRS principle. Event will be organized in Kharkiv, Ciklum office, July 07, 2011 18.00-19.00.

And Let the wheels run!


Карта

Отмечено на карте:





  • Ciklum


суббота, 26 февраля 2011 г.

Remote validation in ASP.NET MVC 2 with jQuery

In my research for CQRS concept project I want to use ASP.NET DataAnnotations for automatically support validation for my view models, but I want to use in the same way validation rules on client side, in standard DataAnnotations it supports client code associations for standard attributes provided with ASP.NET script. Unfortunately, in current version of ASP.NET MVC 2 doesn't support remote validation using ajax call, in MvcContrib project we can take implementation, but it doesn't meet my requirements and during testing I find some cases where it completely even doesn't be called. Simple case was when we submit form, so we can't process validation result in JavaScript callback, because page have been already sent.
I create additional params, so right now we can control processing remote validation, using jQuery synchronous ability.
JavaScript validation function:
Sys.Mvc.ValidatorRegistry.validators.remote = function (rule) {
    var url = rule.ValidationParameters.url;
    var parameterName = rule.ValidationParameters.parameterName;
    var isAsync = rule.ValidationParameters.isAsync=='true' || false;
    var message = rule.ErrorMessage;
    var result = true;

    var onComplete = function (responseData) {
        var lowerData = responseData.toLowerCase();
        if (lowerData != 'true') {
            var newMessage = (lowerData == 'false' ? message : responseData);
            result = newMessage;
        }
    };

    return function (value, context) {
        if (!value || !value.length) {
            return true;
        }

        if (context.eventName == 'blur') {
            return true;
        }

        var ajaxCallParam = {
            url: url,
            async: isAsync,
            data: $.param([{ name: parameterName, value: value}])
        }

        if (isAsync) {
            ajaxCallParam.success = onComplete;
        }

        var responseData = $.ajax(ajaxCallParam);

        if (!isAsync) {
            onComplete(responseData.responseText);
        }

        return result;
    };
}; 
Where custom Remote validation attribute:
public sealed class RemoteValidationAttribute : ValidationAttribute
{
    public string Action { get; set; }
    public string Area { get; set; }
    public string Controller { get; set; }
    public string ParameterName { get; set; }
    public string RouteName { get; set; }

    public bool IsAsync { get; set; }


    public override bool IsValid(object value)
    {
        return true;
    }
} 
With actual Remote Validator:
public class RemoteValidator : DataAnnotationsModelValidator
{
    public RemoteValidator(ModelMetadata metadata, ControllerContext context,
                           RemoteValidationAttribute attribute) :
                               base(metadata, context, attribute)
    {
    }

    public override IEnumerable GetClientValidationRules()
    {
        var rule = new ModelClientValidationRule
                       {
                           ErrorMessage = ErrorMessage,
                           ValidationType = "remote"
                       };

        rule.ValidationParameters["url"] = GetUrl();
        rule.ValidationParameters["parameterName"] = Attribute.ParameterName;
        rule.ValidationParameters["isAsync"] = Attribute.IsAsync.ToString().ToLower();
        return new[] {rule};
    }

    private string GetUrl()
    {
        var rvd = new RouteValueDictionary
                                       {
                                           {"area", Attribute.Area ?? string.Empty },
                                           {"controller", Attribute.Controller},
                                           {"action", Attribute.Action}
                                       };

        var virtualPath = RouteTable.Routes.GetVirtualPath(ControllerContext.RequestContext,
                                                           Attribute.RouteName, rvd);
        if (virtualPath == null)
        {
            throw new InvalidOperationException("No route matched!");
        }

        return virtualPath.VirtualPath;
    }
}
That we have to register on application start up:
DataAnnotationsModelValidatorProvider.RegisterAdapter(
    typeof(RemoteValidationAttribute),
    typeof(RemoteValidator)
    );

ASP.NET MVC 3 presented remote validation out of box, but previous implementation still need such type of functionality. My implementation based on original post by Brad Wilson.

Thank you, and I am always waiting for any feedback.

среда, 15 декабря 2010 г.

Object Reflection Helper

Please, be polite to this article, because it's only example and experiment, for production ready solution we have to measure different velocity and productivity values.

I have created helper, that cache object properties retrieved with reflection. Also helper provide wrapped methods for setting and getting values of properties, that arranged in dictionary with property name as key.
Let's look on ReflectionUtil class, it really do caching job on static level:

public static class ReflectionUtil<T>
{
    static ReflectionUtil()
    {
        Properties = typeof (T).GetProperties();
        GetProperties = Properties.Select(_ => new
                                                         {
                                                             Func = GetGetFunc(_), 
                                                             _.Name,
                                                         })
            .Where(_ => _.Func != null)
            .ToDictionary(_ => _.Name, _ => _.Func);
        
        SetProperties = Properties.Select(_ => new
                                                         {
                                                             Func = GetSetFunc(_), 
                                                             _.Name,
                                                         })
            .Where(_ => _.Func != null)
            .ToDictionary(_ => _.Name, _ => _.Func);
    }


    public static Func<T, object> GetGetFunc(PropertyInfo propertyInfo)
    {
        MethodInfo methodInfo = propertyInfo.GetGetMethod();
        if (methodInfo != null)
        {
            return  _ => methodInfo.Invoke(_, ArrayUtil.Empty<object>());
        }

        return null;
    }

    public static Func<T, object, T> GetSetFunc(PropertyInfo propertyInfo)
    {
        MethodInfo methodInfo = propertyInfo.GetSetMethod();
        if (methodInfo != null)
        {
            return delegate(T _, object val)
                       {
                           methodInfo.Invoke(_, new[] {val});
                           return _;
                       };
        }

        return null;
    }

    public static Dictionary<string, Func<T, object>> GetProperties { get; private set; }

    public static Dictionary<string, Func<T, object, T>> SetProperties { get; private set; }

    public static PropertyInfo[] Properties { get; private set; }
}

One note about code, I extensively use great OSS Lokad Shared Library and class ArrayUtil is from it.
Using this caching can give us some small worth of speeding up iterating over properties of common object and give the ability to lookup through properties using dictionary.

This code snippet help to integrate our reflection utility helper to object pipeline using extension methods syntax.
public static class ObjectReflectionExtension
{
    public static Dictionary<string, Func<T, object>> GetProperties<T>(this T value)
    {
        return ReflectionUtil<T>.GetProperties;
    }

    public static Dictionary<string, Func<T, object, T>> SetProperties<T>(this T value)
    {
        return ReflectionUtil<T>.SetProperties;
    }

    public static PropertyInfo[] Properties<T>(this T value)
    {
        return ReflectionUtil<T>.Properties;
    }
}

This helper I will use in the next article with real world code examples. We can extend ReflectionUtil class for caching another .NET members of object, e.g. methods, events, etc...
Quick example to show how typically we can use helper class and get properties from cache storage. First, we retrieve getters and setters from source object fromObj and destination object toObj:

var getProperties = fromObj.GetProperties();
var setProperties = toObj.SetProperties();

Then, we join different types of accessors by name using simple LINQ expression:

var map = from getProp in getProperties
          join setProp in setProperties on getProp.Key equals setProp.Key
          select new { From = getProp.Value, To = setProp.Value };

In the last expression we simply copied all properties values from source object to destination object, of course those objects have to have properties with the same names, if you would like to see any result. In such manner we can implement very simple shallow clone pattern, because of his reflection nature it can be used for any object type.

map.ForEach(
            _ => _.To(toObj, _.From(fromObj) )
            );

As usually when we using reflection, it is a big question about performance of that type operations, right now we left benchmark out of are of this article, in the next article I will show how to try to accomplish simple object mapper with the help of ReflectionUtil helper, and how to control object mapping in narrow places.
It will be a set of articles, where I will experiment around different aspects of technical implementation CQRS concept in enterprise software. I find interesting article by David Ebbo about interesting solution using the latest .NET 4.0 dynamic object features.
Find enough clever things to say, and you're a Prime Minister; write them down and you're a Shakespeare.
George Bernard Shaw

пятница, 29 октября 2010 г.

Enable CLR Integration in MS SQL Server

This tip can be useless especially in 2010 years, because developers can use SQL CLR during 5+ years and they have already known this procedure, so this tip is more for me, because every time I start using SQL CLR I search for clear script that enables this feature in MS SQL Server 2005/2008.
By default this feature is disabled in effort to security and some performance. Next code will solve this issue:
EXEC sp_configure 'show advanced options' , '1'
GO
reconfigure
GO
EXEC sp_configure 'clr enabled' , '1'
GO
reconfigure
-- turn back advanced options
EXEC sp_configure 'show advanced options' , '0'
GO
After we can write any user-defined functions aggregates, stored procedures, etc...using high versatile and flexible .NET Framework infrastructure in C# or VB.NET.

Typically, I use this feature to accomplish goals of adding Regular Expression support in MS SQL Server. Useful article CLR Assembly RegEx Functions for SQL Server by Example is written by @Phil_Factor.
That's all for today. If you don't mind my dear reader, I will post short tips for myself from time to time, maybe you also find them useful in some cases.

четверг, 30 сентября 2010 г.

Auto-completing geoinformation service

When I started to look into the theme of open source and contributing to the IT world, I had thought about really useful program or library, but after that I decided that it will be waste of time. Taking into account my life style, I won't support this project after some initial time and it will be broken as many other infamous attempts (we can even look on strange life cycle of a great product of Google - Google Wave, that ended after two months in production).
My goal is to provide a small kernel, full cycle of supporting and development of this project without deeply digging into the subject. My choice has become a service. You can ask what the logical difference between producing a program and service? From the program code point of view it is the same operators and conditions, but they give different results to the end user and according to the type of service they can meant for really different end users. Service provides some additional capabilities and very often expands another program product. From the another side, program is completed product that helps end user to do some actions and receive expected results. Of course all my previous thoughts are nothing but philosophy, and they had been running through my head.

Now, let's look into the main goal of this service and why I have chosen exactly this type of service. I want to share useful and commonly used part or subsystem and help developers to make the part of the program faster. What do we see in all types of programs and interfaces? My idea is that it's geoinformation data. Obviously we have systems that don't use any geoinformation and give us great value without it, but the number of program products use it in different approaches and structures.
So, now we have two main questions: will the geoinformational service be used and what type of service will it be?
We can divide it using different criterias, but I will look at three of them: detalisation, validity and sources of retrieving.
By detalisation that is often uses we mean coordinates using longitude and latitude, up to street and house, up to flat and up to city.
Under validity I mean - compliance with the real naming, object hierarchy or privacy and policy.
Sources are in many cases databases that consist of dictionaries or hierarchy structures of objects and places associated with them. Many additional information could be attached to geo objects. These databases could be local, distributed or service oriented. Services provide some API for information search and give quick answer to your problem, they can be filled with data and supported on demand or in contract way. Service takes care of all details of storing these big amounts of information maintenance and accessibility. So we come to the concept of SaaS, that have got new breath after fast growth cloud technologies and especially services.
Next, I will concentrate on implementing simple, lightweight geo web service, with detalisation up to city, that will use RESTfull interface or standard SOAP interface for communication with the clients.
My service will provide simple information:
  • list of all countries in the Earth (with future plans to support new Moon's settlements)
  • list of all cities in specified country
  • additional information about states, provinces, districts or regions and also list of the corresponding cities
  • autocomplete tips that help to input information and names.
In my case I will use different heterogeneous sources like free databases, subqueries to web mapping services and collect any feedback from consumers or clients. May be I will implement self education module, that will try to collect data from queries and add unknown information to the local information storage.
I chose so high detalisation level because of the lack of big resources storing bigger amount of information, and of course because of growing complexity of the service with growing of detalisation level.

Some technical notes, I plan to use .NET platform, MS SQL Server, WCF, git and some library for creating REST interface. Right now I see three candidates RestMvc, RestCake or Simply Restful Routing from the MvcContrib.
I will notify in next post about details and process of contributing and organization of this project.
All feedback and participating is welcome!

понедельник, 27 сентября 2010 г.

Устанавливаем SyntaxHighlighter 3 для Blogger/Blogspot

При написании статьи у меня возникла потребность в подсвечивании синтаксиса кода. Самый удобный и распространенный способ, это использовать библиотеку Alex Gorbatchev - SyntaxHighlighter. Основываясь на предыдущих успешных установках этой библиотеки для движка блогов Blogger, я принялся за дело и по пути, конечно, решил использовать одну из последних усовершенствований - автозагрузку различных кистей. Следую примеру интеграции, а они все следует сказать, достаточно старые и основываясь на обновленной wiki, я сразу не смог получить результат.
Пример из wiki насторек SyntaxHighlighter для Blogger не заработал.
Привожу краткий результат какие необходимы шаги для успешной интеграции SyntaxHighlighter 3 и Blogger:
  1. Скачиваем  последнюю версию библиотеки, это конечно лишает нас возможности автоматического обновления, что было бы доступно при использовании размещенной версии, но я несколько раз получал отказ в доступе к ресурсам размещенных на сервере Amazon S3, поэтому решил использовать собственный хостинг
  2. Заливаем на наш хостинг содержимое папок Scripts и Styles, особенно удобно если у вас подключен дополнительный псевдоним для недоступного контента на Blogger, это можно сделать в настройках Settings->Publishing->Missing files host, тогда заливая на этот хост, мы можем ссылаться на файлы, как будто они размещены на основном домене блога.
  3. Редактируем шаблон сайта и перед закрывающимся тэгом </head> вставляем ссылки


    <link href='/syntaxhighlighter/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
    <link href='/syntaxhighlighter/styles/shCore.css' rel='stylesheet' type='text/css'/>
    <script src='/syntaxhighlighter/scripts/shCore.js' type='text/javascript'/>
    <script src='/syntaxhighlighter/scripts/shAutoloader.js' type='text/javascript'/>
    У меня выделена папка syntaxhighlighter для всех файлов библиотеки.
  4. В конце шаблона сайта перед закрывающим тэгом </body> вставляем код немного отредактированный мной:


    <script type='text/javascript'>
    //<![CDATA[
    function path()
    {
      var args = arguments, result = [];
           
      for(var i = 0; i < args.length; i++)
          result.push(args[i].replace('@', '/syntaxhighlighter/scripts/'));
           
      return result;
    };
    
    SyntaxHighlighter.autoloader.apply(null, path(
      'applescript            @shBrushAppleScript.js',
      'actionscript3 as3      @shBrushAS3.js',
      'bash shell             @shBrushBash.js',
      'coldfusion cf          @shBrushColdFusion.js',
      'cpp c                  @shBrushCpp.js',
      'c# c-sharp csharp      @shBrushCSharp.js',
      'css                    @shBrushCss.js',
      'delphi pascal          @shBrushDelphi.js',
      'diff patch pas         @shBrushDiff.js',
      'erl erlang             @shBrushErlang.js',
      'groovy                 @shBrushGroovy.js',
      'java                   @shBrushJava.js',
      'jfx javafx             @shBrushJavaFX.js',
      'js jscript javascript  @shBrushJScript.js',
      'perl pl                @shBrushPerl.js',
      'php                    @shBrushPhp.js',
      'text plain             @shBrushPlain.js',
      'py python              @shBrushPython.js',
      'ruby rails ror rb      @shBrushRuby.js',
      'sass scss              @shBrushSass.js',
      'scala                  @shBrushScala.js',
      'sql                    @shBrushSql.js',
      'vb vbnet               @shBrushVb.js',
      'xml xhtml xslt html    @shBrushXml.js'
    ));
    SyntaxHighlighter.config.bloggerMode = true;
    SyntaxHighlighter.all();
    //]]>
    </script>
    
Теперь у нас настроена автоматическая подсветка синтаксиса и доступна дополнительная конфигурация