Kendo Grid custom sort order

I’ve been racking my brains as the sorting on the Kendo Grid is pretty good, only that I need to be able to not sort in the order that is being displayed.  An example would be numbers written out in full and you want them in number sort order.

@(Html.Kendo().Grid<Number>()
 .Name("grid")
 .Columns(columns =>
 {
 columns.Bound(c => c.Id);
 columns.Bound(c => c.Item);
 })
 .Sortable()
 .DataSource(dataSource => dataSource
 .Ajax()
 .Read(read => read.Action("Numbers_Read", "Home"))
 )
)


Here is the list not in any order, but it does have a sortorder column

 private static List<Number> GetNumbers()
 {
 List<Number> numbers = new List<Number>();

 numbers.Add(new Number() { Id = 1, Item = "one", SortOrder = "1" });

 numbers.Add(new Number() { Id = 2, Item = "three", SortOrder = "3" });

 numbers.Add(new Number() { Id = 3, Item = "six", SortOrder = "6" });
 numbers.Add(new Number() { Id = 4, Item = "two", SortOrder = "2" });
 numbers.Add(new Number() { Id = 5, Item = "five", SortOrder = "5" });
 numbers.Add(new Number() { Id = 6, Item = "seven", SortOrder = "7" });
 numbers.Add(new Number() { Id = 7, Item = "four", SortOrder = "4" });
 return numbers;
 }

and now for the magic, when the request is coming back into the controller action we check to see what is being requested and then change it to another hidden column, this way it retains all the functionality of the Kendo Grid and it just works….!

public ActionResult Numbers_Read([DataSourceRequest]DataSourceRequest request)
 {
 List<Number> numbers = GetNumbers();

 foreach (var sort in request.Sorts)
 {
 // Find the sort member you need a custom sort for and change it to the custom column 
 if (sort.Member.ToLowerInvariant() == "item")
 {
 sort.Member = "SortOrder";
 }
 }
 return Json(numbers.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
 }

I have created this sample Kendo Grid project so you can see how it is all done.

kendo_grid

The way to handle unauthorised requests to Ajax actions in ASP.NET MVC

Problem

I have created a view that posts to an action via Ajax with the expectation that the action will return the requested data or an empty string.  Even better, I would like it to be configurable to return whatever value I see fit.

The problem arises when I decorate the called action with the [Authorize] attribute.  If the request is not authorized and I have a loginUrl configured in my web.config, my ajax request will return the html output of my loginUrl view.  That is undesirable.

Solution

I can extend the existing Authorize attribute by inheriting from the AuthorizeAttribute class.  Here is the code that extends the Authorize attribute:

public class AjaxAuthorizeOverrideAttribute : AuthorizeAttribute
    {
        public string View { get; set; }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAjaxRequest())
            {
                base.HandleUnauthorizedRequest(filterContext);
                return;
            }

            filterContext.Result = new ViewResult { ViewName = View };
            filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
        }
    }

Here is the decorator for the ajax action in the controller class:

[AjaxAuthorizeOverride(View="AjaxAuthorizeError")]

public ActionResult AjaxRequest()
{
     return View();
}

Note: there is no default view page being rendered.

 

Original article can be found here

Active links on Bootstrap Navbar with ASP.NET MVC

If you have used Bootstrap with your ASP.NET MVC application, you might have faced some issues with implementing active links of it’s Navbar component. We’ll have to dynamically add a css class called active to the particular menu item in order to make it selected in the Navbar. Here is a HtmlHelper extension which is capable of rendering menu items as well as drop-down menu items. I’ve used ASP.NET MVC 5 with Razor and Bootstrap 3.

First step is to create a HtmlHelper extension class. 

using System.Web.Mvc;

