3

I know I can setup OutputCacheProfiles at web.config file.

I like to know how to apply different cache profile to different user role on page (controller) level?

j0k
  • 22,600
  • 28
  • 79
  • 90
Eric Yin
  • 8,737
  • 19
  • 77
  • 118

1 Answers1

6

You can decorate a controller with the OutputCache attribute which allows arguments to be passed as parameters. For example;

[OutputCache(Duration = 3600, VaryByParam = "None")]

There is no reason why you couldn't extend the attribute to take a further argument "RoleName" and perform a "Roles.IsUserInRole(RoleName)" and load different settings based upon each role.

EDIT

After comments from the author, I have reviewed my solution.

Firstly, you can define you cache profiles within the Web.config;

<caching>
  <outputCacheSettings>
    <outputCacheProfiles>
      <clear />

      <add name="Default" duration="60" />
      <add name="Admin" duration="10" />
    </outputCacheProfiles>
  </outputCacheSettings>
</caching>

I have extended the OutputCacheAttribute to account for authorisation of a user, and if the user authenticates, it loads that CacheProfile;

public class AuthorisedOutputCache : OutputCacheAttribute
{
  public string RoleName { get; set; }

  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    // Default Profile.
    CacheProfile = "Default";

    if (HttpContext.Current.Request.IsAuthenticated)
    {
      if (Roles.IsUserInRole(RoleName))
      {
        CacheProfile = RoleName;
      }
    }

    base.OnActionExecuting(filterContext);
  }
}

Here is the Index.cshtml file for completeness;

@model DateTime

@{
  ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
  The time is @Model.TimeOfDay.ToString()
</p>

Note: You will have to make sure to define a cacheprofile for each of your roles, aswell as a default for when no role is found.

EDIT

The author wished to know how to set the cache profile within the controller, I have posted a viable solution, but I don't like it because of the use of HttpContext.Items - so if anyone can suggest alternatives?

Firstly, you must change the OnActionExecuting to OnActionExecuted;

public class AuthorisedOutputCache : OutputCacheAttribute
{
  public string RoleName { get; set; }

  public override void OnActionExecuted(ActionExecutedContext filterContext)
  {
    // Do you wish to force the profile?
    if (HttpContext.Current.Items["Cache.Force"] != null)
    {
      // Force the profile and remove the flag.
      CacheProfile = HttpContext.Current.Items["Cache.Force"].ToString();
      HttpContext.Current.Items.Remove("Cache.Force");
    }
    else
    {
      // If the profile has not been set - use the role based authorisation - 
      // otherwise, carry on as normal.
      if (string.IsNullOrEmpty(CacheProfile))
      {
        CacheProfile = "Default";

        if (HttpContext.Current.Request.IsAuthenticated)
        {
          if (Roles.IsUserInRole(RoleName))
          {
            CacheProfile = "Admin";
          }
        }
      }
    }

    base.OnActionExecuted(filterContext);
  }
} 

The following line allows you to set the profile within the controller;

public ActionResult Index()
{
  // Forces the cache profile to one of the name of "Mandatory".
  HttpContext.Items["Cache.Force"] = "Mandatory";

  return View(IndexViewName, DateTime.Now);
}

Let me know if I can be of further assistance,

Matt

Matt Griffiths
  • 1,142
  • 8
  • 26
  • Thanks. Looks like any place that accept a temp value can be used for this method. How about viewbag? I will try this method now, have to say, change the method from OnActionExecuting to OnActionExecuted is a smart move. – Eric Yin Nov 30 '11 at 20:24
  • Hi Matt, after test. Change CacheProfile @ OnActionExecuting is working, but @ OnActionExecuted is not. The value for CacheProfile is changed but the cache result is not. Maybe the cache has already been deployed after OnActionExecuting but before OnActionExecuted. – Eric Yin Nov 30 '11 at 22:16