How to add content to sections programmatically in MVC / ASP.NET? - c#

In each of my views, I am constantly adding a style and script associated with the view. It is convention in the application we introduced, but we want to automatically apply this convention instead.
Currently our views look like this:
<p>This is the view!</p>
#section styles {
<link rel="stylesheet" href="~/Views/Home/Index.css" />
}
#section scripts {
<script src="~/Views/Home/Index.js"></script>
}
Is there a way to automate adding the styles and scripts? Perhaps in the base class of the controller, such as:
public class BaseController : Controller
{
string controller = RouteData.Values["controller"].ToString();
string action = RouteData.Values["action"].ToString();
string script = string.Format("<script src=\"~/Views/{0}/{1}.js\"></script>", controller, action);
string style = string.Format("<link rel=\"stylesheet\" href=\"~/Views/{0}/{1}.css\" />", controller, action);
// Todo: How to add script and style to sections programmatically???
}

You can use the controller/action name values in your views, and specifically, in your layout. Just edit your layout and in the head add:
<link rel="stylesheet" href="~/Views/#(ViewContext.RouteData.Values["controller"])/#(ViewContext.RouteData.Values["action"]).css" />
And before your closing body tag, add:
<script src="~/Views/#(ViewContext.RouteData.Values["controller"])/#(ViewContext.RouteData.Values["action"]).js"></script>

Related

ASP .Core MVC configure application root url

I have two ASP .Core MVC applications that are hosted under the same url.
I've managed to separate them with Nginx so that a certain path goes to app-2, while the rest goes to app-1:
http://host -> app-1
http://host/setup -> app-2
My problem comes when the user connects to app-2, as the application still thinks it's app-root is http://host.
This leads to the client encountering a 404 when for example style sheets are downloaded, since app-2.css exists under http://host/setup/css but the application searches in http://host/css.
The "include"-lines in the .cshtml file in app-2 look like this:
<link rel="stylesheet" type="text/css" href="#Url.Content("~/css/app-2.css")" asp-append-version="true" />
Is there some way of "overriding" or telling app-2 that ~ should refer to <host>/setup/css/ instead of <host>/css/?
I really don't want to hardcode it in case the url changes at some point.
After many hours of searching I found no way of altering the application root for the entire webserver.
What I ended up doing instead was create class PathHelper with options and added it to Startup.cs:
class PathHelper
{
public PathHelper(IOptions<PathHelperOptions> opt)
{
Path = opt.Path;
if (Path.StartsWith('/'))
{
Path = Path[1..];
}
if (!Path.EndsWith('/'))
{
Path = Path + '/';
}
}
public string Path { get; }
}
class PathHelperOptions
{
public string Path { get; set; }
}
# Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services
.AddScoped<PathHelper>()
.Configure<PathHelperOptions>(opt =>
{
opt.Path = this.configuration.GetSection("URL_SUFFIX");
});
[...]
}
I then used it in the .cshtml files like this:
#inject PathHelper helper
<link rel="stylesheet" type="text/css" href="#Url.Content(helper.Path + "css/app-2.css")" asp-append-version="true" />
I think the easiest way is to include the base tag in pages coming from 'app-2'.
Try it like this:
<html>
<head>
<base href="http://host/setup">
</head>
Now your relative links are sent to 'app-2'.

Set 'cshtml' data and return a string

