AutoFac AsyncRunner – Fix for Autofac not working with background tasks

Inspired from here:

https://stackoverflow.com/a/33830165/249895

Usage:

    public class ServiceModule :Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            
            builder.RegisterType<AutoFac.AsyncRunner>().As<AutoFac.IAsyncRunner>().SingleInstance();
        }
    }

private AutoFac.IAsyncRunner _asyncRunner;

public Controller(AutoFac.IAsyncRunner asyncRunner)
{
	
	_asyncRunner = asyncRunner;
}

public void Function()
{
	_asyncRunner.Run<IService>((cis) =>
   {
	   try
	   {
		  //do stuff
	   }
	   catch
	   {
		   // catch stuff
		   throw;
	   }
   });
}

Class:

public class AsyncRunner : IAsyncRunner
{
	private ILifetimeScope _lifetimeScope { get; set; }

	public AsyncRunner(ILifetimeScope lifetimeScope)
	{
		//Guard.NotNull(() => lifetimeScope, lifetimeScope);
		_lifetimeScope = lifetimeScope;
	}

	public Task Run<T>(Action<T> action)
	{
		Task.Factory.StartNew(() =>
		{
			using (var lifetimeScope = _lifetimeScope.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag))
			{
				var service = lifetimeScope.Resolve<T>();
				action(service);
			}
		});
		return Task.FromResult(0);
	}


}

HttpClient with Error Logging Handler and Retry Handler

Inspired from here: http://www.thomaslevesque.com/2016/12/08/fun-with-the-httpclient-pipeline/

 

Usage:

            var cookieContainer = new System.Net.CookieContainer();

            using (var httpClientHandler = new HttpClientHandler() { UseCookies = true, CookieContainer = cookieContainer })
            using (var errorLoggingHandler = new Handlers.LoggingHandler<AirWatchLogDto>(_httpGetLogger, httpClientHandler))
            //using (var retryHandler = new RetryHandler(errorLoggingHandler) { RetryCounterCount = retryCounterCount })
            using (var httpClient = new HttpClients.AirWatchCustomHeadersHttpClient(httpClientHandler, _appSettingsService))
            {
                HttpRequestMessage httpRequestMessage = new HttpRequestMessage(httpMethod, requestUri);

                if (httpMethod == HttpMethod.Post && postObject != null)
                {
                    string formattedJson = Newtonsoft.Json.JsonConvert.SerializeObject(postObject);
                    httpRequestMessage.Content = new StringContent(formattedJson, Encoding.UTF8, "application/json");
                }

                var httpReponseMessage = await httpClient.SendAsync(httpRequestMessage);
                string content = await httpReponseMessage.Content.ReadAsStringAsync();
                return httpReponseMessage;
            }

Retry Handler class:

    public class RetryHandler : DelegatingHandler
    {
        private int _retryCounterCount = 3;
        public int RetryCounterCount { get { return _retryCounterCount; } set { _retryCounterCount = value; } }

        public RetryHandler(HttpMessageHandler innerHandler) : base(innerHandler)
        {
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            int counter = 0;
            while (true)
            {
                try
                {
                    counter++;                    
                    // base.SendAsync calls the inner handler
                    var response = await base.SendAsync(request, cancellationToken);
                    
                    if (counter >= RetryCounterCount)
                    {
                        return response;
                    }
                    if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
                    {
                        // 503 Service Unavailable
                        // Wait a bit and try again later
                        await Task.Delay(5000, cancellationToken);
                        continue;
                    }

                    if (response.StatusCode == (HttpStatusCode)429)
                    {
                        // 429 Too many requests
                        // Wait a bit and try again later
                        await Task.Delay(1000, cancellationToken);
                        continue;
                    }

                    // Not something we can retry, return the response as is
                    return response;
                }
                catch (Exception ex) when (IsNetworkError(ex))
                {
                    if (counter >= RetryCounterCount)
                    {
                        throw;
                    }
                    // Network error
                    // Wait a bit and try again later
                    await Task.Delay(2000, cancellationToken);
                    continue;
                }
            }
        }

        private static bool IsNetworkError(Exception ex)
        {
            // Check if it's a network error
            if (ex is SocketException)
                return true;
            if (ex.InnerException != null)
                return IsNetworkError(ex.InnerException);
            return false;
        }
    }