public static class MenuLinkExtension
{
    public static MvcHtmlString MenuLink(this HtmlHelper htmlHelper, string itemText, string actionName, string controllerName, MvcHtmlString[] childElements = null)
    {
        var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
        var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
        string finalHtml;
        var linkBuilder = new TagBuilder("a");
        var liBuilder = new TagBuilder("li");

        if (childElements != null && childElements.Length > 0)
        {
            linkBuilder.MergeAttribute("href", "#");
            linkBuilder.AddCssClass("dropdown-toggle");
            linkBuilder.InnerHtml = itemText + " <b class=\"caret\"></b>";
            linkBuilder.MergeAttribute("data-toggle", "dropdown");
            var ulBuilder = new TagBuilder("ul");
            ulBuilder.AddCssClass("dropdown-menu");
            ulBuilder.MergeAttribute("role", "menu");
            foreach (var item in childElements)
            {
                ulBuilder.InnerHtml += item + "\n";
            }

            liBuilder.InnerHtml = linkBuilder + "\n" + ulBuilder;
            liBuilder.AddCssClass("dropdown");
            if (controllerName == currentController)
            {
                liBuilder.AddCssClass("active");
            }

            finalHtml = liBuilder.ToString() + ulBuilder;
        }
        else
        {
            var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection);
            linkBuilder.MergeAttribute("href", urlHelper.Action(actionName, controllerName));
            linkBuilder.SetInnerText(itemText);
            liBuilder.InnerHtml = linkBuilder.ToString();
            if (controllerName == currentController && actionName == currentAction)
            {
                liBuilder.AddCssClass("active");
            }

            finalHtml = liBuilder.ToString();
        }

        return new MvcHtmlString(finalHtml);
    }
}

Once you have saved it, you can it by just calling like this!

<header class="navbar navbar-inverse navbar-fixed-top bs-docs-nav" role="banner">
    <div class="container">
        <div class="navbar-header">
            <a href="#" class="navbar-brand">Mvc Shop</a>
        </div>
        <nav role="navigation">
 
            <ul class="nav navbar-nav">
                @Html.MenuLink("Home", "Index", "Home")
                @Html.MenuLink("Dropdown", "Index", "Home2", new MvcHtmlString[]{
                                      @Html.MenuLink("Link1", "Action1", "Controller1"),
                                      @Html.MenuLink("Link2", "Action2", "Controller1"),
                                      @Html.MenuLink("Link3", "Action3", "Controller1"),
                                    })
                @Html.MenuLink("JavaScript", "Index", "Home1", new MvcHtmlString[]{
                                      @Html.MenuLink("Link1", "Index1", "Home1"),
                                      @Html.MenuLink("Link2", "Index2", "Home1"),
                                      @Html.MenuLink("Link3", "Index3", "Home1")
                                    })
 
            </ul>
        </nav>
    </div>
</header>

Make Fake MVC Objects for testing

If you need to create some Fake MVC objects for testing MVC objects then here you are:

FakeControllerContext

using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;

using MvcContrib.TestHelper.Fakes;

public class FakeControllerContext : ControllerContext
{
    public FakeControllerContext(IController controller)
        : this(controller, null, null, null, null, null, null)
    {
    }

    public FakeControllerContext(IController controller, HttpCookieCollection cookies)
        : this(controller, null, null, null, null, cookies, null)
    {
    }

    public FakeControllerContext(IController controller, SessionStateItemCollection sessionItems)
        : this(controller, null, null, null, null, null, sessionItems)
    {
    }
        
    public FakeControllerContext(IController controller, NameValueCollection formParams)
        : this(controller, null, null, formParams, null, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, NameValueCollection formParams, NameValueCollection queryStringParams)
        : this(controller, null, null, formParams, queryStringParams, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, string userName)
        : this(controller, userName, null, null, null, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, string userName, string[] roles)
        : this(controller, userName, roles, null, null, null, null)
    {
    }
        
    public FakeControllerContext
        (
            IController controller,
            string userName,
            string[] roles,
            NameValueCollection formParams,
            NameValueCollection queryStringParams,
            HttpCookieCollection cookies,
            SessionStateItemCollection sessionItems
        )
        : base(new FakeHttpContext(new FakePrincipal(new FakeIdentity(userName), roles), formParams, queryStringParams, cookies, sessionItems), new RouteData(), (Controller)controller)
    { }
}