I have a confirmation email template .cshtml as following:
<html>
<head>
<title>company name: Email Verification - Action Required</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
Thanks for signing up for company name!
<br/>
<br/>
Thank you for signing up to company name. Please press the link below to confirm your email address <br/>
If you did not sign up for company name, please ignore this email, and accept our apologies for the inconvenience.
<br/>
<br/>
#Model.ConfirmLink
<br/>
<br/>
<br/>
Thanks,<br/>
The <a href="http://company name.com" >company name</a> Team
</table>
</body>
</html>
Is there a mechanism I can set data (#Model.ConfirmLink) and get back a result as string? (not manually replace string)
You can use RazorEngine, which uses the same syntax as Razor does, but gives you the ability to render the text without the need of ASP.NET MVC.
How your code would work:
string template = yourHtmlCodeAsString;
string result = Razor.Parse(template, new { ConfirmLink = "http://.../" });
You can load that template string from a file, a resource, etc.
Yes, you can use Razor as template engine for emails.
I use this class.
public static class EmailFactory
{
public static string ParseTemplate<T>(T model, string templatesPath, EmailType emailType)
{
string templatePath = Path.Combine(templatesPath, string.Format("{0}.cshtml", emailType));
string content = templatePath.ReadTemplateContent();
return Razor.Parse(content, model);
}
}
templatesPath - is the path where my cshtml views for email are.
EmailType is and enum that has elements that are the same as the view namse from the templatesPath directory.
The essence is Razor.Parse(content, model); it takes a string that is a valid razor view and a model and merges them together. Same as the views in ASP MVC.

Orchard. How to render something before 'HeadScripts' shape?

Sometimes javascript code needs some data from server (e.g. constants or configs shared between JS and C#). I don't want to pull this data via Ajax. I want to render this data into html page on server.
Let's say, I have a component which consits of C# server-side code and JS client-side code. Component defines some C# constants to be provided for a specific JS code. This definition can be done somehow in ResourceManifest. Defined C# constants should be rendered into html before JS script links. The first part of JS links is rendered in 'HeadScripts' shape.
The question is how to render something before 'HeadScripts' shape?
I tried to wrap 'HeadScripts' shape. But it didn't help.
Wrapper in IShapeTableProvider implementation:
builder.Describe("HeadScripts").Configure(desc => desc.Wrappers.Add("HeadScriptsWrapper"));
HeadScriptsWrapper.cshtml:
<script>
var ServerConstants = {
const1: 'value1',
const2: 'value2'
};
</script>
#Display(Model.Child)
The result is:
...
<script src="/.../jquery-1.11.1.js" type="text/javascript"></script>
<script src="/.../some.js" type="text/javascript"></script>
<script src="/.../onemore.js" type="text/javascript"></script>
...
<meta content="Orchard" name="generator" />
<meta content="utf-8" name="charset" />
...
<link href="/.../favicon.png" rel="shortcut icon" type="image/x-icon" />
<script>
var ServerConstants = {
const1: 'value1',
const2: 'value2'
};
</script>
As you can see code from wrapper is rendered after 'HeadScripts'.
Please help.
I've managed to render custom string before 'HeadScripts' shape.
public class BeforeHeadScriptsShapeProvider : IShapeTableProvider
{
private readonly Work<IOrchardServices> orchardServices;
public BeforeHeadScriptsShapeProvider(Work<IOrchardServices> orchardServices)
{
this.orchardServices = orchardServices;
}
public void Discover(ShapeTableBuilder builder)
{
builder.Describe("HeadScripts")
.OnCreated(created =>
{
orchardServices.Value.WorkContext.Layout.Head.Add(created.New.BeforeHeadScriptsShape());
});
}
[Shape]
public void BeforeHeadScriptsShape(HtmlHelper Html)
{
Html.ViewContext.Writer.WriteLine("<script type=\"text/javascript\"> alert('TEST');</script>");
}
}
I can't explain this code in details, but I've found that some shapes are rendered through TextWriter Output parameter. But Output always renders after 'HeadScripts'. 'HeadScripts' (which is a set of 'Script' shapes) uses writer from HtmlHelper Html parameter. So, using HtmlHelper Html allows you to render custom content before 'HeadScripts'.

MVC .Net 4 Razor Problems using <text> tag

Here is my code:
<text>
<script type="text/javascript">
#foreach (var script in Model.Content.StartupScripts)
{
#script
}
</script>
</text>
#script contains a javascript script, but this gets rendered by razor as:
<script type="text/javascript">
{
{
var instanceId = 'blah';
new RequestQueue(' blah
// etc
So...it looks like the tag is not applying to the #script variable because single quotes are being replaced with '. What am I doing wrong?
Thanks!
Since MVC is automatically encoding all output, you need to force it to display raw text. You can do that with #Html.Raw(script) HTML helper.

Setting default text in WYMEDITOR

I've got a question about using WYMEditor in ASP.NET MVC 3 with jQuery. I'd like to set default text in WYMEditor on my web page. If I'm doing in that way :
<script type="text/javascript">
jQuery(function() {
jQuery(".wymeditor").wymeditor( { html : '<strong>some text</strong>'});
});
There is no problem, and wymeditor shows well-formated text, but is I try it in that way :
<script type="text/javascript">
jQuery(function() {
jQuery(".wymeditor").wymeditor( { html : '#ViewBag.HtmlText'});
});
(HtmlText is variable where I keep : <strong>some text</strong>) the WymEditor shows me not formated text <strong>some text</strong>. I tried HtmlEncoding and etc, but it stil isn't working.
Try like this:
<script type="text/javascript">
jQuery(function() {
var html = #Html.Raw(Json.Encode(ViewBag.HtmlText));
jQuery('.wymeditor').wymeditor({ html: html });
});
</script>
And please get rid of this ViewBag as everytime I see it I get sick. Use view models and strongly typed views.

Categories

Resources