Logging Handler:

    //http://www.thomaslevesque.com/2016/12/08/fun-with-the-httpclient-pipeline/
    public class LoggingHandler<T> : DelegatingHandler
    {
        private readonly IHttpClientEventLogger<T> _logger;

        public LoggingHandler(IHttpClientEventLogger<T> logger, HttpMessageHandler innerHandler) : base(innerHandler)
        {
            _logger = logger;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            try
            {
                _logger.MapRequest(request);
                
                var response = await base.SendAsync(request, cancellationToken);
                _logger.MapResponse(response);
                return response;
            }
            catch (Exception ex)
            {
                _logger.MapResponseException(ex);
                throw;
            }
            finally
            {
                _logger.LogEvent();
            }
        }
    }

    public class ErrorLoggingHandler<T> : DelegatingHandler
    {
        private readonly IHttpClientEventLogger<T> _logger;

        public ErrorLoggingHandler(IHttpClientEventLogger<T> logger, HttpMessageHandler innerHandler) : base(innerHandler)
        {
            _logger = logger;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            bool hasError = false;
            try
            {
                _logger.MapRequest(request);

                var response = await base.SendAsync(request, cancellationToken);
                
                return response;
            }
            catch (Exception ex)
            {
                hasError = true;
                _logger.MapResponseException(ex);
                throw;
            }
            finally
            {
                if(hasError)
                    _logger.LogEvent();
            }
        }
    }

Kendo Mvc CustomKendoMvcExtensions. DataSourceRequest Filters in case of Datetime comparison. Don’t take time into consideration

Usage:

return Json(requestsList.ToCustomDataSourceResult(request));

Or:

public ActionResult GetList([CustomDataSourceRequest]DataSourceRequest request)

Implementation:

using Kendo.Mvc;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;




namespace Kendo.Mvc.Extensions
{
    public static class CustomKendoMvcExtensions
    {
        /// <summary>
        /// Changes DataSourceRequest Filters in case of Datetime comparison. Does not take time into consideration
        /// //http://www.crowbarsolutions.com/ignoring-time-when-filtering-dates-in-telerik-kendo-grids/
        /// Adapted from above link.
        /// Uses CustomDataSourceRequestModelBinder.TransformFilterDescriptors function
        /// </summary>
        /// <param name="queryable"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public static DataSourceResult ToCustomDataSourceResult(this IQueryable queryable, DataSourceRequest request)
        {
            if (request.Filters != null && request.Filters.Count > 0)
            {

                ModelBinders.CustomDataSourceRequestModelBinder customModelBinder = new ModelBinders.CustomDataSourceRequestModelBinder();

                var transformedFilters = request.Filters.Select(customModelBinder.TransformFilterDescriptors).ToList();
                request.Filters = transformedFilters;
            }

            return queryable.ToDataSourceResult(request);
        }
    }
}


namespace Kendo.Mvc.UI
{
    //http://www.crowbarsolutions.com/ignoring-time-when-filtering-dates-in-telerik-kendo-grids/
    public class CustomDataSourceRequestAttribute : DataSourceRequestAttribute
    {
        public override IModelBinder GetBinder()
        {
            return new Kendo.Mvc.ModelBinders.CustomDataSourceRequestModelBinder();
        }
    }
}

namespace Kendo.Mvc.ModelBinders
{
    /// <summary>
    /// DateTime filtering is horribly unintuitive in Kendo Grids when a non-default (00:00:00) time is attached
    /// to the grid's datetime data. We use this custom model binder to transform the grid filters to return 
    /// results that ignore the attached time, leading to intuitive results that make users happy.
    /// 
    /// To use the code, substitute the [DataSourceRequest] attribute for [CustomDataSourceRequest] in your MVC controller
    /// </summary>
    public class CustomDataSourceRequestModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            // Get an instance of the original kendo model binder and call the binding method
            var baseBinder = new DataSourceRequestModelBinder();
            var request = (DataSourceRequest)baseBinder.BindModel(controllerContext, bindingContext);

