Sunday, July 14, 2013

Identifying the most dominant color in an image

Hi,
I developed an algorithm that identifies the most dominant color in an image.
The input is a URL to the target image and the output is the dominant color.
The algorithm reads all the pixels of the bitmap and maps them into a dictionary.
Then, it builds a graph of similar colors by a pre-defined threshold.
While building the graph, the algorithm maintains the most dominant color by the node that has the largest amount of pixels combined with its' adjacent nodes.

public class ColorsGraph
{
    private const int _similarityThreshhold = 30;
    private readonly Dictionary<Color, int> _colorsMapping;
    private Dictionary<ColorNode, List<ColorNode>> _colorsGraph;
    private KeyValuePair<ColorNode, List<ColorNode>> _mostDominantColor;

    public ColorsGraph(string imageUrl)
    {
        _colorsMapping = new Dictionary<Color, int>();

        var request = WebRequest.Create(imageUrl);
        using (var response = request.GetResponse())
        using (var stream = response.GetResponseStream())
        using (var image = Bitmap.FromStream(stream) as Bitmap)
        {
            BuildColorsMapping(image);
        }

        BuildColorsGraph();
    }

    public Color GetMostDominantColor()
    {
        return _mostDominantColor.Key.Color;
    }

    public Color GetMostDominantColorAverage()
    {
        var nodes = new[] { _mostDominantColor.Key }.Union(_mostDominantColor.Value).ToList();
        return Color.FromArgb(
            nodes.Sum(x => x.Color.A) / nodes.Count,
            nodes.Sum(x => x.Color.R) / nodes.Count,
            nodes.Sum(x => x.Color.G) / nodes.Count,
            nodes.Sum(x => x.Color.B) / nodes.Count);
    }

    private void BuildColorsMapping(Bitmap aBitmap)
    {
        for (var x = 0; x < aBitmap.Height; ++x)
        {
            for (var y = 0; y < aBitmap.Width; ++y)
            {
                var color = aBitmap.GetPixel(x, y);
                if (_colorsMapping.ContainsKey(color))
                {
                    ++_colorsMapping[color];
                }
                else
                {
                    _colorsMapping.Add(color, 1);
                }
            }
        }
    }

    private void BuildColorsGraph()
    {
        _colorsGraph = _colorsMapping.ToDictionary(x => new ColorNode(x.Key, x.Value), x => new List<ColorNode>());
        _mostDominantColor = _colorsGraph.OrderByDescending(x => x.Key.TotalPixelsCount).First();

        foreach (var sourceColor in _colorsGraph.Keys)
        {
            foreach (var targetColor in _colorsGraph)
            {
                if (sourceColor != targetColor.Key && AreSimilar(sourceColor.Color, targetColor.Key.Color))
                {
                    targetColor.Value.Add(sourceColor);
                    targetColor.Key.TotalPixelsCount += sourceColor.PixelsCount;
                    if (targetColor.Key.TotalPixelsCount > _mostDominantColor.Key.TotalPixelsCount)
                    {
                        _mostDominantColor = targetColor;
                    }
                }
            }
        }
    }

    private bool AreSimilar(Color aSource, Color aTarget)
    {
        return
            Math.Abs(aSource.B - aTarget.B) < _similarityThreshhold &&
            Math.Abs(aSource.R - aTarget.R) < _similarityThreshhold &&
            Math.Abs(aSource.G - aTarget.G) < _similarityThreshhold;
    }

    private class ColorNode
    {
        public ColorNode(Color color, int pixelsCount)
        {
            Color = color;
            PixelsCount = pixelsCount;
            TotalPixelsCount = pixelsCount;
        }

        public Color Color { get; private set; }
        public int PixelsCount { get; private set; }
        public int TotalPixelsCount { get; set; }
        public override bool Equals(object obj)
        {
            return ((ColorNode)obj).Color == Color;
        }

        public override int GetHashCode()
        {
            return Color.GetHashCode();
        }
    }
}
Feel free to play with the threshold to optimize your results!

Good luck!

Monday, May 20, 2013

Uploading files asynchronously in asp.net mvc site

Hi,
I've been looking for quite some time for a complete solution to uploading files in ajax for my site.
For those of you who don't know, browsers won't let you upload files without making a full page reload.
I haven't been able to find a good, working and cross browser solution for this problem.
So after much research and development I have finally managed to solve this problem.