FakeHttpContext

using System;
using System.Collections.Specialized;
using System.Security.Principal;
using System.Web;
using System.Web.SessionState;

public class FakeHttpContext : HttpContextBase
{
    private readonly FakePrincipal principal;
    private readonly NameValueCollection formParams;
    private readonly NameValueCollection queryStringParams;
    private readonly HttpCookieCollection cookies;
    private readonly SessionStateItemCollection sessionItems;

    public FakeHttpContext(FakePrincipal principal, NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies, SessionStateItemCollection sessionItems)
    {
        this.principal = principal;
        this.formParams = formParams;
        this.queryStringParams = queryStringParams;
        this.cookies = cookies;
        this.sessionItems = sessionItems;
    }

    public override HttpRequestBase Request
    {
        get
        {
            return new FakeHttpRequest(this.formParams, this.queryStringParams, this.cookies);
        }
    }

    public override IPrincipal User
    {
        get
        {
            return this.principal;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override HttpSessionStateBase Session
    {
        get
        {
            return this.sessionItems == null ? null : new FakeHttpSessionState(this.sessionItems);
        }
    }

}

FakeHttpRequest

using System.Collections.Specialized;
using System.Web;

public class FakeHttpRequest : HttpRequestBase
{
    private readonly NameValueCollection formParams;
    private readonly NameValueCollection queryStringParams;
    private readonly HttpCookieCollection cookies;

    public FakeHttpRequest(NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies)
    {
        this.formParams = formParams;
        this.queryStringParams = queryStringParams;
        this.cookies = cookies;
    }

    public override NameValueCollection Form
    {
        get
        {
            return this.formParams;
        }
    }

    public override NameValueCollection QueryString
    {
        get
        {
            return this.queryStringParams;
        }
    }

    public override HttpCookieCollection Cookies
    {
        get
        {
            return this.cookies;
        }
    }
}

FakeHttpSessionState

using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Web.SessionState;

public class FakeHttpSessionState : HttpSessionStateBase
{
    private readonly SessionStateItemCollection sessionItems;

    public FakeHttpSessionState(SessionStateItemCollection sessionItems)
    {
        this.sessionItems = sessionItems;
    }

    public override void Add(string name, object value)
    {
        this.sessionItems[name] = value;
    }

    public override int Count
    {
        get
        {
            return this.sessionItems.Count;
        }
    }

    public override IEnumerator GetEnumerator()
    {
        return this.sessionItems.GetEnumerator();
    }

    public override NameObjectCollectionBase.KeysCollection Keys
    {
        get
        {
            return this.sessionItems.Keys;
        }
    }

    public override object this[string name]
    {
        get
        {
            return this.sessionItems[name];
        }
        set
        {
            this.sessionItems[name] = value;
        }
    }

    public override object this[int index]
    {
        get
        {
            return this.sessionItems[index];
        }
        set
        {
            this.sessionItems[index] = value;
        }
    }

    public override void Remove(string name)
    {
        this.sessionItems.Remove(name);
    }
}

FakePrincipal

using System.Linq;
using System.Security.Principal;

public class FakePrincipal : IPrincipal
{
    private readonly IIdentity identity;
    private readonly string[] roles;

    public FakePrincipal(IIdentity identity, string[] roles)
    {
        this.identity = identity;
        this.roles = roles;
    }

    public IIdentity Identity
    {
        get { return this.identity; }
    }

    public bool IsInRole(string role)
    {
        return this.roles != null && this.roles.Contains(role);
    }
}

The original article and source is from Stephen Walter Faking the Controller Context

Disclaimer Page using MVC

If you ever need a disclaimer page in MVC, there are a few things you need to consider, the first is you should not be able to get to a page without agreeing to the disclaimer and if you have to re-login then you need to be presented with the disclaimer page again.

I’ve opted to use an Attribute, which can be used on a Controller.

[AgreeToDisclaimer]
public class Page1Controller : Controller
{

This makes things very simple and as easy to use as the Authorise Attribute.

The implementation of the AgreeToDisclaimer inherits the Authorize Attribute, which over rides the AuthorizeCore and HandleUnauthorizedRequest methods

public class AgreeToDisclaimerAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        if (!this.HasAgreedToDisclaimer(httpContext))
            return false;

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // Returns HTTP 401 by default 
        filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary 
    {
        { "action", "index" },
        { "controller", "Disclaimer" }
    });
    }