            if (request.Filters != null && request.Filters.Count > 0)
            {
                var transformedFilters = request.Filters.Select(TransformFilterDescriptors).ToList();
                request.Filters = transformedFilters;
            }

            return request;
        }

        public IFilterDescriptor TransformFilterDescriptors(IFilterDescriptor filter)
        {
            if (filter is CompositeFilterDescriptor)
            {
                var compositeFilterDescriptor = filter as CompositeFilterDescriptor;
                var transformedCompositeFilterDescriptor = new CompositeFilterDescriptor { LogicalOperator = compositeFilterDescriptor.LogicalOperator };
                foreach (var filterDescriptor in compositeFilterDescriptor.FilterDescriptors)
                {
                    transformedCompositeFilterDescriptor.FilterDescriptors.Add(TransformFilterDescriptors(filterDescriptor));
                }
                return transformedCompositeFilterDescriptor;
            }
            if (filter is FilterDescriptor)
            {
                var filterDescriptor = filter as FilterDescriptor;
                if (filterDescriptor.Value is DateTime)
                {
                    var value = (DateTime)filterDescriptor.Value;
                    switch (filterDescriptor.Operator)
                    {
                        case FilterOperator.IsEqualTo:
                            //convert the "is equal to <date><time>" filter to a "is greater than or equal to <date> 00:00:00" AND "is less than or equal to <date> 23:59:59"
                            var isEqualCompositeFilterDescriptor = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.And };
                            isEqualCompositeFilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(filterDescriptor.Member,
                                FilterOperator.IsGreaterThanOrEqualTo, new DateTime(value.Year, value.Month, value.Day, 0, 0, 0)));
                            isEqualCompositeFilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(filterDescriptor.Member,
                                FilterOperator.IsLessThanOrEqualTo, new DateTime(value.Year, value.Month, value.Day, 23, 59, 59)));
                            return isEqualCompositeFilterDescriptor;

                        case FilterOperator.IsNotEqualTo:
                            //convert the "is not equal to <date><time>" filter to a "is less than <date> 00:00:00" OR "is greater than <date> 23:59:59"
                            var notEqualCompositeFilterDescriptor = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.Or };
                            notEqualCompositeFilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(filterDescriptor.Member,
                                FilterOperator.IsLessThan, new DateTime(value.Year, value.Month, value.Day, 0, 0, 0)));
                            notEqualCompositeFilterDescriptor.FilterDescriptors.Add(new FilterDescriptor(filterDescriptor.Member,
                                FilterOperator.IsGreaterThan, new DateTime(value.Year, value.Month, value.Day, 23, 59, 59)));
                            return notEqualCompositeFilterDescriptor;

                        case FilterOperator.IsGreaterThanOrEqualTo:
                            //convert the "is greater than or equal to <date><time>" filter to a "is greater than or equal to <date> 00:00:00"
                            filterDescriptor.Value = new DateTime(value.Year, value.Month, value.Day, 0, 0, 0);
                            return filterDescriptor;

                        case FilterOperator.IsGreaterThan:
                            //convert the "is greater than <date><time>" filter to a "is greater than <date> 23:59:59"
                            filterDescriptor.Value = new DateTime(value.Year, value.Month, value.Day, 23, 59, 59);
                            return filterDescriptor;

                        case FilterOperator.IsLessThanOrEqualTo:
                            //convert the "is less than or equal to <date><time>" filter to a "is less than or equal to <date> 23:59:59"
                            filterDescriptor.Value = new DateTime(value.Year, value.Month, value.Day, 23, 59, 59);
                            return filterDescriptor;

                        case FilterOperator.IsLessThan:
                            //convert the "is less than <date><time>" filter to a "is less than <date> 00:00:00"
                            filterDescriptor.Value = new DateTime(value.Year, value.Month, value.Day, 0, 0, 0);
                            return filterDescriptor;

                        default:
                            throw new Exception(string.Format("Filter operator '{0}' is not supported for DateTime member '{1}'", filterDescriptor.Operator, filterDescriptor.Member));
                    }
                }
            }
            return filter;
        }
    }
}

