Creating Object-Oriented Templates - c#

I am using ASP.NET MVC and Razor.
Using Razor, I am able to create helpers that print HTML code. However, I would like to take an object oriented approach, where my helpers have methods to add code.
However, if I just use C# to return HTML, then I am writing HTML in a string, which is difficult to maintain. Is there some best-practice that allows me to combine the best of both worlds?

In MVC you have some classes to help you.
One. HtmlHelper and UrlHelper. HtmlHelper can generate code for you, for example:
HtmlHelper.TextBox()
Two. TagBuilder. TagBuilder enables you to write more custom elements.
TagBuilder builder = new TagBuilder("input");
builder.GenerateId(id);
builder.MergeAttribute("type", "submit");
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
string html = builder.ToString(TagRenderMode.SelfClosing);

Related

How can I simply parse a stand-alone razor template and use the output as an email body in c#?

I've looked at a dozen or so ways to do this and I'm having a very hard time getting things to work. The issues I've run into fall into one of two categories:
1) A full MVC setup is assumed in the examples I'm looking at. In my case, I'm sending an email from a WebApi project and will not be using any of the pre-wired MVC view functionality provided by the ASP.NET project stub.
2) Libraries are asking for some complex setup I don't really think I need, specifically RazorEngine asking me to set up a TemplateManager, when all I need to do is give a .cshtml file a model and get the parsed results back.
Pardon the noob question; I'm working on my first .NET project here. Thanks!
I had to do the same thing for different reasons a while ago. I had found this class that I used to render the view into a string: https://github.com/RickStrahl/WestwindToolkit/blob/master/Westwind.Web.Mvc/Utils/ViewRenderer.cs
Use it like this:
var r = new ViewRenderer();
var renderedView = r.RenderViewToString("~/Views/MyView.cshtml");
If you need to pass a model to the view, call it like this:
var renderedView = r.RenderViewToString("~/Views/MyView.cshtml", model);
Where model is what your view expects.

Populating Html Helpers route arguments

Is there a way to populate anonymous type properties (route arguments) in Html Helpers like Html.ActionLink or Url.Action with data.
Example.
Create link like this:
Anchor Text
... and populate propertyValue with data extracted from current state of DOM (using Javascript).
I know there's a lot of ways that I can get that logic to work (ex. using form data and passing it to controller) but I'm just curious if a provided scenario is possible.
populate propertyValue with data extracted from current state of DOM (using Javascript)
No.
C# runs on the server, JavaScript runs on the client. You can't use JavaScript on the client to modify code which already ran on the server. You can use JavaScript to modify the markup which gets emitted to the client, and the first step in that would be to examine what that markup actually is. (In this case it looks like you'd be modifying a URL, which may involve some interesting string parsing in the JavaScript code.)
But no, JavaScript can't affect your calls to HTML Helpers.

How to include #Html.Actionlink in C# text string?

While the #Html.Actionlink() helper is very convenient for building <a> elements in the .cshtml files, is it possible to construct them inside C# strings, such that they are subsequently rendered correctly in the HTML output?
For example, if I assign a string variable a value similar to the following:
Book.ReadMore = "Click #Html.ActionLink(\"this link\", \"About\", \"Home\") to read more.";
And then I try to display it (the literal text plus the link) through my .cshtml page, using code similar to:
<p>#Model.ReadMore</p>
All I get in the browser is the whole string exactly as I typed it, including the #Html... etc:
Click #Html.ActionLink("this link", "About", "Home") to read more.
Now, for proper SoC, I know that it's not the best of practices to have HTML stuff included in C# code, but is it at all possible to get the proper <a> link in this scenario, instead of the string itself?
EDIT: More information - This string is just one item in a collection of about 20-30 strings (displayed using a for loop in the View). Only a small handful of those items need a link (which is different in each case). Since, as mentioned above, I agree that it's obviously not good practice to use Razor/HTML in Model code, I'm trying to get a simple approach (if possible) which would give me the flexibility of building the link somewhere at the right place, while still yielding the maintainability of MVC SoC.
There must be a "right" way of doing this, which is simple yet maintainable.
Your model should not contain HTML, that's a view concern and belongs in view code. Probably you should be using a Razor helper.
In your App_Code folder (create one if you don't have one), add a file, ReadMoreHelpers.cshtml:
#helper ReadMore() {
<text>Click #Html.ActionLink("this link", "About", "Home") to read more.</text>
}
Then in any view:
#ReadMoreHelpers.ReadMore()
And that will output what you want. If you insist on putting that property in your view, you could do:
Book.ReadMore = "Click " + #Html.ActionLink("this link", "About", "Home").ToHtmlString() + " to read more.";
Then in your view, make sure you use Raw:
#Html.Raw(Book.ReadMore)
However, I couldn't recommend more strongly that you do not put HTML in your model properties.
I don't think so. The Razor view engine will interpret the ActionLink code during run-time while stuffing it as part of a C# string will be interpreted during compile time.