    private bool HasAgreedToDisclaimer(HttpContextBase current)
    {
        return current != null && current.User != null ? (bool)current.User.Disclaimer() : false;
    }
}

You’ll have noticed that I have extended the User object to include Disclaimer, this way when the user session expires or the user logs out the current user is null

As for extending the User object this again is quite simple:

public static class IPrincipalExtension
{
    /// <summary>
    /// ObjectCache references the objects with WeakReferences for avoiding memory leaks.
    /// </summary>
    public static ConditionalWeakTable<object, Dictionary<string, object>> ObjectCache = new ConditionalWeakTable<object, Dictionary<string, object>>();

    public static void SetValue<T>(this T obj, string name, object value) where T : class
    {
        Dictionary<string, object> properties = ObjectCache.GetOrCreateValue(obj);

        if (properties.ContainsKey(name))
            properties[name] = value;
        else
            properties.Add(name, value);
    }

    public static T GetValue<T>(this object obj, object name)
    {
        Dictionary<string, object> properties;
        if (ObjectCache.TryGetValue(obj, out properties) && properties.ContainsKey(name.ToString()))
            return (T)properties[name.ToString()];
        else
            return default(T);
    }

    public static object GetValue(this object obj, bool name)
    {
        return obj.GetValue<object>(name);
    }

    public static bool Disclaimer(this IPrincipal principal)
    {
        return principal.GetValue<bool>("Disclaimer");
    }

    public static void SetDisclaimer(this IPrincipal principal, bool value)
    {
        principal.SetValue("Disclaimer", value);
    }
}

URL Activity Tampering and how to prevent it in MVC

No web applications are developed without concerning the security issues. But it is not sure whether the security measures are implemented correctly and the applications are well protected. We could see a lot of web applications query string parameters in plain string which are easy to manipulate and way to escalate restricted resources. Even the URL parameters are encrypted there is still a chance of a bruteforce attack by manipulating the encrypted hash and it yields when the database is large where the chance of matching a random hash is high. So it is clear the importance to protect the URL in the web application is necessary for all programming platforms. Here, this is discussed with reference to ASP.NET MVC and the utility class is presented.

.NET Framework has a lot of improved methods for security and the MVC framework introduced new security methods like AntiForgeryToken that I discussed in a previous article Preventing Cross Site Request Forgery. Let us have a brief look at the security methods in general practice.

  • Authorize attribute: This is useful to authorize a user or role to access any resource in the application after authenticated. This helps to have User and Role level protections.
  • Http Referrer Check: This is a general method not confined to .NET. This is to prevent an URL request which is not from the site, but from an external link or the link directly executed at the browser navigation
  • Anti Forgery Token: This is a powerful option to prevent any hidden field manipulation while form posting and prevents Cross-Site Request Forgery
  • HTML Encoding: It is advised to encode all user inputs to prevent Cross Site Scripting attack/ XSS attack etc.,
  • Protection against SQL injections
  • Encryption of Query string parameters. This is good way to prevent manipulation of query string parameters. But this is not a complete protection, still vulnerable for a brute force attack.

Even though all the above methods are available, .NET framework doesn’t provide an inbuilt functionality for protecting the URL parameters. Its URL authorization technique protects the whole URL, but not parts of the URL which are still vulnerable for manipulation. This piece of coding here helps to easily implement all these security methods with special importance to protecting the URL parameters. Creating a URL hash is not new but yet it is not a common practice in the industry though it is an important concern. So it would be important to share a piece of code for the easy implementation of this method in ASP.NET MVC.