Difference between static class and singleton pattern?

An interesting question at an interview.

Some interesting answers here 

The big difference between a singleton and a bunch of static methods is that singletons can implement interfaces (or derive from useful base classes, although that’s less common, in my experience), so you can pass around the singleton as if it were “just another” implementation.

 

A singleton allows access to a single created instance – that instance (or rather, a reference to that instance) can be passed as a parameter to other methods, and treated as a normal object.

A static class allows only static methods.

 

A singleton can be initialized lazily or asynchronously while a static class is generally initialized when it is first loaded, leading to potential class loader issues. However the most important advantage, though, is that singletons can be handled polymorphically without forcing their users to assume that there is only one instance.

 

Investigation still ongoing. 🙂

An answer I received today is that Singleton is thread safe(or can be made), whyle static is not.
Static is created once at the start of the application.

Another is that you can inherit, transform Sigleton class.

Still looking for more answers.

Left side, vertical, scroll through menu

If you want to create a vertical menu that scrolls through the items as you scrolls through the page

 

HTML:

<nav id="leftMenu">
	<ul class="sidebar-nav nav leftMenuItems padding-0">
		<li><h4>Navigation Menu</h4></li>
		<li class="active">     <a id="menuItem202" href="#formSectionInstance_202">Menu Item 1</a> </li>
		<li><a id="menuItem203" href="#formSectionInstance_203">Menu Item 2<</a></li>
		<li><a id="menuItem204" href="#formSectionInstance_204">Menu Item 3<</a></li>
		<li><a id="menuItem208" href="#formSectionInstance_208">Menu Item 4<</a></li>
		<li><a id="menuItem206" href="#formSectionInstance_206">Menu Item 5<</a></li>
		<li><a id="menuItem207" href="#formSectionInstance_207_documentUpload">Menu Item 6<</a></li>
	</ul>
</nav>

 

Javascript:

function BindEventsToFormMenuItems()
{
	// Cache selectors
	var lastId,
		topMenu = $("#navbar"),
		leftMenu = $("#leftMenu"),
		topMenuHeight = topMenu.outerHeight() + 15,
		// All list items
		menuItems = leftMenu.find("a"),
		// Anchors corresponding to menu items
		scrollItems = menuItems.map(function ()
		{
			var item = $($(this).attr("href"));
			if (item.length) { return item; }
		});

	// Bind click handler to menu items
	// so we can get a fancy scroll animation
	menuItems.each(function (index) {
		$(this).click(function (e) {
			var href = $(this).attr("href"),
				offsetTop = href === "#" ? 0 : $(href).offset().top - topMenuHeight + 1;
			$('html, body').stop().animate({
				scrollTop: offsetTop
			}, 300);
			e.preventDefault();
			
			if ($('#menu-toggle').is(':visible'))
			{
				$("#menu-toggle").trigger("click");
			}

			menuItems.parent().removeClass("active");
			$(this).parent().addClass("active");
		});
	});

	// Bind to scroll
	$(window).scroll(function ()
	{
		// Get container scroll position
		var fromTop = $(this).scrollTop() + topMenuHeight + 50;

		// Get id of current scroll item
		var cur = scrollItems.map(function ()
		{
			if ($(this).offset().top < fromTop)
				return this;
		});
		// Get the id of the current element
		cur = cur[cur.length - 1];
		var id = cur && cur.length ? cur[0].id : "";

		if (lastId !== id)
		{
			lastId = id;
			// Set/remove active class
			menuItems
			  .parent().removeClass("active")
			  .end().filter("[href='#" + id + "']").parent().addClass("active");
		}
	});
}