Lets take a look at the following controller.
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult UploadImage(HttpPostedFileBase image)
    {
        try
        {
            if (Request.ContentLength > 1024 * 1024 * 2)
            {
                return UploadCompanyLogoResult(new { success = false, error = "File size too big. Maximum file size is 2MB." });
            }

            if (Request.Files.Count == 0)
            {
                return UploadCompanyLogoResult(new { success = false, error = "Failed uploading file" });
            }

            image = Request.Files[0];
            var webImage = new WebImage(image.InputStream) { FileName = image.FileName };
            var imageUrl = SaveImageToFile(webImage);

            return UploadCompanyLogoResult(new { success = true, url = imageUrl });
        }
        catch (Exception e)
        {
            Logger.Instance.Error("Failed to upload image", LOG_CATEGORY, e.ToString());
            return UploadCompanyLogoResult(new { success = false, error = "Unknown error uploading file" });
        }
    }

    private string SaveImageToFile(WebImage webImage)
    {
        var filePath = Server.MapPath("~/Content/" + webImage.FileName);
        System.IO.File.WriteAllBytes(filePath, webImage.GetBytes());
        return Url.Content("Content/" + webImage.FileName);
    }

    private ActionResult UploadCompanyLogoResult(object json)
    {
        if (Request.UserAgent.ToLower().Contains("ie"))
        {
            var javascriptSerializer = new JavaScriptSerializer();
            return Content(string.Format("<pre>{0}</pre>", javascriptSerializer.Serialize(json)));
        }

        return Json(json);
    }
}
The controller has 2 actions:
1. Home
2. UploadImage
The Home action returns a simple view, that you'll see down below, and the UploadImage action is responsible for handling the file uploaded.
This is Index.cshtml:
For comfortable view I've written the css & js inside, but of course it's recommended to split them into different files.
The layout file contains only a reference to jQuery.
<style type="text/css">
    #container { position: relative; display: inline-block; }
    #container > .loading-circle-container { position: absolute; width: 100%; height: 100%; top: 0; left: 0; text-align: center; background: white; opacity: 0.9; display: none; }
    #container > .loading-circle-container > .loading_circle { display: inline-block; position: static; background: url('http://pictures.reuters.com/ClientFiles/RTR/Images/ajax-loader.gif') no-repeat; width: 37px; height: 37px; }
    #container > form { display: inline-block; text-align: center; }
    #container > form > label { display: block; cursor: pointer; }
    #container > form > label > #image { cursor: pointer; max-height: 150px; vertical-align: middle; }
    #container > form > #imageUpload { position: absolute; left: -9999em; }
</style>
<div id="container">
    @using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data", target = "upload_file_target" }))
    {
        var defaultImage = "https://www.compuchecks.com/BJA/images/logo-placeholder.gif";
        <label for="imageUpload" id="button">
            <img id="image" src="@defaultImage">
        </label>
        <input type="file" name="imageUpload" id="imageUpload" />
    }
    <div class="loading-circle-container">
        <div class="loading_circle">
        </div>
    </div>
</div>
<script type="text/javascript">
    var uploadFileAjax = function (inputTag, successCallback) {
        var iframe = $('#upload_file_target');
        if (iframe.length == 0) {
            iframe = $('<iframe>').attr({
                id: 'upload_file_target',
                name: 'upload_file_target'
            }).css({
                width: 0,
                height: 0,
                border: 0
            }).appendTo($('body'));
        }

        iframe.load(function () {
            var iframeContents = iframe[0].contentWindow.document.body.innerHTML;
            successCallback($(iframeContents).html());
        });

        inputTag.parent().submit();
    }

    var container = $('#container');
    var loader = $('.loading-circle-container', container);
    var image = $('#image', container).load(function () {
        loader.fadeOut();
    });
    var imageUpload = $('#imageUpload', container).on('change', function () {
        uploadFileAjax(imageUpload, function (responseText) {
            var responseJson = JSON.parse(responseText);
            if (responseJson.success) {
                image.attr('src', responseJson.url);
            }
        });
    });

    $('form', container).on('submit', function () {
        loader.fadeIn();
    });

    if ($.browser.mozilla) {
        $('#button', container).click(function () {
            imageUpload.click();
        });
    }
