views:

622

answers:

5

Hello,

I've been doing a bit of research regarding action filters and wondered if there was a way to add them programmatically to controllers??

To give some context, I'd like to add a logging filter if logging is configured in the web.config, otherwise I don't want the filter to exist in the execution chain of each action method.

I appreciate I can put a check in the actual filter code itself to see if logging is enabled but don't want to have to do this is possible.

Many thanks!

A: 

I've never added attributes to methods programatically as it looks like an inefficient nightmare for which I have always found a preferable alternative.

You need to do the check somewhere, and while I agree that the attribute code may not be the best place for it, it's not particularly bad. If you really don't want to do this then you could abstract out the logging code so that it only takes the kinds of entries that have been enabled, then it's up to you how much architecture you want to put around it.

tags2k
+1  A: 
    [LogRequest]
 [PermissionRequired(Permits.View_users, Permits.Edit_users)]
 public ActionResult Edit(int id, .....)
            {
             ...
            }

    public class PermissionRequired : ActionFilterAttribute, IActionFilter
{
 private readonly PermissionsList permits;

 public PermissionRequired(params Permits[] perm)
 {
  permits = new PermissionsList(perm);
 }

 #region IActionFilter Members

 void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
 {
  ...
  IEnumerable<int> intersection = (from up in User.CurrentUser.UserPermission
                                   select up.PermissionID).ToList().Intersect(permits.Cast<int>());
  if (intersection.Count() != permits.Count)
  {
   filterContext.Result = null;
   HttpContext.Current.Response.Redirect("/Error/PermissionsRequired.htm");
  }
 }

 #endregion
}
omoto
A: 

You can look in to creating your own implementation of ActionInvoker which is the class that that handles invoking the filters and action methods. Having said that I don't think this is a good solution. It violates the separation of concerns. Better to have your logging action filter determine if logging should occur or not.

Mike Glenn
+1  A: 

A better solution would be to use the null object pattern.

Your filter would log normally (its job is to log, not to decide how to log or what to log to, necessarily), but by default the actual logger would be an implementation that does nothing. If it's configured, the logger instance will be an implementation that logs as configured.

A simple factory could make the decision of which logger implementation to deliver to the filter or any IOC container could be configured to handle it.

Matt Hinze
A: 

I've been looking through the new Oxite code (last version suffered a major refactoring due to the massive critics) and they do something interesting. They create their own ActionFilterRepository to hold different filters (IActionFilters, IAuthorizationFilters, etc.). In a custom ControllerActionInvoker the GetFilters method is overriden and adds the filters from the repository to the current collection. This way, they have a set of global filters applied to every action and controller.

You can see the custom invoker code here: OxiteControllerActionInvoker.cs

And an example filter here: LocalizationActionFilter.cs

Hope this helps.

Marc Climent