Issue of RazorViewEngine caching and Layout location in .NET Core

 

 

I recently tried to implement the razor  email template explained by Scott Sauber

Tutorial here: https://scottsauber.com/2018/07/07/walkthrough-creating-an-html-email-template-with-razor-and-razor-class-libraries-and-rendering-it-from-a-net-standard-class-library/

                         

All fine and dandy until I had issues regarding the template file. Problem was that even though the file is in ‘~\bin\Debug\netcoreapp2.2’ it searches for the template in the root folder such as ‘rootfolder\Views\Shared\_Layout.cshtml’ and not in ‘rootfolder\bin\Debug\netcoreapp2.2\Views\Shared\_Layout.cshtml’.

 

This is most likely generated by the fact that I have the views as an embedded resource in a CLASS LIBRARY and not in a Web Api solution directly.

 

The weird part is that if you do not have the files in the root folder, you still get the CACHED Layout page.

The good part is that when you PUBLISH the solution, it flattens the solution so the VIEWS are in ROOT folder.

 

[Solution]

The solution seems to be in the Startup.cs folder.

Got my solution from here: https://stackoverflow.com/q/50934768/249895

//https://stackoverflow.com/q/50934768/249895
     services.Configure<Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions>(o => {
                o.ViewLocationFormats.Add("/Views/{0}" + Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.ViewExtension);
                o.FileProviders.Add(new Microsoft.Extensions.FileProviders.PhysicalFileProvider(AppContext.BaseDirectory));
            });

After this, you can put your code like this:

var contentRootPath = _hostingEnvironment.ContentRootPath;
string executingAssemblyDirectoryAbsolutePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string executingAssemblyDirectoryRelativePath = System.IO.Path.GetRelativePath(contentRootPath, executingAssemblyDirectoryAbsolutePath);

string executingFilePath = $"{executingAssemblyDirectoryAbsolutePath.Replace('\\', '/')}/Views/Main.cshtml";
string viewPath = "~/Views/Main.cshtml";
string mainViewRelativePath = $"~/{executingAssemblyDirectoryRelativePath.Replace('\\','/')}/Views/Main.cshtml";

var getViewResult = _viewEngine.GetView(executingFilePath: executingFilePath, viewPath: viewPath, isMainPage: true);

<!-- OR -->

var getViewResult = _viewEngine.GetView(executingFilePath: viewPath, viewPath: viewPath, isMainPage: true);

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();
            }
        }
    }

Validating a view model after custom model binding

Adapted from here:
https://stackoverflow.com/questions/13684354/validating-a-view-model-after-custom-model-binding

Usage:

CustomModelBinderHelper.DoValidation(bindingContext, indexViewModel);

Implementation:

    public static class CustomModelBinderHelper
    {
        /// <summary>
        /// https://stackoverflow.com/a/22652195/249895
        /// </summary>
        /// <param name="bindingContext"></param>
        /// <param name="model"></param>
        public static void DoValidation(ModelBindingContext bindingContext, IValidatableObject model)
        {
            var validationResults = new HashSet<ValidationResult>();
            var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true);
            if (!isValid)
            {
                var resultsGroupedByMembers = validationResults
                    .SelectMany(_ => _.MemberNames.Select(
                         x => new
                         {
                             MemberName = x ?? "",
                             Error = _.ErrorMessage
                         }))
                    .GroupBy(_ => _.MemberName);

                foreach (var member in resultsGroupedByMembers)
                {
                    bindingContext.ModelState.AddModelError(
                        member.Key,
                        string.Join(". ", member.Select(_ => _.Error)));
                }
            }
        }
    }

 

To be noted that objects have to implment System.ComponentModel.DataAnnotations.IValidatableObject interface.

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;
        }
    }
}

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>

Kendo Mvc GridHelper

Code beautifier: http://hilite.me/

Usage

@(Html.CustomKendoGrid<ViewModels.UserViewModel>("grid"))

Code:

namespace Kendo.Mvc.UI
{
    //read here about Func vs Action https://stackoverflow.com/a/12687775/249895
    public static class KendoMvcGridHelper
    {

        public static readonly int AxajPageSize = 20;
        public static readonly int AxajPageSizeSmall = 10;

        public static Kendo.Mvc.UI.Fluent.GridBuilder CustomKendoGrid(this HtmlHelper helper, string name) where T : class
        {
            var returnGridBuilder = helper.Kendo().Grid();
            returnGridBuilder = returnGridBuilder.Name(name);
            returnGridBuilder = ConfigureGridBuilder(returnGridBuilder);

            return returnGridBuilder;
        }

        private static GridBuilder ConfigureGridBuilder(GridBuilder gridBuilder) where T : class
        {
            gridBuilder = gridBuilder.Pageable(p => p.PageSizes(new List<int>() { 10, 20 }));
            gridBuilder = gridBuilder.Sortable();
            gridBuilder = gridBuilder.Resizable(r => r.Columns(true));
            gridBuilder = gridBuilder.Filterable(ConfigureGridFilterableSettingsBuilder);
            gridBuilder = gridBuilder.Pageable();
            return gridBuilder;
        }


        public static void ConfigureGridFilterableSettingsBuilder(GridFilterableSettingsBuilder config)        
        {
            config = config.Mode(GridFilterMode.Row).Extra(false);
            config = config.Operators(ConfigureFilterableOperators);
        }