</script>
You can test the code and see that it actually works (the page doesn't refresh - and the image uploads successfully).

Wednesday, February 20, 2013

Coupling properties with friendly names

Hey, For some time I've been looking for a good way to couple between the property, and it's display name.
Some may say it's a bad practice, but I think sometimes it has it's advantages.
So I solved it using DescriptionAttribute. The class is in System.dll, so we don't need to add any reference.
Let's take a look on the following class:
public class UserChecklistEntity
{
    public bool TakeTheTour { get; set; }

    public int VisitsCount { get; set; }
}
Let's decorate the properties with DescriptionAttributes:
public class UserChecklistEntity
{
    [Description("Take the tour")]
    public bool TakeTheTour { get; set; }

    [Description("Visits count")]
    public int VisitsCount { get; set; }
}
And now for the interesting part, add this extension method:
public static class ObjectExtensions
{
    public static string GetDescription<T>(this T obj, Expression<Func<T, object>> expression) where T : class
    {
        if (obj == null)
        {
            throw new ArgumentNullException("obj");
        }

        if (expression == null)
        {
            throw new ArgumentNullException("expression");
        }

        if (expression.NodeType == ExpressionType.Lambda && expression.Body is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)expression.Body;
            if (unaryExpression.Operand.NodeType == ExpressionType.MemberAccess && unaryExpression.Operand is MemberExpression)
            {
                var attribute = ((MemberExpression)unaryExpression.Operand).Member
                    .GetCustomAttributes(typeof(DescriptionAttribute), false)
                    .Select(x => x as DescriptionAttribute).FirstOrDefault() ?? new DescriptionAttribute();
                return attribute.Description;
            }
        }

        return null;
    }
}
For your convenience, because the extension method is on type object, put it in a non commonly used namespace.
The usage is very easy:
static void Main(string[] args)
{
    var userChecklistEntity = new UserChecklistEntity();
    var takeTheTourDescription = userChecklistEntity.GetDescription(x => x.TakeTheTour);
    var visitsCountDescription = userChecklistEntity.GetDescription(x => x.VisitsCount);

    Console.WriteLine(takeTheTourDescription);
    Console.WriteLine(visitsCountDescription);
}
Hope you find it useful!

Tuesday, February 5, 2013

Extending cshtml with functions and properties

Hey, Lately I've been building many infrastructures for my company's website and I wanted to expose those infrastructures in the most natural way that coders are used to.
One of the problems I spent time on was exposing the infrastructures on *.cshtml files.
I didn't want to use static classes - because it's not a natural way, and not very trivial.
So I managed to extend the class that represents the view, and by that add more properties and functions to it.
public abstract class ViewBase<TModel> : WebViewPage<TModel> where TModel : class
{
    public LayoutConfiguration LayoutConfiguration { get; private set; }

    public ViewBase()
    {
        LayoutConfiguration = LayoutConfiguration.GetInstance();
    }

    public void DoWork()
    {
  
    }
}
And now on your Web.config (in the Views folder) replace this line:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
With this one:
<pages pageBaseType="namespace.ViewBase">
And then on cshtml you can access the code:
@{    
    LayoutConfiguration.PageLabel = "HomepageBusiness";
    DoWork();
}

This way is much more elegant to adding extensions on HtmlHelper, or using static classes.

Sunday, January 27, 2013

Impersonating CurrentUser from SYSTEM

Hey all,

