In my MVC3 solution, I am attempting to implement the solution in this answer to dynamically add a CSS reference to the _Layout.cshtml file from within a partial view.
Here is a snippet of my _Layout file:
<!DOCTYPE html>
<html>
<head>
#Html.RenderStyles()
</head>
<body>
<div id="header-wrapper">
#Html.Action("Header", "Shared")
</div>
<div class="container">
#RenderBody()
</div>
#RenderSection("scripts", required: false)
</body>
</html>
and in the partial view (that is rendered by the #Html.Action("Header", "Shared") bit):
#{
Html.AddStyle(Model.Company.CSSPath);
}
While the HtmlExtension methods are working as expected, it seems that the events are occuring in the incorrect order.
The #Html.RenderStyles() in the _Layout head is occuring before the Partial View has time to add the CSS file to the Styles. I was under the impression that Partial Views were rendered before the _Layout.
I'm guessing that the cause has to do with the fact that I'm rendering my Partial View with an Html.Action call. If I don't do so, however, then how can I populate the Partial view with its desired model?
Per Matt Razza's comment, if I were to render the partial view the "normal way" using:
#Html.Partial("ViewName", model)
I'm then required to give my _Layout a Model and then force all other models to inherit from that Model? Is that truly the best option?
Related
I'm facing an issue when I'm trying to link my .cshtml file and my JavaScript reference in an ASP.NET Core 6 MVC.
As of right now, I have made a webpack setup such that it generates my JavaScript tags in a separate file called home.sources.cshtml:
#section Scripts
{
<script src="/js/npm.popperjs.bundle.js"></script>
<script src="/js/npm.jquery.bundle.js"></script>
<script src="/js/npm.bootstrap.bundle.js"></script>
<script src="/js/home.bundle.js"></script>
}
As you can see, my tags are encapsulated in the Scripts section. All these dependencies are for my View/Home/Index.cshtml page:
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p class="test">Learn about building Web apps with ASP.NET Core.</p>
</div>
// Insert Script Section here
I want to make it so that the contents of home.sources.cshtml gets appended to this page at runtime. I don't want to manually add the script section myself, nor do I want to modify the page later on should I add more JavaScript dependencies. Any extra JavaScript dependencies that I add or remove will have their changes reflected only in home.sources.cshtml.
How do I go about doing that?
I was looking into #Html.Partial() in the attempt to add the Script section into the page as a partial view, but that doesn't seem to work.
That's a very odd way to add script references if I understand what you're doing here.
Normally in MVC You see a couple lines in the layout page that look like this:
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
Those refer to a set of bundles in App_Start -> BundleConfig.cs
That's the standard way of adding .js files to your runtime pages.
Thank you Jonespopolis for giving me this approach.
Essentially, what I need to do is to make a Layout template file, specifying that I am using my preexisting Layout file that I was already using, and declaring where all the JS tags would go. For instance, here's my template file:
#{
Layout = "_Layout";
}
#RenderBody()
#section Scripts
{
<% for (index in htmlWebpackPlugin.files.js) { %>
<script src="<%= htmlWebpackPlugin.files.js[index] %>"></script>
<% } %>
}
This template file refers back to my original _Layout.cshtml file:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Head content here -->
</head>
<body>
<!-- Header content here -->
<div class="container">
<main role="main" class="pb-3">
#RenderBody()
</main>
</div>
<!-- Footer content here -->
</footer>
#await RenderSectionAsync("Scripts", required: false)
</body>
</html>
The #await RenderSectionAsync("Scripts", required: false) line will render the Script section that I created in my template file.
From there, I used Webpack's Htmlwebpackplugin with the following config:
plugins: [
new HtmlWebpackPlugin({
inject: false,
template: 'Views/Shared/PageTemplate.cshtml',
filename: '../../Views/Shared/home.sources.cshtml',
minify: false
}),
],
Running the webpack command will net us a home.source.cshtml file containing everything in the template file, but it shows my actual JS references needed for home.cshtml. All that's left is to make this file be the Layout for the page, by inserting this at the beginning:
#{
Layout = "home.sources";
}
Running the application gives me the home page with all the correct JS tags downloaded! Now if I ever change my JS dependencies, I don't need to ever worry about generating the tags nor inserting them into the page, since all of that has been automated now, which is exactly what I wanted!
I literally would do a partial, because it makes it look cleaner. So I have a partial called _ScriptsPartial and I have all js I need in it.
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2#11"></script>
<script src="//cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="https://cdn.tiny.cloud/1/srxbhbztd7jetvbg65d7si3gxatiku0ym7l8if3mda35vxxe/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
Then I use it as such in my layout like this I make many partials
<!DOCTYPE html>
<html lang="en">
<head>
<partial name="_HeadPartial" />
</head>
<body>
<header>
<partial name="_NavPartial" />
</header>
<div class="container">
<main role="main" class="pb-3">
<partial name="_Notification" />
#RenderBody()
</main>
</div>
<footer >
<partial name="_FooterPartial" />
</footer>
<partial name="_ScriptsPartial" />
#await RenderSectionAsync("Styles", required: false)
#await RenderSectionAsync("Scripts", required: false)
</body>
</html>
this seems to work okay :)
HI read some articles about razorengine and I implemented the same.
https://antaris.github.io/RazorEngine/IntellisenseAndResharper.html
but it was not working for me.
even researched code from stackoverflow and try to work around it, but it was also not working.
Note: the answer is stackoverflow is not working for me
this is how I tried add intellisense to cshtml
#using RazorEngine
#using Text.Model
#inherits Templating.TemplateBase<EmailModel>
I had a model under folder Model with name EmailModel, I have a HTML template under Templates with name EmailTemplate
my model class
public class EmailModel
{
public string Timestamp { get; set; }
public string Name { get; set; }
}
my goal is to write in cshtml
#using RazorEngine
#using Text.Model<!-- namespace-->
#inherits Templating.TemplateBase<EmailModel>
<html>
<head></head>
<body>
<p>
#Model.Name
#Model.Timestamp
</p>
</body>
</html>
but still my intellisense is showing me squiggly lines #Model
but still my intellisense is showing me squiggly lines #Model
Shouldn't that be since you are referring to #Model as seen in below code segment but I don't see anywhere in your *.cshtml you are having a #Model binded. Basically your view is not a Strongly Typed View. So there is no model and thus the error
<p>
#Model.Name
#Model.Timestamp
</p>
#inherits is for inheriting a base class as the linked doc in your comment say
you can get minimal intellisense by providing your own base class and
using it with the #inherits directive.
You need to add the #Model directive to bind a model like
#model namespace.modelname
<html>
<head></head>
<body>
<p>
#Model.Name
#Model.Timestamp
</p>
</body>
</html>
For more information see Accessing Your Model's Data from a Controller
this is dll project so we cannot use #model to bind and get intellisense help in cshtml.
the appropriate solution to this in 2 ways
1) write a class and define a constant in that class
const string EmailTemplate =#"<html>
<p>
#model.Name is going to #model.Country
</p>
</html>";
call this constant into the class where you are calling razorengine
and pass this EmailTemplate as template for razorengine and you EmailModel as model
2)write in App.config under argumnets section
<arguments>
<add name="EmailBody" value="<html>
<body>
<p>
#Model.Name is going to
#Model.Country*********
</p>
</body>
</html>" />
<arguments/>
Note: html regular<> tags don't work in app.config
these two ways are working to make razorengine to create email templates in Non MVC (dll & console) applications
I'm learning ASP.NET MVC. I have a service folder where I have a class which reads data from an XML file. I've created a controller that I think (?) should work, and I'm attempting to create a view for this as well but for some reason I can't get intellisense to autocomplete the #model which makes me think I've done something wrong. Additionally, when I try access model properties from the view (eg Model.Description - if that is even the syntax?) I get numerous missing { and } errors. What am I doing wrong?
Controller:
public ActionResult Index()
{
NewsReader newsReader = new NewsReader(); //Read news from file
var newsItems = newsReader.GetNewsItems();
return View(newsItems);
}
And so far this is all I have for the view:
#Model IEnumerable<TestSite.Services.News.NewsItem>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
<ul>
#foreach(Model.Description)
{
}
</ul>
</div>
</body>
</html>
Refer to #Erik Funkenbusch explanation of MVC #model meaning
The # sign is a directive to tell the Razor engine that what follows
is code, and it should compile that rather than simply write it to the
output.
so when you type
#model blah This is compiled by razor, and tells the Razor engine that
the type of the model is 'blah', so that when you use the keyword
Model (note the capital M and you would have to use the # sign as
well) it will refer to the model you have defined (in this case blah).
Therefore corrections should be taken as following:
//#Model IEnumerable<TestSite.Services.News.NewsItem>
#model IEnumerable<TestSite.Services.News.NewsItem>
//#foreach(Model.Description)
#foreach(var item in model.Description)
{
}
I recommend you to read Getting Started with ASP.NET MVC 5 to learn some basics about ASP.NET MVC 5. Razor engine is used by MVC 5 for the view styling.
And have some idea here
I have a regular application _Layout.cshtml and #RenderBody() to render all views inside, but only for the Login view need to be render as full page not inside #RenderBody().
Regards
You need to set the Layout property to null at the beginning of your view.
So, your Login.cshtml file should start with:
#model YourModel
#{
Layout = null;
}
You may not want to have no layout for your view. You probably want a custom layout (something like _LayoutFullPage.cshtml
<!DOCTYPE html>
<head>
<title>SOMETHING HERE ALONG WITH OTHER HEAD ATTRIBUTES</title>
</head>
<body>
#RenderBody()
</body>
</html>
and then use that layout in the view with
#{
Layout = "~/Views/Shared/_LayoutFullPage.cshtml";
}
Other options are to set the view as null in the cshtml (as suggested by RePierre) or to call return PartialView(model); within your controller.
I'm refactoring all my partial views to use the leading underscore naming convention (didn't know about this convention when I got started, don't want to deviate from such a plain convention). But I've come across the generated (razor, C#) "Error.cshtml" view in \Views\Shared and I noticed it looks like it may be a partial view (no html / body tags) yet doesn't follow the convention:
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
}
<h2>
Sorry, an error occurred while processing your request.
</h2>
I also notice it doesn't specify a Layout, yet sets the ViewBag.Title property as if it were going to be used by a Layout. What's the deal?
Strange. My generated Error.cshtml looks like a "normal" view with HTML body:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h2>
Sorry, an error occurred while processing your request.
</h2>
</body>
</html>
I think in your case the layout is not set to null, hence the default layout will be used that contains the HTML wrapping elements.
But it is still a "normal" view (not partial).