The basic idea is simple, encrypting the URL parameters along with controller, action names to a hash and later it will be passed to server as a URL parameter. The hash will be verified at the server side for its validity by recomputing the hash and compared with the submitted hash. This hash is dynamic and specific to a session. So even though your URL cached in the man-in-the middle attack, it will not work in other sessions. Basically a utility class extends the HTML helper ActionLink class. So we can use Html.ActionLink method as such in the MVC implementation, in addition you only need to pass a boolean argument as a last argument to get the protected URL. It is pretty easy to use this coding. Examples are shown below.

<%=Html.ActionLink("link Test 3", "HandleLink", new { id = 200 }, true)%>

You’ll notice the extra boolean parameter at the end to enable encryption.

The ExtendedHtmlActionLinkHelper looks like this:

namespace ExtendedHtmlActionLinkHelper
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using System.Web.Routing;

    /// <summary>
    /// This class is an extension for the Html Helper
    /// </summary>
    public static class ActionLinkExtensions
    {
        // This password is included in the hash. If needed it can be changed.
        private static string tokenPassword = "@#123%#";

        public static string TokenPassword
        {
            get { return tokenPassword; }

            set { tokenPassword = value; }
        }

        /// <summary>
        /// This is the extended method of Html.ActionLink.This class has the extended methods for the 10 overloads of this method
        /// All the overloaded method applys the same logic excepts the parameters passed in
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="linkText">The link text.</param>
        /// <param name="actionName">Name of the action.</param>
        /// <param name="generateToken">if set to <c>true</c> [generate token].</param>
        /// <returns></returns>
        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary();
            if (generateToken)
            {
                // Call the generateUrlToken method which create the hash
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);

                // The hash is added to the route value dictionary
                rvd.Add("urltoken", token);
            }

            // the link is formed by using the GenerateLink method.
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, object routeValues, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, RouteValueDictionary routeValues, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = routeValues;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary();
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        private static IDictionary<string, object> GetDictionaryFromObject(object sourceObject)
        {
            var objType = sourceObject.GetType();

            return objType.GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(sourceObject, null));
        }
    }
}

It is also worth generating the UrlHelper.Action too should this be required

using System.Web.Mvc;
using System.Web.Routing;

public static class ActionExtensions
{
    public static MvcHtmlString Action(this UrlHelper helper, string actionName, bool generateToken)
    {
        var rvd = new RouteValueDictionary();
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, object routeValues, bool generateToken)
    {
        if(routeValues== null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, RouteValueDictionary routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, bool generateToken)
    {
        var rvd = new RouteValueDictionary();
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, object routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, RouteValueDictionary routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, object routeValues, string protocol, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd, protocol);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd, protocol, hostName);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }
        
}Getting a protected URL in the view is easy as just passing a boolean parameter. Now let us see how to validate the URL when submitted to controller. It is even simpler. Just add this attribute to the controller method.
[IsValidURLRequest]

This attribute has taken care of the simple authorize check (user name, password verification), check for http referrer and protect the URL parameters.

Now for the TokenUtility that performs most of the work for creating the URL Hash.

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Routing;

/// <summary>
/// This is a static helper class which creates the URL Hash
/// </summary>
public static class TokenUtility
{
    public static string GenerateUrlToken(string controllerName, string actionName, RouteValueDictionary argumentParams, string password)
    {
        //// The URL hash is dynamic by assign a dynamic key in each session. So
        //// eventhough your URL is stolen, it will not work in other session
        if (HttpContext.Current.Session["url_dynamickey"] == null)
        {
            HttpContext.Current.Session["url_dynamickey"] = RandomString();
        }

        // The salt include the dynamic session key and valid for an hour.
        var salt = HttpContext.Current.Session["url_dynamickey"] + DateTime.Now.ToShortDateString() + " " + DateTime.Now.Hour;

        // generating the partial url
        var stringToToken = controllerName + "/" + actionName + "/";
        stringToToken = argumentParams.Where(item => item.Key != "controller" && item.Key != "action" && item.Key != "urltoken").Aggregate(stringToToken, (current, item) => current + (item.Value));

        // Converting the salt in to a byte array
        var saltValueBytes = System.Text.Encoding.ASCII.GetBytes(salt);

        // Encrypt the salt bytes with the password
        var key = new Rfc2898DeriveBytes(password, saltValueBytes);

        // get the key bytes from the above process
        var secretKey = key.GetBytes(16);

        // generate the hash
        var tokenHash = new HMACSHA1(secretKey);
        tokenHash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(stringToToken));