I've been searching for a very long time an easy way to impersonate current user while running in a "SYSTEM" user credentials.
I haven't found any code that does it and actually works.
So I managed to combine pieces of code from several places, and added some of my own.
This helper class exposes 2 functions:
1. Get current user impersonated scope - in this scope you can do pretty much whatever you want in the current user credentials.
2. Start a process as current user.
public static class ImpersonationUtils
{
    private const int SW_SHOW = 5;
    private const int TOKEN_QUERY = 0x0008;
    private const int TOKEN_DUPLICATE = 0x0002;
    private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
    private const int STARTF_USESHOWWINDOW = 0x00000001;
    private const int STARTF_FORCEONFEEDBACK = 0x00000040;
    private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
    private const int TOKEN_IMPERSONATE = 0x0004;
    private const int TOKEN_QUERY_SOURCE = 0x0010;
    private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
    private const int TOKEN_ADJUST_GROUPS = 0x0040;
    private const int TOKEN_ADJUST_DEFAULT = 0x0080;
    private const int TOKEN_ADJUST_SESSIONID = 0x0100;
    private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
    private const int TOKEN_ALL_ACCESS =
        STANDARD_RIGHTS_REQUIRED |
        TOKEN_ASSIGN_PRIMARY |
        TOKEN_DUPLICATE |
        TOKEN_IMPERSONATE |
        TOKEN_QUERY |
        TOKEN_QUERY_SOURCE |
        TOKEN_ADJUST_PRIVILEGES |
        TOKEN_ADJUST_GROUPS |
        TOKEN_ADJUST_DEFAULT |
        TOKEN_ADJUST_SESSIONID;

    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct STARTUPINFO
    {
        public int cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public int dwX;
        public int dwY;
        public int dwXSize;
        public int dwYSize;
        public int dwXCountChars;
        public int dwYCountChars;
        public int dwFillAttribute;
        public int dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    private enum SECURITY_IMPERSONATION_LEVEL
    {
        SecurityAnonymous,
        SecurityIdentification,
        SecurityImpersonation,
        SecurityDelegation
    }

    private enum TOKEN_TYPE
    {
        TokenPrimary = 1,
        TokenImpersonation
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool CreateProcessAsUser(
        IntPtr hToken,
        string lpApplicationName,
        string lpCommandLine,
        ref SECURITY_ATTRIBUTES lpProcessAttributes,
        ref SECURITY_ATTRIBUTES lpThreadAttributes,
        bool bInheritHandles,
        int dwCreationFlags,
        IntPtr lpEnvironment,
        string lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool DuplicateTokenEx(
        IntPtr hExistingToken,
        int dwDesiredAccess,
        ref SECURITY_ATTRIBUTES lpThreadAttributes,
        int ImpersonationLevel,
        int dwTokenType,
        ref IntPtr phNewToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool OpenProcessToken(
        IntPtr ProcessHandle,
        int DesiredAccess,
        ref IntPtr TokenHandle);

    [DllImport("userenv.dll", SetLastError = true)]
    private static extern bool CreateEnvironmentBlock(
            ref IntPtr lpEnvironment,
            IntPtr hToken,
            bool bInherit);

    [DllImport("userenv.dll", SetLastError = true)]
    private static extern bool DestroyEnvironmentBlock(
            IntPtr lpEnvironment);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(
        IntPtr hObject);

    private static void LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock, int sessionId)
    {
        var pi = new PROCESS_INFORMATION();
        var saProcess = new SECURITY_ATTRIBUTES();
        var saThread = new SECURITY_ATTRIBUTES();
        saProcess.nLength = Marshal.SizeOf(saProcess);
        saThread.nLength = Marshal.SizeOf(saThread);

        var si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = @"WinSta0\Default";
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
        si.wShowWindow = SW_SHOW;

        if (!CreateProcessAsUser(
            token,
            null,
            cmdLine,
            ref saProcess,
            ref saThread,
            false,
            CREATE_UNICODE_ENVIRONMENT,
            envBlock,
            null,
            ref si,
            out pi))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateProcessAsUser failed");
        }
    }

    private static IDisposable Impersonate(IntPtr token)
    {
        var identity = new WindowsIdentity(token);
        return identity.Impersonate();
    }

    private static IntPtr GetPrimaryToken(Process process)
    {
        var token = IntPtr.Zero;
        var primaryToken = IntPtr.Zero;

        if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, ref token))
        {
            var sa = new SECURITY_ATTRIBUTES();
            sa.nLength = Marshal.SizeOf(sa);

            if (!DuplicateTokenEx(
                token,
                TOKEN_ALL_ACCESS,
                ref sa,
                (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                (int)TOKEN_TYPE.TokenPrimary,
                ref primaryToken))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "DuplicateTokenEx failed");
            }

            CloseHandle(token);
        }
        else
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
        }

        return primaryToken;
    }

    private static IntPtr GetEnvironmentBlock(IntPtr token)
    {
        var envBlock = IntPtr.Zero;
        if (!CreateEnvironmentBlock(ref envBlock, token, false))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateEnvironmentBlock failed");
        }
        return envBlock;
    }

    public static void LaunchAsCurrentUser(string cmdLine)
    {
        var process = Process.GetProcessesByName("explorer").FirstOrDefault();
        if (process != null)
        {
            var token = GetPrimaryToken(process);
            if (token != IntPtr.Zero)
            {
                var envBlock = GetEnvironmentBlock(token);
                if (envBlock != IntPtr.Zero)
                {
                    LaunchProcessAsUser(cmdLine, token, envBlock, process.SessionId);
                    if (!DestroyEnvironmentBlock(envBlock))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error(), "DestroyEnvironmentBlock failed");
                    }
                }

                CloseHandle(token);
            }
        }
    }

    public static IDisposable ImpersonateCurrentUser()
    {
        var process = Process.GetProcessesByName("explorer").FirstOrDefault();
        if (process != null)
        {
            var token = GetPrimaryToken(process);
            if (token != IntPtr.Zero)
            {
                return Impersonate(token);
            }
        }

        throw new Exception("Could not find explorer.exe");
    }
}
And the usage is very easy:
ImpersonationUtils.LaunchAsCurrentUser("notepad");