C# code that generates javascript on the fly

Is it OK to generate code like this on the fly? Or is this a major code smell? How can this be made better?
I'm new to web but I'm stumbling across this all the time and I don't really understand why.
// Create a js function that applies foo to each group of controls
foreach (KeyValuePair<string, Dictionary<Control, string>> pair in maps)
{
js.Append(pair.Key);
js.Append("=function(grid){Prm.remove_endRequest(");
js.Append(pair.Key);
js.Append(");if(grid && grid._element)"); // ... blah blah blah
}
page.ClientScript.RegisterClientScriptBlock(page.GetType(), key + "Ajax",
js.ToString(), true);
I don't see it as a smell until you start doing it all over the place.
Consider these changes, however, that will help out in the future:
Write data-driven JS functions, and only dynamically generate the data that they need. This way, all your JS can be tucked away in a fast static file, and your server only sends the data. This is a better design change than (2) and (3) - and it really isn't that hard. Just think of the data that your current code generator needs, serve that data instead of the JS code, then wrap your JS code in "factory functions" that accept that data as input.
Use templates for the JS code just as you use templates for HTML. This way you don't have to munge around in C# flow control / data control code when you really just want to change some variable names. I would suggest naming template files with the name of the view that it assists. If you have Home.aspx then perhaps you will have JS code templates Home_DoCrazyGridThing.js, Home_DoOtherCrazyThing.js. You can write a simple template engine or use one of many existing such.
Create a thin layer over generating code so that it's obvious what you're doing to the maintainer. That is, have a JSCodeGenerator class with varying levels of intelligence (understands the language OR just allows you to dump string in it OR interfaces with the emplate engine from (2)).

In C# 3.0, are there any classes that help me generate static html?

I am developing a HTML form designer that needs to generate static HTML and show this to the user. I keep writing ugly code like this:
public string GetCheckboxHtml()
{
return ("<input type="checkbox" name="somename" />");
}
Isn't there a set of strongly typed classes that describe html elements and allow me to write code like this instead:
var checkbox = new HtmlCheckbox(attributes);
return checkbox.Html();
I just can't think of the correct namespace to look for this or the correct search term to use in Google.
Well, if you download the ASP.NET MVC DLL's (which you can use in any type of project... including Console apps)... then you can use the many HTML helpers they have.
You could use the classes in the System.Web.UI.HtmlControls namespace. Then you can use RenderControl to generate the html content.
HtmlInputCheckBox box = new HtmlInputCheckBox();
StringBuilder sb = new StringBuilder();
using(StringWriter sw = new StringWriter(sb))
using(HtmlTextWriter htw = new HtmlTextWriter(sw))
{
box.RenderControl(htw);
}
string html = sb.ToString();
One option is to use XElement functional construction. See this blog post for an example calendar generator.
In your case, your Html could be generated with:
var input = new XElement("input",
new XAttribute("type", "checkbox"),
new XAttribute("name", "somename"));
return input.ToString();
HtmlTextWriter contains goodies like "WriteStartTag" and "WriteEndTag", which can be used to create properly formed HTML fairly easily.
You essentially pass the tagname and attributes to the HtmlTextWriter, and it generates the proper HTML, and will close it properly with WriteEndTag.
You can also use the prewritten HTMLControls that wrap this code up into strongly typed classes.
Also consider using System.Xml. By using it, you almost guarantee your HTML is XHTML compliant.

Categories

Resources