Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC4 bundles by host name

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?

like image 882
Max Favilli Avatar asked Jan 04 '13 17:01

Max Favilli


1 Answers

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)
like image 185
viperguynaz Avatar answered Sep 18 '22 03:09

viperguynaz