Can you have dependency injection in a .css file? - css

I have a c# .NET 6 app. Some of the web pages (razor pages) of the app are using dependency injection, injecting configuration into the razor pages (the .cshtml files) so that some config elements can be displayed in the UI.
My question is, is it possible to inject configuration in a similar way to a .css file? Is it possible to have something similar to this in a .css file:
/**mycssfile.css**/
#using Microsoft.Extensions.Configuration
#inject IConfiguration Configuration
.mystyle {
background-image: Configuration.image;
}

You might be looking for the #import keyword, if you are just looking to bring in rules from other style sheets.
The #import CSS at-rule is used to import style rules from other valid stylesheets. An #import rule must be defined at the top of stylesheet, before any other at-rule (except #charset and #layer) and style declaration, else it will be ignored.
https://developer.mozilla.org/en-US/docs/Web/CSS/#import
However, if you are trying to bring in values, strings, or any other kind of data from C# (which you appear to want in your example), you’re going to have to dynamically build the CSS file content in an endpoint on your server (where you have access to the C# values), then send that down to the browser where it acts like just another style sheet.
The issue is, once the browser parses CSS, it does not have access to your server’s code, because it’s already been downloaded.
Although, the functionality I just described may already be available to use as a built-in feature of the .NET framework, otherwise, you’ll have to code it yourself in .NET.

CSS files are plain text and are not processed by ASP.NET Core. Consequently, it is not possible to execute server-side code within them. However, you can easily use a Razor page to generate your CSS file, which will support DI etc (although you likely lose any CSS support offered by your IDE).
Here's the PageModel for an example. Note that the ContentType for the Response has been altered:
public class CssModel : PageModel
{
public string TextColor => "green";
public void OnGet()
{
Response.ContentType= "text/css; charset=utf-8";
}
}
Here's the .cshtml file content. The Layout has been set to null:
#page
#model WebApplication3.Pages.CssModel
#{
Layout = null;
}
body{
font-family:consolas;
color: #Model.TextColor;
}
Here's an example of a page that uses the generated CSS. Note here that the script is being output in a section:
#page
#model CssTestModel
#{
}
<h1>Hello World!</h1>
<p>This page tests Razor generated CSS</p>
#section styles{
<link rel="stylesheet" href="/css" />
}
And here's the layout page's head section that includes the necessary RenderSection call:
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>#ViewData["Title"]</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
#RenderSection("styles", false)
</head>

Related

Css and js Not Loadind in spring mvc application

I am trying to create an application in Spring MVC. I want to create login page using style-sheets and js files in jsp file. But I'm unable to load css and js files at the login file.
1)
I tried using:
<link href=" <c:url value="/resources/css/bootstrap.min.css"/> " rel="stylesheet">
By using (in springWeb.xml):
<mvc:resources mapping="/resources/**" location="/resources/" cache-period="31556926"/>
2) I directly used
<link href="resources/css/bootstrap.min.css" rel="stylesheet">
When I loaded the page, resources (CSS/Js files) have not been loaded.
What is missing / what am I doing wrong? Thanks!
Did you tried ResourceHandlerRegistry?
#Configuration
#EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
Like Arpit suggested in his answer, you probably want to declare a resource handler in your configuration class.
What did the trick for me was to put a link in like this, especially the "media" attribute seemed to make the difference for my application.
<link rel="stylesheet" href="<c:url value="/resources/css/bootstrap.min.css"/>" type="text/css" media="screen">
On top of that you need to pay extra attention to the path you declare in the resource handler and the actual path.

Why does MVC automatically expand virtual URLs?

In my Layout.cshtml file I have the following line:
<link rel="stylesheet" href="~/Content/bootstrap.css" />
My assumption was that since I did not include Url.Content() call, it would actually just render what I wrote but not expand the virtual URL automatically. This assumption is wrong - the generated HTML does include the correct path to the file, not the virtual path I entered.
If I wrap the <link> in <script>
<script type="text/html">
<link rel="stylesheet" href="~/Content/bootstrap.css" />
</script>
then the URL is not expanded.
Which part of ASP.NET MVC does this automatic parsing of HTML and is there a way to control it?
This was a new feature included in Razor2 and ASP.NET MVC 4 and was designed to make life easier by not having to use Url.Content everywhere.
http://www.davidhayden.me/blog/asp.net-mvc-4-the-new-tilde-slash-feature-in-razor-2
The feature only works inside standard HTML attributes and that's why you don't get it inside your <script> tag or anywhere else.
You could use a simple output write to work around this:
<link rel="stylesheet" href="#("~/Content/bootstrap.css")" />

User Control with external CSS file