        public static void ConfigureFilterableOperators(FilterableOperatorsBuilder operators)
        {
            operators = operators.ForString(str => str.Clear()
                        .IsEqualTo("Is equal to")
                        .IsNotEqualTo("Is not equal to")
                        .StartsWith("Starts with")
                        .EndsWith("Ends with")                        
                        .Contains("Contains")
                        .DoesNotContain("Does not contain")
                    )
                    .ForDate(str => str.Clear()
                        .IsEqualTo("Is Equal To")
                        .IsGreaterThan("Is Greater Than")
                        .IsGreaterThanOrEqualTo("Is Greater Than Or Equal To")
                        .IsLessThan("Is Less Than")
                        .IsLessThanOrEqualTo("Is Less Than Or Equal To")
                        .IsNotEqualTo("Is Not Equal To")
                    )
                    .ForEnums(str => str.Clear()
                        .IsEqualTo("Is Equal To")
                        .IsNotEqualTo("Is Not Equal To")
                    )
                    .ForNumber(str => str.Clear()
                        .IsEqualTo("Is Equal To")
                        .IsGreaterThan("Is Greater Than")
                        .IsGreaterThanOrEqualTo("Is Greater Than Or Equal To")
                        .IsLessThan("Is Less Than")
                        .IsLessThanOrEqualTo("Is Less Than Or Equal To")
                        .IsNotEqualTo("Is Not Equal To")
                    );
        }
    }
}

Azure BlobStorageHelper – Blob create and upload

Code beautifier: http://hilite.me/

Code: 

namespace Helpers
{
    public sealed class BlobStorageHelper : StorageHelper
    {
        private readonly CloudBlobClient _blobClient;
        public string _containerName { get; set; }

        public BlobStorageHelper() : base()
        {
            _blobClient = base.StorageAccount.CreateCloudBlobClient();
            _containerName = ConfigurationManager.AppSettings["StorageContainerName"];
        }


        public Uri CreateBlob(Stream inputStream, string blobName)
        {
            CloudBlobContainer container = _blobClient.GetContainerReference(_containerName);
            container.CreateIfNotExists();

            ICloudBlob blob = container.GetBlockBlobReference(blobName);
            blob.UploadFromStream(inputStream);

            return blob.Uri;
        }

        public Uri CreateBlob(byte[] byteArray, string blobName)
        {
            CloudBlobContainer container = _blobClient.GetContainerReference(_containerName);
            container.CreateIfNotExists();

            ICloudBlob blob = container.GetBlockBlobReference(blobName);
            blob.UploadFromByteArray(byteArray, 0, byteArray.Length);

            return blob.Uri;
        }

        public string GetBlobFileDownloadPath(string blobPath)
        {
            string blobName = blobPath.Substring(blobPath.IndexOf("/" + _containerName + "/")).Replace("/" + _containerName + "/", "");

            CloudBlobContainer container = _blobClient.GetContainerReference(_containerName);
            container.CreateIfNotExists();

            ICloudBlob cloudBlob = container.GetBlobReferenceFromServer(blobName);

            var sasConstraints = new SharedAccessBlobPolicy();
            sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5);
            sasConstraints.Permissions = SharedAccessBlobPermissions.Read;

            var sasBlobToken = cloudBlob.GetSharedAccessSignature(sasConstraints);

            return blobPath + sasBlobToken;
        }

        public void DeleteBlob(string blobPath)
        {
            CloudBlobContainer container = _blobClient.GetContainerReference(_containerName);
            container.CreateIfNotExists();

            CloudBlob cloudBlob = container.GetBlockBlobReference(blobPath);

            cloudBlob.DeleteIfExists();
        }
    }
}

 

Azure BlobStorageHelper – Download file as byte array

Code beautifier: http://hilite.me/

Helper code: 

namespace Helpers
{
    public class BlobStorageHelper : StorageHelper
    {
        private readonly CloudBlobClient _blobClient;
        public string _containerName { get; set; }

        public BlobStorageHelper()
            : base()
        {
            _blobClient = base.StorageAccount.CreateCloudBlobClient();
            _containerName = ConfigurationManager.AppSettings["StorageContainerName"];
        }

        protected Stream DownloadBlobAsStream(string blobUri)
        {
            CloudStorageAccount account = this.StorageAccount;
            CloudBlockBlob blob = GetBlockBlobReference(account, blobUri);

            Stream mem = new MemoryStream();
            if (blob != null)
            {
                blob.DownloadToStream(mem);                
            }

            return mem;
        }

        private CloudBlockBlob GetBlockBlobReference(CloudStorageAccount account, string blobUri)
        {
            string blobName = blobUri.Substring(blobUri.IndexOf("/" + _containerName + "/")).Replace("/" + _containerName + "/", "");
            CloudBlobClient blobclient = account.CreateCloudBlobClient();
            CloudBlobContainer container = _blobClient.GetContainerReference(_containerName);
            container.CreateIfNotExists();
            CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
            return blob;
        }


        public byte[] DownloadBlobAsByeArray(string blobUri)
        {
            Stream inputStream = DownloadBlobAsStream(blobUri);

            byte[] buffer = new byte[16 * 1024];

            inputStream.Position = 0; // Add this line to set the input stream position to 0

            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = inputStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }

       
    }


    public abstract class StorageHelper
    {
        protected readonly CloudStorageAccount StorageAccount;

        public StorageHelper()
        {
            this.StorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        }
    }
}

 

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;
            }
        }
    }


}