        // convert the hash to a base64string
        var token = Convert.ToBase64String(tokenHash.Hash).Replace("/", "_");

        return token;
    }

    /// <summary>
    /// This validates the token
    /// </summary>
    /// <param name="token">The token.</param>
    /// <param name="controllerName">Name of the controller.</param>
    /// <param name="actionName">Name of the action.</param>
    /// <param name="argumentParams">The argument params.</param>
    /// <param name="password">The password.</param>
    /// <returns></returns>
    public static bool ValidateToken(string token, string controllerName, string actionName, RouteValueDictionary argumentParams, string password)
    {
        // compute the token for the currrent parameter
        var computedToken = GenerateUrlToken(controllerName, actionName, argumentParams, password);

        // compare with the submitted token
        if (computedToken != token)
        {
            computedToken = GenerateUrlToken(string.Empty, actionName, argumentParams, password);
        }
        else { return true; }

        return computedToken == token;
    }

    /// <summary>
    /// It validates the token, where all the parameters passed as a RouteValueDictionary
    /// </summary>
    /// <param name="requestUrlParts">The request URL parts.</param>
    /// <param name="password">The password.</param>
    /// <param name="token">the Url encrypted token to be used to validate against</param>
    /// <returns></returns>
    public static bool ValidateToken(RouteValueDictionary requestUrlParts, string password, string token)
    {
        // get the parameters
        string controllerName;
        try
        {
            controllerName = Convert.ToString(requestUrlParts["controller"]);
        }
        catch (Exception)
        {
            controllerName = string.Empty;
        }

        var actionName = Convert.ToString(requestUrlParts["action"]);
        //var token = Convert.ToString(requestUrlParts["urltoken"]);

        // Compute a new hash
        var computedToken = GenerateUrlToken(controllerName, actionName, requestUrlParts, password);

        // compare with the submited hash
        if (computedToken != token)
        {
            computedToken = GenerateUrlToken(string.Empty, actionName, requestUrlParts, password);
        }
        else
        {
            return true;
        }

        return computedToken == token;
    }

    /// <summary>
    /// This method create the random dynamic key for the session
    /// </summary>
    /// <returns></returns>
    private static string RandomString()
    {
        var builder = new StringBuilder();
        var random = new Random();
        for (var i = 0; i < 8; i++)
        {
            var ch = Convert.ToChar(Convert.ToInt32(Math.Floor((26 * random.NextDouble()) + 65)));
            builder.Append(ch);
        }

        return builder.ToString();
    }
}

 

ExtendedHtmlActionLinkHelper (3).zip (277.13 kb)

Original Source

URL Validator

I needed to check to see if a URL that the user was entering was a valid Url, does it contain HTTP:// or HTTPS:// I ended up writing a small ValidationAttribute to add to the collection I am now building up, here is the code:

using System;
using System.ComponentModel.DataAnnotations;
using System.Net;

public class IsUriAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var myString = value.ToString();
        Uri myUri;
        if (Uri.TryCreate(myString, UriKind.Absolute, out myUri) && (myUri.Scheme == Uri.UriSchemeHttp || myUri.Scheme == Uri.UriSchemeHttps))
        {
            return ValidateUri(myUri);
        }
        return new ValidationResult("URL is invalid.\nStart with http:// or https:// and end with\na proper image extension");
    }

    private ValidationResult ValidateUri(Uri myUri)
    {
        var webRequest = WebRequest.Create(myUri);
        try
        {
            webRequest.GetResponse();
        }
        catch //If exception thrown then couldn't get response from address
        {
            return new ValidationResult("URL is invalid and does not exist");
        }
        return ValidationResult.Success;
    }
}
 