SQL Server – make a copy of parent child rows

Let us say we have 2 tables that are in a parent-child relation.

We want to make a copy of the FormSectionInstance rows, but also copy and correlate the FormDetails rows.

This means copy rows from 2 tables and then set them up with the correct NEW corresponding IDs.

We could use a cursor, but a better alternative is the the MERGE INTO function.

We also create a TEMP transition table to hold the new VS old values. We use these values when we insert the CHILD values.

This way we can make the INSERT faster.

-- Copy the FormSectionInstance
DECLARE @FormSectionInstanceTable TABLE(OldFormSectionInstanceId INT, NewFormSectionInstanceId INT)

;MERGE INTO [dbo].[FormSectionInstance]
USING
(
	SELECT
		fsi.FormSectionInstanceId [OldFormSectionInstanceId]
		, @NewFormHeaderId [NewFormHeaderId]
		, fsi.FormSectionId
		, fsi.IsClone
		, @UserId [NewCreatedByUserId]
		, GETDATE() NewCreatedDate
		, @UserId [NewUpdatedByUserId]
		, GETDATE() NewUpdatedDate
	FROM [dbo].[FormSectionInstance] fsi
	WHERE fsi.[FormHeaderId] = @FormHeaderId 
) tblSource ON 1=0 -- use always false condition
WHEN NOT MATCHED
THEN INSERT
( [FormHeaderId], FormSectionId, IsClone, CreatedByUserId, CreatedDate, UpdatedByUserId, UpdatedDate)
VALUES( [NewFormHeaderId], FormSectionId, IsClone, NewCreatedByUserId, NewCreatedDate, NewUpdatedByUserId, NewUpdatedDate)
	
OUTPUT tblSource.[OldFormSectionInstanceId], INSERTED.FormSectionInstanceId
INTO @FormSectionInstanceTable(OldFormSectionInstanceId, NewFormSectionInstanceId);
	

-- Copy the FormDetail
INSERT INTO [dbo].[FormDetail]
	(FormHeaderId, FormFieldId, FormSectionInstanceId, IsOther, Value, CreatedByUserId, CreatedDate, UpdatedByUserId, UpdatedDate)
SELECT
	@NewFormHeaderId, FormFieldId, fsit.NewFormSectionInstanceId, IsOther, Value, @UserId, CreatedDate, @UserId, UpdatedDate
FROM [dbo].[FormDetail] fd
INNER JOIN @FormSectionInstanceTable fsit ON fsit.OldFormSectionInstanceId = fd.FormSectionInstanceId
WHERE [FormHeaderId] = @FormHeaderId 

Web.config transform from template and transformation files

This solution is usefull when you want to debug on multiple environments.

Just add ad template file, some transformation config files and then select your desired Solution configuration.

Web config will be changed on the spot.

 

Also usefull when you want to publish on different environments.

 

You can setup different web.cofig configurations.

<Target Name="BeforeBuild">
    <TransformXml Source="$(WebFolderName)Web.Template.config" Transform="$(WebFolderName)Web.$(Configuration).config" Destination="$(WebFolderName)Web.config" />
</Target>

MVC CustomAuthorizeAttribute using Reflection to get Controllers and Actions

Code beautifier used: http://hilite.me/ 

Usage:

    [CustomAuthorize]
    public class AdministrationController : BaseController
    {
        #region Users List

        [NavigationMenuEnumAuthorize(NavigationMenuEnum.UserAdministration)]
        public ActionResult Index()
        {
            return View();
        }
    }

 

CustomAuthorizeAttrbute Code:

namespace System.ComponentModel.DataAnnotations
{

    public class NavigationMenuEnumAuthorizeAttribute : System.Attribute
    {
        public List NavigationMenuEnumList { get; set; }
        public NavigationMenuEnumAuthorizeAttribute(params NavigationMenuEnum[] navigationPages)
        {
            NavigationMenuEnumList = new List();
            if (navigationPages != null && navigationPages.Count() > 0)
            {
                NavigationMenuEnumList = navigationPages.ToList();
            }
        }
    }

