Question

I have a multi-tenant application in ASP.NET MVC. The instance of the application that will be served is function of the hostname alone (something along the lines of stackexchange, I suppose).

Each instance of the application might have a different culture setting (even "auto", to read the browser's language and try to use it), and will be localized accordingly.

In this situation, I'd like to do some output caching on some of my actions. So, my questions are:

  1. What are the possibilities to achieve output caching of a multi-tenant ASP.NET MVC application, if the output depends exclusively on the hostname (ie, ignoring the localization requirement)?

  2. Same as (1), but now considering that the output depends on the culture settings as well?

  3. Same as (2), but considering that the output might vary with parameters that were passed to the action?

In this case, I'm considering that all the sites run from a single IIS website.

Was it helpful?

Solution

I've just figured out how to achieve this.

Simply use the VaryByHeader property, set to "host". There are many possibilities to do so.

Method 1

Use the OutputCacheAttribute passing all the needed configuration elements, including VaryByHeader:

public class HomeController : Controller
{  
    [OutputCache(Duration = 3600, VaryByParam = "none", VaryByHeader = "host")]
    public ActionResult Index() { /* ... */ }
}

Method 2.

Or you could set it to a profile on the Web.config:

<?xml version="1.0"?>
<configuration>
  <!-- ... -->
  <system.web>
    <!-- ... -->
    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <clear/>
          <add name="Multitenant" 
               enabled="true"
               duration="3600"
               varyByHeader="host"
               varyByParam="none"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>
  </system.web>
</configuration>

Then use it:

public class HomeController : Controller
{  
    [OutputCache(CacheProfile = "Multitenant")]
    public ActionResult Index() { /* ... */ }
}

Method 3.

Or you can subclass the OutputCacheAttribute and use it:

public sealed class MultitenantOutputCacheAttribute : OutputCacheAttribute
{
    public MultitenantOutputCacheAttribute()
    {
        VaryByHeader = "host";
        VaryByParam = "none";
        Duration = 3600;
    }
}

Then use it:

public class HomeController : Controller
{  
    [MultitenantOutputCache]
    public ActionResult Index() { /* ... */ }
}

OTHER TIPS

In case people land on this page and are looking for the equivalent in asp.net 2.x. The attribute will look like this:

[ResponseCache(Duration = 30, Location = ResponseCacheLocation.Any, VaryByHeader = "host", VaryByQueryKeys = new string[] { "*" })]

And you will need the middleware added. You need this nuget package and this code:

public void ConfigureServices(IServiceCollection services)
{
    //stuff before...

    services.AddResponseCaching();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    //stuff after...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //stuff before...

    app.UseResponseCaching();

    //stuff after...
}

More details here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top