Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject a CSS file from an ASP.NET MVC partial view (server-side)?

I have a partial view (.ascx) that should include its own CSS file as it's used in multiple other views. How do I inject a stylesheet in the page server-side, i.e. without using JavaScript?

like image 479
Dario Solera Avatar asked Oct 06 '10 10:10

Dario Solera


2 Answers

Dario - due to using this for partialviews, you're going to always have the problem that the <head> section of the document is already in place and therefore can't be modified. If you want to remain WC3 compliant, then you'll have to put any further css into the head section via javascript. This may or may not be desirable (if you've got to cater for downsteam browsers with javascript turned off).

the main problem that you may be aluding to is the fact that you can't put <asp:contentplaceholders> into your partials. this is a pain (tho understandable as the masterpage ref would tie the partial too closely to a particular master page).

To this end, I've created a little helper method that does the basic grunt work to put the css file into the head section automatically.

edit - (as per Omu's js suggestion) this is a nice little halfway house:

// standard method - renders as defined in as(cp)x file
public static string Css(this HtmlHelper html, string path)
{
    return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static string Css(this HtmlHelper html, string path, bool renderAsAjax)
{
    var filePath = VirtualPathUtility.ToAbsolute(path);

    HttpContextBase context = html.ViewContext.HttpContext;
    // don't add the file if it's already there
    if (context.Items.Contains(filePath))
        return "";

    // otherwise, add it to the context and put on page
    // this of course only works for items going in via the current
    // request and by this method
    context.Items.Add(filePath, filePath);

    // js and css function strings
    const string jsHead = "<script  type='text/javascript'>";
    const string jsFoot = "</script>";
    const string jsFunctionStt = "$(function(){";
    const string jsFunctionEnd = "});";
    string linkText = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\"></link>", filePath);
    string jsBody = string.Format("$('head').prepend('{0}');", linkText);

    var sb = new StringBuilder();

    if (renderAsAjax)
    {
        // join it all up now
        sb.Append(jsHead);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionStt);
        sb.AppendFormat("\r\n\t\t");
        sb.Append(jsBody);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionEnd);
        sb.AppendFormat("\r\n");
        sb.Append(jsFoot);
    } 
    else
    {
        sb.Append(linkText);
    }

    return sb.ToString();
}

usage:

<%=Html.Css("~/Content/yourstyle.Css")%>

or:

<%=Html.Css("~/Content/yourstyle.Css", true)%> // or false if you want!!

worth a back-pocket approach if all else fails. it may also be possible to adapt the logic above to hit an actionfilter and add the css to the reponse headers etc.., rather than outputting the js string.

like image 157
jim tollan Avatar answered Oct 21 '22 07:10

jim tollan


Is there a reason you cannot just put the stylesheet in the main view page? Unless it is extremely large, it should not cause your page to load significantly slower when not being used, especially after compression.

Furthermore, if the partial view is being retrieved by ajax, you will end up re-downloading the css file multiple times (depending on the browser's caching).

like image 28
KallDrexx Avatar answered Oct 21 '22 08:10

KallDrexx