using (ImpersonationUtils.ImpersonateCurrentUser())
{
    
}
It's easy and it's fun!
I really hope this code will save you the hours I spend on writing it.

Saturday, January 19, 2013

Json To Dictionary generic model binder

Hey all,

Few days ago I was challenged by a good friend and colleague to write a generic model binder for a dynamic json.
Why does he need such a thing ? I'll explain:
Normally, when you write a classic website using any platform, the contract between the client and the server is obvious and well known.
However, if you write a complex web system, and you have the need to build your client model dynamically without creating a massive model on the server that handles all kinds of properties and values, you might be interested in getting a generic dictionary that contains all your client values.
To implement it I used a state machine to parse the json:
public class DictionaryModelBinder : DefaultModelBinder
{
    private const string _dateTimeFormat = "dd/MM/yyyy HH:mm:ss";

    private enum StateMachine
    {
        NewSection,
        Key,
        Delimiter,
        Value,
        ValueArray
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var stream = controllerContext.HttpContext.Request.InputStream;
        string text;

        stream.Position = 0;
        using (var reader = new StreamReader(stream))
        {
            text = reader.ReadToEnd();
        }

        int index = 0;
        return Build(text, ref index);
    }

    private static Dictionary<string, object> Build(string text, ref int index)
    {
        var state = StateMachine.NewSection;
        var dictionary = new Dictionary<string, object>();
        var key = string.Empty;
        object value = string.Empty;

        for (; index < text.Length; ++index)
        {
            if (state == StateMachine.NewSection && text[index] == '{')
            {
                dictionary = new Dictionary<string, object>();
                state = StateMachine.NewSection;
            }
            else if (state == StateMachine.NewSection && text[index] == '"')
            {
                key = string.Empty;
                state = StateMachine.Key;
            }
            else if (state == StateMachine.Key && text[index] != '"')
            {
                key += text[index];
            }
            else if (state == StateMachine.Key && text[index] == '"')
            {
                state = StateMachine.Delimiter;
            }
            else if (state == StateMachine.Delimiter && text[index] == ':')
            {
                state = StateMachine.Value;
                value = string.Empty;
            }
            else if (state == StateMachine.Value && text[index] == '[')
            {
                state = StateMachine.ValueArray;
                value = value.ToString() + text[index];
            }
            else if (state == StateMachine.ValueArray && text[index] == ']')
            {
                state = StateMachine.Value;
                value = value.ToString() + text[index];
            }
            else if (state == StateMachine.Value && text[index] == '{')
            {
                value = Build(text, ref index);
            }
            else if (state == StateMachine.Value && text[index] == ',')
            {
                dictionary.Add(key, ConvertValue(value));
                state = StateMachine.NewSection;
            }
            else if (state == StateMachine.Value && text[index] == '}')
            {
                dictionary.Add(key, ConvertValue(value));
                return dictionary;
            }
            else if (state == StateMachine.Value || state == StateMachine.ValueArray)
            {
                value = value.ToString() + text[index];
            }
        }

        return dictionary;
    }

    private static object ConvertValue(object value)
    {
        string valueStr;
        if (value is Dictionary<string, object> || value == null || (valueStr = value.ToString()).Length == 0)
        {
            return value;
        }

        bool boolValue;
        if (bool.TryParse(valueStr, out boolValue))
        {
            return boolValue;
        }

        int intValue;
        if (int.TryParse(valueStr, out intValue))
        {
            return intValue;
        }

        double doubleValue;
        if (double.TryParse(valueStr, out doubleValue))
        {
            return doubleValue;
        }