    public class CustomAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
    {
        string currentAction;
        string currentController;
        string currentArea;
        public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var routeData = httpContext.Request.RequestContext.RouteData;

            currentAction = routeData.GetRequiredString("action");
            currentController = routeData.GetRequiredString("controller");
            currentArea = routeData.Values["area"] as string;

            if (Utils.CurrentUser == null)
                return false;

            Dictionary<NavigationMenuEnum, bool> menuSecurity = new Dictionary<NavigationMenuEnum, bool>();

            using (var dbContext = new Web.Models.ConnectionStringEDMX())
            {
                int userid = Utils.CurrentUser.UserId;

                menuSecurity[NavigationMenuEnum.CreateNewForm] = false;
                menuSecurity[NavigationMenuEnum.CreateNewChildForm] = false;
                menuSecurity[NavigationMenuEnum.EditNewForm] = false;
                menuSecurity[NavigationMenuEnum.FormSummary] = false;
                menuSecurity[NavigationMenuEnum.AllRequests] = false;
                menuSecurity[NavigationMenuEnum.MyRequests] = false;
                menuSecurity[NavigationMenuEnum.WaitingForApproval] = false;
                menuSecurity[NavigationMenuEnum.UserAdministration] = false;
                menuSecurity[NavigationMenuEnum.Delegate] = false;
                menuSecurity[NavigationMenuEnum.Reporting] = false;

                if (userid == 0)
                {
                    httpContext.Session[Web.Helpers.StaticStrings.MenuSecuritySessionName] = (Dictionary<NavigationMenuEnum, bool>)menuSecurity;
                    return false;
                }

                var userRoles = dbContext.admUserRoles.Where(x => x.UserId == userid || Utils.CurrentUser.CurrentUserDelegatedForUserIdList.Contains(x.UserId));

                foreach (admUserRole userRole in userRoles)
                {
                    switch ((EnRoles)userRole.RoleId)
                    {
                        case EnRoles.Admin:
                            {
                                menuSecurity[NavigationMenuEnum.CreateNewForm] = true;
                                menuSecurity[NavigationMenuEnum.CreateNewChildForm] = true;
                                menuSecurity[NavigationMenuEnum.EditNewForm] = true;
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.MyRequests] = true;
                                menuSecurity[NavigationMenuEnum.WaitingForApproval] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                menuSecurity[NavigationMenuEnum.UserAdministration] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                menuSecurity[NavigationMenuEnum.Reporting] = true;
                                break;
                            }
                        case EnRoles.Originator:
                            {
                                menuSecurity[NavigationMenuEnum.CreateNewForm] = true;
                                menuSecurity[NavigationMenuEnum.CreateNewChildForm] = true;
                                menuSecurity[NavigationMenuEnum.EditNewForm] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.MyRequests] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                break;
                            }
                        case EnRoles.Reviewer:
                            {
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.WaitingForApproval] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                break;
                            }
                        case EnRoles.Approver:
                            {
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.WaitingForApproval] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                break;
                            }
                        case EnRoles.Reporting:
                            {
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.Reporting] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                break;
                            }
                        case EnRoles.Viewer:
                            {
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                break;
                            }
                        case EnRoles.Supervisor:
                            {
                                menuSecurity[NavigationMenuEnum.AllRequests] = true;
                                menuSecurity[NavigationMenuEnum.WaitingForApproval] = true;
                                menuSecurity[NavigationMenuEnum.FormSummary] = true;
                                menuSecurity[NavigationMenuEnum.Delegate] = true;
                                break;
                            }
                        default:
                            {
                                break;
                            }
                    }
                }
            }

            httpContext.Session[Web.Helpers.StaticStrings.MenuSecuritySessionName] = (Dictionary<NavigationMenuEnum, bool>)menuSecurity;
            
            List pageMapping = GetGeneralPageDetailsList(); // all page mappings are generating from controllers that have the CustomAuthorizeAttribute and Actions that have the NavigationMenuEnumAuthorizeAttribute


            if (!pageMapping.Any(x => x.Action == currentAction && x.Controller == currentController))
                return true;

            NavigationMenuEnum currentPage = pageMapping.Where(x => x.Action == currentAction && x.Controller == currentController).Select(x => x.Page).FirstOrDefault();

            return menuSecurity[currentPage];
        }

        public class PageDetails
        {
            public string Action { get; set; }
            public string Controller { get; set; }
            public NavigationMenuEnum Page { get; set; }
            public PageDetails(string action, string controller, NavigationMenuEnum page)
            {
                this.Action = action;
                this.Controller = controller;
                this.Page = page;
            }
                }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {            
            if (Utils.CurrentUser == null || Utils.CurrentUser.UserId == 0)
            {
                filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary 
                        {
                            { "area", "" },
                            { "controller", "Home" },
                            { "action", "SignIn" }
                        });
            }
            else
            {
                filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary 
                        {
                            { "area", "" },
                            { "controller", "Account" },
                            { "action", "NoAccess" }
                        });
            }
            return;
            base.HandleUnauthorizedRequest(filterContext);
        }

        /// https://stackoverflow.com/a/11305443/249895
        public List GetGeneralPageDetailsList()
        {
            try
            {
                ///https://stackoverflow.com/a/30969888/249895
                Assembly asm = Assembly.GetAssembly(typeof(MvcApplication));

                var controllerTypesList = asm.GetTypes().Where(type => typeof(System.Web.Mvc.Controller).IsAssignableFrom(type));

                var returnPagesList = new List();

                foreach (var controllerType in controllerTypesList)
                {
                    var reflectedControllerDescriptor = new ReflectedControllerDescriptor(controllerType);
                    string controllerName = reflectedControllerDescriptor.ControllerName;
                    var customAuthorizeAttributeList = reflectedControllerDescriptor.GetCustomAttributes(typeof(CustomAuthorizeAttribute), true);

                    if (customAuthorizeAttributeList != null && customAuthorizeAttributeList.Count() > 0)
                    {
                        var actionsList = reflectedControllerDescriptor.GetCanonicalActions();
                        foreach (var action in actionsList)
                        {
                            var attributesList = action.GetCustomAttributes(typeof(NavigationMenuEnumAuthorizeAttribute), true).Select(x => (NavigationMenuEnumAuthorizeAttribute)x).ToList();
                            if (attributesList != null && attributesList.Count() > 0)
                            {
                                foreach (var attribute in attributesList)
                                {
                                    foreach (var navigMenuEnum in attribute.NavigationMenuEnumList)
                                    {
                                        var page = new CustomAuthorizeAttribute.PageDetails(action.ActionName, controllerName, navigMenuEnum);
                                        returnPagesList.Add(page);
                                    }
                                }
                            }
                            else
                            {
                                var page = new CustomAuthorizeAttribute.PageDetails(action.ActionName, controllerName, NavigationMenuEnum.None);
                                returnPagesList.Add(page);
                            }
                        }
                    }
                }

                return returnPagesList;
            }
            catch (ReflectionTypeLoadException ex)
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                foreach (Exception exSub in ex.LoaderExceptions)
                {
                    sb.AppendLine(exSub.Message);
                    System.IO.FileNotFoundException exFileNotFound = exSub as System.IO.FileNotFoundException;
                    if (exFileNotFound != null)
                    {
                        if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
                        {
                            sb.AppendLine("Fusion Log:");
                            sb.AppendLine(exFileNotFound.FusionLog);
                        }
                    }
                    sb.AppendLine();
                }
                string errorMessage = sb.ToString();
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
                Exception newEx = new Exception(errorMessage);
                Elmah.ErrorSignal.FromCurrentContext().Raise(newEx);
                throw newEx;
                //Display or log the error based on your application.
            }
            catch (Exception ex)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
                throw;
            }
        }
    }


}