Eric Yin
Eric Yin

Reputation: 9003

ASP.NET MVC3, How to Use Different OutputCacheProfile to Different User Role?

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?

Upvotes: 3

Views: 2135

Answers (1)

Matt Griffiths
Matt Griffiths

Reputation: 1142

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

Upvotes: 6

Related Questions