I have an ASCX user control in the root of my Web application. It references a stylesheet, something like
<link type="text/css" rel="stylesheet" href="MyStyle.css" />
The problem is if any ASPX pages located in application subfolders reference that user control - they don't see the stylesheet, because href path is relative and stylesheet remains in the app root.
Is there a way besides copying the CSS into all the subfolders to universally reference it from the root? I have no problem referencing external JavaScript, using ScriptManagerProxy I can specify path to external JS file via ASP.NET "~/" notation which gets resolved into real path from any location. Does something similar exist for CSS?
ResolveUrl will convert application-relative urls for you. http://msdn.microsoft.com/en-us/library/system.web.ui.control.resolveurl.aspx
<link href="<%= ResolveUrl("~/MyStyle.css") %>" rel="stylesheet" />
EDIT: If you don't want to use inline code blocks
code-behind
protected void Page_Load(object sender, EventArgs e)
{
litStyle.Text = string.Format("<link href=\"{0}\" rel=\"stylesheet\" />", ResolveUrl("~/MyStyle.css"))
}
markup
<asp:Literal ID="litStyle" runat="server"/>
As I mentioned in my comments I didn't want to use <%= %> blocks. But I didn't want to assign URL of CSS file in code-behind either, so I found a compromise. I declare <link> tag with runat="server" attribute and ASP.NET - style href:
<link rel="stylesheet" type="text/css" runat="server" id="xlinkCSS" href="~/MyStyle.CSS" />
and then in code-behind simple resolve that link
xlinkCSS.Attributes("href") = ResolveUrl(xlinkCSS.Attributes("href"))
Using this approach ultimately I can create a function that accepts page as a parameter, loops thru all "link" tags, resolving their URLs.
Actually you have two options:
1- to include it in your themes folder, then the asp.net framework will automatically include it in all pages using this theme
2- to add a public variable in your CS code that includes the path, then to use it in your code, as the following code:
public string basepath = "http://" + Request.Url.Authority + Request.ApplicationPath;
then to use it in ASP code:
<link type="text/css" rel="stylesheet" href="<%=basepath %>MyStyle.css" />
You should make bundle.config file and then you can use this in your code

ASP.NET MVC 3 send <head> before <body> renders

I have asp.net mvc application, that uses razor view engine.
I want to send head to browser, before body renders, to start parallel loading css, js and images, linked in css. (You can see, how this technique works on SO in chrome developer tools - network for example)
I found question about it in asp.net web forms: Send head before body to load CSS and JS asap
I tried to use this solution, but it don't work.
For razor engine next sequense of steps is actual:
action returns view result
_ViewStart.cshtml executes (set ViewBag.Layout)
view executes from first line to last (with code inclusions and sections)
view engine checks ViewBag.Layout and if it found - executes Layout (with renderind body and sections)
I think that good solution is to divide step 3 into 3 parts:
generating content for Head and Css section
send to browser
generating other part of view
Other solution is to static include all.css and basic .js files in (without sections content, generated from view), send head, and then generate view (with generation FooterScript section).
In both ways I need to start execution from Layout page, not from view. For first: Layout (head) - view (sections) - layout (flush) - view (other) - layout (body). For second: Layout (head + flush) - view (all) + Layout (body).
My _Layout.cshtml file:
<html #Html.Raw(ViewBag.xmlns)>
<head>
<title>#ViewBag.Title</title>
#Html.Partial("_MetaTags")
<link href="#Url.ThemeCss("jquery-ui-1.8.18.custom.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Css("masterPage.css")" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico"/>
#RenderSection("Css", required: false)
<script src="#Url.CommonScript("jquery.common.min.js")" type="text/javascript"></script>
<script src="#Url.Script("Master.js")" type="text/javascript"></script>
#RenderSection("Head", required: false)
</head>
<body>
<div id="pageWhithoutFooter">
<div id="main">
#RenderBody()
</div>
</div>
#RenderSection("FooterScript", required: false)
</body>
</html>
Howto?
Try putting your head section into a Partial view then call this in your controller:
PartialView("_PageHeader").ExecuteResult(ControllerContext);
Response.Flush();
// Generate model
return View(model);
Not tested this but I can't see why it wouldn't work.

Implementing CSS as a variable in the site.master page in ASP.NET MVC3

I am implementing a web application using ASP.NET MVC3. In the application I want to add the option of switching between CSS files (for themes) based on clicking some links. I did some research and I came up with the following:
To pass data to site.master, the good solution is to create an abstract controller and inherit that into the other controllers that have site.master as their template, according to this article: Passing Data to View Master Pages
I can pass a viewbag message to the link which controls the css file URL to set the current css file to use, based on the code that I am seeing being passed to scripts at the top of the site.master page:
script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"
So I created an abstract controller, ApplicationController, with the following method:
public ApplicationController()
{ViewBag.NewMessage = "../../Content/Site2.css";}
And in the site.master, I included this link:
<link href="<%: (string) ViewBag.NewMessage %>" rel="stylesheet" type="text/css" />
However, that doesn't seem to be working, as it is being interpreted as:
<link href="<%: (string) ViewBag.NewMessage %>" rel="stylesheet" type="text/css" />
And only when I remove the quotation marks:
<link href=<%: (string) ViewBag.NewMessage %> rel="stylesheet" type="text/css" />
is it being interpreted correctly (and the webpage gets rendered with the correct css), except that it violates html standards:
<link href=../../Content/Site2.css rel="stylesheet" type="text/css" />
Any suggestion about how to go tackling this problem or is there a more elegant solution I'm missing? I was going to proceed and implement variables in the ApplicationController that get selected based on links the user clicks at the top of the page, to switch between css styles.
Thank you!
Check to make sure your <head> tag does not have runat="server".
After making this change, be sure to check your script and css tags. This change can break the paths if you use the ~/ to ref app root. To help with this, use the Url.Content(...) helper.

Resources