7

I am new to MVC.

I know how to create bundles, it's easy and it's a great feature:

  bundles.Add(new StyleBundle("~/content/css").Include(
    "~/content/main.css",
    "~/content/footer.css",
    "~/content/sprite.css"
    ));

But let's say your application is accessible under different domains and serving different content with different css depending on the host name.

How can you have a bundle include different files depending on the host name? In application start where my RegisterBundles is (like in the MVC standard internet application I started with) I don't even know the host name yet.

What are the best practices?

If I had the host name available when registering the bundles I could pick the right .css file for the current host name. Can I register bundles on application begin request for instance, and somehow check if it was already registered and if not, pick the right files for the host name of the request and register it?

If yes, how?

EDIT 1

In the last two hours I investigated this topic a little deeper, let me propose my solution with hopes who is more expert than me with MVC can correct my approach if wrong.

I replaced:

@Styles.Render("~/Content/css")

with:

@Html.DomainStyle("~/Content/css")

Which is just a simple helper:

public static class HtmlExtensions
{
  public static IHtmlString DomainStyle(this HtmlHelper helper, string p)
  {
    string np = mynamespace.BundleConfig.RefreshBundleFor(System.Web.Optimization.BundleTable.Bundles, "~/Content/css");

    if (!string.IsNullOrEmpty(np))
      return Styles.Render(np);
    else
    {
      return Styles.Render(p);
    }
  }
}

Where RefreshBundleFor is:

public static string RefreshBundleFor(BundleCollection bundles, string p)
{
  if (bundles.GetBundleFor(p) == null)
    return null;

  string domain = mynamespace.Utilities.RequestUtility.GetUpToSecondLevelDomain(HttpContext.Current.Request.Url);

  string key = p + "." + domain;

  if (bundles.GetBundleFor(key) == null)
  {
    StyleBundle nb = new StyleBundle(key);

    Bundle b = bundles.GetBundleFor(p);
    var bundleContext = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, p);

    foreach (FileInfo file in b.EnumerateFiles(bundleContext))
    {
      string nf = file.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(file.Name) + "." + domain + file.Extension;
      if (!File.Exists(nf))
        nf = file.FullName;

      var basePath = HttpContext.Current.Server.MapPath("~/");
      if (nf.StartsWith(basePath))
      {
        nb.Include("~/" + nf.Substring(basePath.Length));
      }
    }
    bundles.Add(nb);
  }

  return key;
}

And GetUpToSecondLevelDomain is just returning the second level domain out of the host name, so GetUpToSecondLevelDomain("www.foo.bar.com") = "bar.com".

How is it?

tshepang
  • 12,111
  • 21
  • 91
  • 136
Max Favilli
  • 6,161
  • 3
  • 42
  • 62

1 Answers1

3

Over-complicated - the Request object is available in Application_Start. Just use:

var host = Request.Url.Host;

before you register your bundles and conditionally register your bundles base on the value returned.

UPDATE Register all you bundles with a domain key:

StyleBundle("~/content/foo1.css")...
StyleBundle("~/content/foo2.css")...

Then in a base controller that all controllers inherit you can build the bundle name to pass to the view:

var host = Request.Url.Host;  // whatever code you need to extract the domain like Split('.')[1]
ViewBag.BundleName = string.Format("~/content/{0}.css", host);

and then in the layout or view:

@Styles.Render(ViewBag.BundleName)
viperguynaz
  • 12,044
  • 4
  • 30
  • 41
  • But I suspect it's not enough. Application_Start is called just when the application is started, multiple domains on the same application means it start on the first request from one of the domain, but on the subsequent requests from the other domains? – Max Favilli Jan 05 '13 at 20:28
  • you are going to be eating up a ton of CPU time trying to bundle & optimize on every request, more than likely slowing down your response and defeating the purpose of bundling/minimizing. You will be better off bundling/minimizing all your domain specific bundles once and then using the layout and/or controller to choose the right bundle. – viperguynaz Jan 05 '13 at 21:02
  • I would recommend doing it in the layout, a couple of simple if statements and you're done. I'm not a fan of logic in a layout, view, etc, but this is a good exception. – Erik Philips Jan 05 '13 at 23:25
  • But I don't bundle an minimize on every request, I do only the first time the bundle is not found, that's the purpose of "if (bundles.GetBundleFor(key) == null)", if it's different than null does nothing. – Max Favilli Jan 06 '13 at 15:26
  • 1
    @viperguynaz Request object is not available in Application_Start, see http://stackoverflow.com/questions/5750030/request-object-in-application-start-event – Max Favilli Jan 07 '13 at 09:05