        valueStr = valueStr.Trim('"');

        DateTime datetimeValue;
        if (DateTime.TryParseExact(valueStr, _dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out datetimeValue))
        {
            return datetimeValue;
        }

        if (valueStr.First() == '[' && valueStr.Last() == ']')
        {
            valueStr = valueStr.Trim('[', ']');
            if (valueStr.Length > 0)
            {
                if (valueStr[0] == '"')
                {
                    return valueStr
                        .Split(new[] { '"' }, StringSplitOptions.RemoveEmptyEntries)
                        .Where(x => x != ",")
                        .ToArray();
                }
                else
                {
                    return valueStr
                        .Split(',')
                        .Select(x => ConvertValue(x.Trim()))
                        .ToArray();
                }
            }
        }

        return valueStr;
    }
}
We need to register this model binder in the Global.asax file:
ModelBinders.Binders.Add(typeof(Dictionary<string, object>), new DictionaryModelBinder());
And the usage in the client side is pretty much straight forward as you probably expected:
var url = '/';
var data = {
    name: 'Amir Yonatan',
    age: 26,
    height: 1.7,
    hasDrivingLicence: true,
    nicknames: ['amiry', 'speedy'],
    education: {
        graduationDate: '30/10/2010 15:12:30',
        grades: [100, 95, 87],
        major: 'Computer Science'
    }
};

$.ajax(url, {
    cache: false,
    contentType: 'application/json',
    data: JSON.stringify(data),
    dataType: 'json',
    type: 'POST'
});
That's it!
Hope you'll find it useful.

Sunday, January 13, 2013

Testing controller actions with ActionFilterAttribute in ASP .NET MVC

Hey,
Have you ever wanted to test your controller actions with the logic you add with ActionFilterAttributes?
Well, I did.
So I wrote this helper class, which executes the ActionFilterAttribute methods.
public class FilterAttributeTester
{
    public ActionExecutingContext ExecuteOnActionExecuting<TAttribute>(Controller aController, Func<ActionResult> aAction)
     where TAttribute : ActionFilterAttribute
    {
        var actionExecutingContext = CreateActionExecutingContext(aController, aAction);

        var attribute = GetAttribute<TAttribute>(aAction);
        attribute.OnActionExecuting(actionExecutingContext);
        return actionExecutingContext;
    }

    public ActionExecutedContext ExecuteOnActionExecuted<TAttribute>(Controller aController, Func<ActionResult> aAction)
     where TAttribute : ActionFilterAttribute
    {
        var actionExecutedContext = CreateActionExecutedContext(aController, aAction);

        var attribute = GetAttribute<TAttribute>(aAction);
        attribute.OnActionExecuted(actionExecutedContext);
        return actionExecutedContext;
    }

    public static ActionExecutingContext CreateActionExecutingContext(Controller aController, Func<ActionResult> aAction)
    {
        return new ActionExecutingContext(
           new ControllerContext(new HttpContextWrapper(HttpContext.Current), new RouteData(), aController),
           new ReflectedActionDescriptor(aAction.Method, aAction.Method.Name, new ReflectedControllerDescriptor(aController.GetType())),
           new Dictionary<string, object>());
    }

    public static ActionExecutedContext CreateActionExecutedContext(Controller aController, Func<ActionResult> aAction)
    {
        return new ActionExecutedContext(
           new ControllerContext(new HttpContextWrapper(HttpContext.Current), new RouteData(), aController),
           new ReflectedActionDescriptor(aAction.Method, aAction.Method.Name, new ReflectedControllerDescriptor(aController.GetType())),
           false,
           null);
    }

    private static TAttribute GetAttribute<TAttribute>(Func<ActionResult> aAction) where TAttribute : ActionFilterAttribute
    {
        return aAction.Method.GetCustomAttributes(typeof(TAttribute), true).Select(x => x as TAttribute).SingleOrDefault();
    }
}
And that's it!
In your test add the following code:
var filterAttributeTester = new FilterAttributeTester();
var actionExecutingContext = filterAttributeTester.ExecuteOnActionExecuting<UserLoggedInAttribute>(homepageController, homepageController.Index);
var returnValue = actionExecutingContext.Result as RedirectResult;
if (returnValue != null)
{
 // filter attribute redirected to another action
}
All you have to do is fake HttpContext, and you're good!

Good luck!