Provide custom variables to every view in MVC (settings) - c#

I want to implement a CMS and I would like to make some settings available to views.
These settings may be the web site's name, the company name and maybe some more complex items.
I would like these to be available on every view without using strongly typed Models, something like ViewData-ViewBag but without having to set it in every action.
I think that I have to create a ControllerFactory that will set the ViewBag on every CreateController.
What do you think that it's the best solution for this problem?
Possible duplication at Execute Code on Every Request

Create your own application controller and override OnActionExecuting. There you can initialize your own properties in Viewbag:
public abstract class ApplicationController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// set your ViewBag.Settings here
}
}
Create all of your controller classes derived from ApplicationController:
public class HomeController : ApplicationController { ... }
Now you can access ViewBag.Settings from all of your views without setting this property explicitly in each action.

Related

Capture User last request timestamp in ASP NET Web API

I'm looking for a good place in the ASP.NET Web API lifecycle To update a property in my User entity that is purposed to store the date and time the User last made a request. Obviously, I could just add the code to each of my Controller methods but I would prefer doing this in one place outside of my controllers.
Ideally I would have access to the User principal and could use its Identity property to get the user's ID so that I could retrieve and update my User entity using Entity Framework.
I am currently looking at using a DelegatingHandler implementation.
Can anyone suggest the place in the lifecycle where I should carry this out? A code example would be appreciated.
Create an ActionFilter:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Do your work
}
}
Yes, but wouldn't I have to add the ActionFilter to each and every controller method?
No, you can apply it to the controller or to actions.
Alternatively, you can do the following and you will not have to apply it to every controller (sort of like a global filter):
[LogActionFilter ]
public class LogableApiController : ApiController
{
...
}
Then inherit that wherever you want.
And lastly, another option is to add to global filters by finding the App_Start/FilterConfig.cs and add:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LogActionFilter());
}
So I have shown you how to apply it to action level, controller level, one or more controllers but not all controllers and then how to apply it to all controllers (global).
I would create an Attribute for your Controller to execute the update on your User Entity with an ActionFilter.
This example explain how to create an attribute for a controller method, it is the same way to do it: Custom Attribute above a controller function
b.e, your controller would be like this:
[SaveUserRequest]
public class HomeController : ApiController

Front Controller in MVC c#

Could someone tell me which is the front controller in MVC 4 c# visual studio please?
I mean, i have to do a big application and i want add security to restrict the access to the controllers and actions. I used to do this in the Logistic of the Front Controller in CodeIgniter, adding a token to the session, so if someone wanted to write the route manually on the browser he couldnt access.
I've been reading about [Authorize(Roles="Admin")] and i have to admit that is a solution, but that means i have to write in every method of the all controllers, and i want to have that centralized in the front-controller with IF/ELSE.
PD: If you don't know how to do this, at least try to tell me where can i find the front controller in MVC c# visual studio please.
Thanks for all.
There is no front controller in MVC. You need to create a base controller , And your every controller will inherit Base controller.
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var getControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var getActionName = filterContext.ActionDescriptor.ActionName;
//Write your code here
}
}
Now Inherit your controller with Base controller.
public class AccountController : BaseController
{
//Your action goes here.
}
There is no such thing as a front controller in ASP MVC. I think the thing you're looking for is some sort of base controller where all of the other controllers inherit from.
You can add this Authorize attribute to methods or classes (whole controllers). If every action needs this attribute I suggest to create a master controller and let every controller inherit from this controller.
Consider using action filters.
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/understanding-action-filters-cs

What is the clean way to Implement Audit Trail in Asp.net MVC and Web API

I am trying to look for a more clean way to add audit trail function to an exist asp.net MVC and Web Api project which contains hundreds of Controller and ApiController.
The Audit trail log would look like below. Basically I just want to log In what time who did what in this function.
UserID
ActionTime
Controller
Action
Anything I missed ? If there is . Please correct me. Thanks.
Currently I found there are some ways to make it .
Implement an ActionFilterAttribute and write my own log function in the OnActionExecuting, and then decorate all the actions with this attribute.
Implement a base Controller like BaseController for all the exist controller. And write log in the OnActionExecuting. Then change all the controller to inherit from BaseController. (If it is wrong . Please correct me . Thanks.)
For the ApiController. Implement a DelegatingHandler to make it.
For 1 and 2. I need change to all the exist code to make it. like change base class or decorate with new attribute. Considering in my case, This will be a hard work. Because thousands of class or methods need to be changed . I thinks it is kind of verbose. So I wondered if there is some clean way like 3 for ApiController to make it. Thanks.
I find that using global action filters is the best way to handle cross-cutting/aspect-oriented concerns such as this.
Note that this code is not tested.
public class AuditFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var userName = HttpContext.Current.User.Identity.Name;
var time = DateTime.Now.ToString(CultureInfo.InvariantCulture);
var controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
var actionName = actionContext.ActionDescriptor.ActionName
Logger.Log(string.Format("user: {0}, date: {1}, controller {2}, action {3}", userName, time, controllerName, actionName));
}
}
And somewhere in your application startup pipeline, register the filter globally:
GlobalConfiguration.Configuration.Filters.Add(new AuditFilter());
Are you using a DI container? If you are or want to use a DI container, that could intercept all requests to the controllers. That way you don't change codes in hundreds of controllers, albeit simple change.
Here's Castle Windsor DI.
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
Have a look at the examples on this site if you intended to use it. I am sure there is a way to use it for both Web API and MVC controllers.