MVC way to check the File Extension

Following on from my article about checking for the file signature to ensure that the file is who it says it is

I decide to take it further and produce a Data Validation attribute, I found that the Microsoft.Web.Mvc.dll library already has one ,but it only checks for the file names, which is generally okay.

So I thought I’d enhance the Microsoft FileExtension attribute, but it was sealed……!  Grrrrrrrr  But Microsoft now have most of its code as open source, yaaaaa  🙂

So I downloaded the source and created my own variation of the FileExtensionsAttribute

First we need to generate DataTypeAttribute, and IClientValidatable to inherit.

IClientValidatable

using System.Collections.Generic;
using System.Web.Mvc;

public interface IClientValidatable
{
    IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context);
}

ModelClientValidationRule

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[TypeForwardedFrom("System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
public class ModelClientValidationRule
{
    private readonly Dictionary<string, object> _validationParameters = new Dictionary<string, object>();
    private string _validationType;

    public string ErrorMessage { get; set; }

    public IDictionary<string, object> ValidationParameters
    {
        get { return _validationParameters; }
    }

    public string ValidationType
    {
        get { return _validationType jQuery15201478678032162548_1380881227039 String.Empty; }
        set { _validationType = value; }
    }
}

Now the actual code for FileExtensionsAttribute

FileExtensionsAttribute

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DataValidation.Properties;

/// <summary>
/// The file extensions, default is png,jpg,jpeg,gif.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class FileExtensionsAttribute : DataTypeAttribute, IClientValidatable
{
    private string _extensions;
    private string _extensionsSignatures;

    public FileExtensionsAttribute()
        : base("upload")
    {
        ErrorMessage = DataValidationResource.FileExtensionsAttribute_Invalid;
    }

    /// <summary>
    /// The file extensions, default is png,jpg,jpeg,gif.
    /// </summary>
    /// <value>
    /// The extensions.
    /// </value>
    public string Extensions
    {
        get { return String.IsNullOrWhiteSpace(_extensions) ? "png,jpg,jpeg,gif" : _extensions; }
        set { _extensions = value; }
    }

    /// <summary>
    /// The extensions signatures, this is the fileclass signature within the actual file.
    /// </summary>
    /// <value>
    /// The extensions signatures.
    /// </value>
    public string ExtensionsSignatures
    {
        get { return String.IsNullOrWhiteSpace(_extensionsSignatures) ? "" : _extensionsSignatures; }
        set { _extensionsSignatures = value; }
    }

    private string ExtensionsFormatted
    {
        get { return ExtensionsParsed.Aggregate((left, right) => left + ", " + right); }
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private string ExtensionsNormalized
    {
        get { return Extensions.Replace(" ", String.Empty).Replace(".", String.Empty).ToLowerInvariant(); }
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private string ExtensionsSignaturesNormalized
    {
        get { return ExtensionsSignatures.Replace(" ", String.Empty).Replace(".", String.Empty).ToLowerInvariant(); }
    }

    private IEnumerable<string> ExtensionsParsed
    {
        get { return ExtensionsNormalized.Split(',').Select(e => "." + e); }
    }

    private IEnumerable<string> ExtensionsSignaturesParsed
    {
        get { return ExtensionsSignaturesNormalized.Split(','); }
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ExtensionsFormatted);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ValidationType = "extension",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };
        rule.ValidationParameters["extension"] = ExtensionsNormalized;
        yield return rule;
    }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return true;
        }

        var valueAsFileBase = value as HttpPostedFileBase;
        if (valueAsFileBase != null)
        {
            return ValidateExtension(valueAsFileBase.FileName) && ValidateFileContent(valueAsFileBase);
        }

        var valueAsString = value as string;
        return valueAsString != null && ValidateExtension(valueAsString);
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private bool ValidateExtension(string fileName)
    {
        try
        {
            return ExtensionsParsed.Contains(Path.GetExtension(fileName).ToLowerInvariant());
        }
        catch (ArgumentException)
        {
            return false;
        }
    }

    private bool ValidateFileContent(HttpPostedFileBase file)
    {
        var validExtensions = GetValidExtenstions();
            
        var br = new BinaryReader(file.InputStream);
        string fileclass;
        byte buffer;

        try
        {
            buffer = br.ReadByte();
            fileclass = buffer.ToString();
            buffer = br.ReadByte();
            fileclass += buffer.ToString();
        }
        catch
        {
            return false;
        }

        return string.IsNullOrWhiteSpace(ExtensionsSignatures)
            ? ExtensionsParsed.Where(validExtensions.ContainsKey).Any(extension => validExtensions[extension].ToString() == fileclass) 
            : ExtensionsSignaturesParsed.Any(extensionsSignatures => extensionsSignatures == fileclass);
    }

    private Dictionary<string, int> GetValidExtenstions()
    {
        var validExtenstions = new Dictionary<string, int>
                                    {
                                        {".gif", 7173},
                                        {".jpg", 255216},
                                        {".png", 13780},
                                        {".bmp", 6677},
                                        {".txt", 239187},
                                        {"/", 239187},
                                        {".asp", 239187},
                                        {".sql", 239187},
                                        {".xls", 208207},
                                        {".doc", 208207},
                                        {".docx", 208207},
                                        {".dot", 208207},
                                        {".dotx", 208207},
                                        {".ppt", 208207},
                                        {".xml", 6063},
                                        {".html", 6033},
                                        {".js", 4742},
                                        {".xlsx", 8075},
                                        {".zip", 8075},
                                        {".ptx", 8075},
                                        {".mmap", 8075},
                                        {".rar", 8297},
                                        {".accdb", 01},
                                        {".mdb", 01},
                                        {".exe", 7790},
                                        {".dll", 7790},
                                        {".bat", 64101},
                                        {".tiff", 7373},
                                        {".tif", 7373}
                                    };
        return validExtenstions;
    }
}

You’ll notice the ValidateFileContent method which is the additional feature I’ve added to check for the file signature.

That’s it job done

A sample project can be found here

FileUploader.zip (9.24 mb)

MVC running on IIS8

After a number of 500 errors coming up from IIS8 under Windows Server 2012, I final found the solution.

The solution was to go back to the Microsoft Server 2012 Dashboard and select the “Add Roles” feature. Scroll down to the root “Web Server (IIS)”, expand “Web Server”, expand “Application Development” and select “ASP.NET 3.5” and “ASP.NET 4.5” and “Install”.

What confused me originally was I hadn’t expanded “Application Development”, but selected IIS and continued. On the next step, “Features”, “.NET Framework 4.5 Features” was selected by default so I selected “.NET Framework 3.5 Features” and thought all would be fine.

Validating an e-mail address the DataAnnotation way

There are many ways to validate if an e-mail address is right, and many wrong ways.  The biggest wrong way is using a Regular expression, why?  They are complex and there is not one that resolves this issue, you will always get an invalid e-mail address that passes through okay.

So what can we do?  Why not use something that already works, something that someone else maintains, something we already have?

Let’s take a look at the System.Net.Mail name space, it has MailAddress, and if you add a string that is an invalid e-mail address it fails eg:

new MailAddress("invalidemailaddress");

This causes an exception to be thrown.

This mean you can use a single line of code to see if an e-mail is valid or not.

Let’s make it more practical and generate a ValidationAttribute that validates an email address for any given field in a model, what we are after doing is something like this:

    public class UserModel
    {
        [Required]
        public string name { get; set; }
        
        [Email]
        public string email { get; set; }
    }

To does this we just need to create an email attribute:

public class EmailAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid
        (object value, ValidationContext validationContext)
        {
            if (string.IsNullOrWhiteSpace(value?.ToString())) return ValidationResult.Success;

            try
            {
                new MailAddress(value.ToString());
            }
            catch (Exception)
            {
                return new ValidationResult("Please provide a valid email address.");
            }
            return ValidationResult.Success; 
         } 
     }

So simple when you know how to do it.