ASP.NET MVC Base Controller with Initialize() gets executed multiple times with HTml.Action()

This is a question about best-practices in ASP.NET MVC
I've created a website in MVC. Because every page has a menu, I thought I'd create a base controller class which all MVC Controllers in the project inherit from. In The Initialize() function of the base controller class I would then load my Menu.
In that way, I could keep my logic for loading the menu in one place and have it executed automatically.
Code (C#):
public abstract class BaseController : System.Web.Mvc.Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
//Load the menu:
ViewBag.HeaderModel = LoadMenu();
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
//the menu is loaded by the base controller, so we can just return the view here
return View();
}
}
That works like a charm. Now here's the problem.
In my View, I present a list of the five latest Articles on the website. Since the Articles have their own logic and their own section on the website, I've created an ArticleController, which inherits from BaseController as well, with an action that displays a PartialResult with my five latest Articles.
public class ArticlesController : BaseController
{
public ActionResult DisplayLatestArticles()
{
var model = ... //abbreviated, this loads the latest articles
return PartialView("LatestArticles", model);
}
}
And the method is called like this in the View:
#Html.Action("Index", new { controller = "Articles" })
But this has one drawback: namely the Initialize() function on my Base Controller is executed twice, which loads the menu two times, which is undesirable (for performance reasons). So far I haven't been able to find a way to avoid this behavior.
What do you suggest in so far as refactoring this code? I want to make sure my logic to load my menu stays somewhere so it gets called automatically, without me or any other developers on the project having to worry about it. I prefer keeping my logic to display the latest Articles in the ArticlesController so everything to do with Articles is kept in its own Controller.
So, how best to proceed?
What you're trying to do is more suited to calling your header menu from a _Layout.cshtml page.
_Layout.cshtml:
<html>
...
<body>
...
#Html.Action("Header", "SharedStuff")
...
SharedStuffController.cs
public ActionResult Header()
{
// logic to create header, also create a view
return this.View();
}
Base controllers, I feel, are normally the wrong way to go. The above means that you keep all logic for the header nicely contained in something that describes it.
I am not expert on the MVC and landed on this page while searching for my own answer. I completely agree that Base contoller should not be used for generating menu items. However, for what so ever reason, if you wanted to continue using base controller, I would suggest the controller that returns partial views (i.e ArticlesController) should not inherit from base controller and it should inherit from Controller class.

Getting Filter.OnAuthorization to run before Controller.OnAuthorization

I have an existing site which has a base controller class for all of its controllers which overrides the implementation of OnAuthorization. In the simplest cut down form:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//Do Stuff
}
This all works fine and well and does what it wants at the right time. I now want to add a new global authorization that will run before all other authorisation attributes. For test purposes this attribute looks like this:
public class TestFilterAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var text = "debug point";
return;
}
}
And is added to the Global Filters like this:
filters.Add(new TestFilterAttribute());
My problem is that the OnAuthorization of the controller always seems to run before my filter's one. Is there any way that I can change this? I've tried playing with the order property that you can set when adding it to the global filter collection but that doesn't seem to help.
I could probably move the logic of the Controller's OnAuthorization into a new filter attribute when order would probably be usable but I'd rather avoid major code restructuring if there is an easier way to do it.
I've been searching for information on the Controller.OnAuthorization method but the best I have found is http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx which only talks about filters. I had assumed that they would work the same way on Controllers but they seem to be getting treated specially, in particular not respecting the order (not even int.MinValue gets in first so its not just that the controller has a very low order by default).
So any suggestions on how to get an auth filter to run as the very first thing?
The final solution used was to refactor the code. I took all of the methods that can be run on a filter attribute (eg OnAuthorization, OnActionExecuting, etc.) and moved them onto attributes named for the classes they came from. So the OnAuthorization from BasicController became the same method on BasicControllerAttribute.
These attributes were then applied to the controllers and the attributes are then inherited by all of the classes that subclass from BasicController which essentially maintains the same functionality.
However the attribute can have its Order set that allows you to play around with the running order however you want.
My takeaway from this was to never override those methods on the controller and to always use attributes. :)
I had a related problem with the Controller.OnAuthorization and the AuthorizationFilter.OnAuthorization methods order of execution.
The short answer is: you can't override that Controller.OnAuthorization
runs prior to other filters.
Detailed answer on the question 'why is it so?' is in the code from
ASP.NET MVC sources below.
There is also nice blog post on filter ordering.
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
FilterProviders.cs
namespace System.Web.Mvc
{
public static class FilterProviders
{
static FilterProviders()
{
Providers = new FilterProviderCollection();
Providers.Add(GlobalFilters.Filters);
Providers.Add(new FilterAttributeFilterProvider());
Providers.Add(new ControllerInstanceFilterProvider());
}
public static FilterProviderCollection Providers { get; private set; }
}
}
ControllerInstanceFilterProvider.cs
using System.Collections.Generic;
namespace System.Web.Mvc
{
public class ControllerInstanceFilterProvider : IFilterProvider
{
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (controllerContext.Controller != null)
{
// Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
}
}
}
}

Categories

Resources