.NET MVC View question - asp.net-mvc

I have this cute little progress bar looking thing in a dashboard page. Once it is started up, it updates itself every minute via ajax, javascript, blah, blah. Since some of my viewers are looking at it on older Blackberries, I normally figure out how big the bar should be for the initial rendering server-side, and draw the page accordingly, then let the javascript take over after that, on those viewers that have it.
The old code, plain old ASP.NET has an asp:Label in the page where the img tag goes, and on the server I cat together the whole thing. As I refactor to an MVC way of looking at things, I thought how wonderful it would be to only write the width style attribute of the image on the server. The code on the page would be a good deal more understandable that way.
But it doesn't work. Example:
<img src="/content/images/blue_1px.png" class="productionBar_variableBar"
style="width: <% =dbd["ThisShiftProduction_variableBar"] %>;"/>
Unfortunately, Visual Studio doesn't seem to recognize the <% %> escape inside of the quoted style attribute.
Any suggestions?
Siggy

The simplest way - creating HtmlHelper extension:
public static class Html
{
public static string ProgressBar(this HtmlHelper html, int width)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("img src=\"/content/images/blue_1px.png\" class=\"productionBar_variableBar\" style=\"width: {0};\" />", width);
return sb.ToString();
}
// OR
public static string ProgressBar(this HtmlHelper html, int width, string src, string cssClass)
{
TagBuilder tagBuilder = new TagBuilder("img");
tagBuilder.AddCssClass(cssClass);
tagBuilder.MergeAttribute("style", "width: " + width.ToString());
string srcUrl = new UrlHelper(html.ViewContext.RequestContext).Content(src);
tagBuilder.MergeAttribute("src", srcUrl);
return tagBuilder.ToString(TagRenderMode.Normal);
}
}
Using it:
<%= Html.ProgressBar(dbd["ThisShiftProduction_variableBar"]) %>
<!-- OR -->
<%= Html.ProgressBar(dbd["ThisShiftProduction_variableBar"], "~/content/images/blue_1px.png", "productionBar_variableBar") %>

Have you tried doing this instead
<img src="/content/images/blue_1px.png" class="productionBar_variableBar" style='width: <% =dbd["ThisShiftProduction_variableBar"] %>;'/>
Notice the single quotes instead of the double quotes in the style attribute

Related

Inline Razor output after dash

I don't know how to output a variable in Razor as part of an attribute name after a dash:
<span data-#(DataAttributeName)="value"/>
// fails, output:
<span data-#(DataAttributeName)="value"/>
<span data- #(DataAttributeName)="value"/>
// works, however, the space results in invalid HTML:
<span data- myname="value"/>
How to do that properly?
Currently, I have the following workaround:
<span #("data-" + DataAttributeName)="value"/>
But I don't like it for obvious style reasons + Visual Studio tells me that "an attribute name is expected" and shows an error (although it seems to work properly), also something I don't like.
That's a tricky part in razor engine, it tries to be smart to save some escape but sometimes leave no easy solution in scenarios like this.
Just to stay neat, I may create a HtmlHelper Extension, which might be a overkill, but just in case you are sick of red things in editor like me :)
public static class MyHtmlHelperExtension
{
public static MvcHtmlString DataAttribute(this HtmlHelper helper, string attrName, string value)
{
return new MvcHtmlString(string.Format("data-{0}='{1}'", attrName, value));
}
}
Then in your view it can be somehow cleaner:
<span #Html.DataAttribute(DataAttributeName, "value") />

Html.TextArea generates extra line break by default

I'm rendering a usual textarea like this:
#Html.TextAreaFor(x => x.Description)
I expected to see an empty textarea but here is what I see instead (I selected the first line to make it more clear):
I checked out the generated html and it contains a line break between an opening and closing tags:
<textarea class="form-control" cols="20" id="Description" name="Description" rows="2">
</textarea>
Is that done by design? Can I change this behaviour?
After saw your question, I research on Google to see what is the issue behind extra line in #Html.TextAreaFor. Have a look.
There are some articles those are related to your issue:-
http://www.peschuster.de/2011/11/new-line-bug-in-asp-net-mvcs-textarea-helper/
ASP.NET MVC Textarea HTML helper adding lines when using AntiXssLibrary
Articles suggested that basic issue in TextAreaHelper class which is used by #Html.TextAreaFor.
private static MvcHtmlString TextAreaHelper(HtmlHelper htmlHelper,
ModelMetadata modelMetadata, string name, IDictionary<string,
object> rowsAndColumns, IDictionary<string, object> htmlAttributes)
{
// Some initialization here...
TagBuilder tagBuilder = new TagBuilder("textarea");
// Some more logic...
tagBuilder.SetInnerText(Environment.NewLine + attemptedValue);
return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}
and the issue in above code is
tagBuilder.SetInnerText(Environment.NewLine + attemptedValue);
That's why actual output of #Html.TextAreaFor will be like this and extra line shows up:-
<textarea>
This is the content...</textarea>
The workaround of this problem is to
1st Workaround Implementing a Javascript onLoad fix to remove the offending encoding from all textareas:
$("textarea").each(function () { $(this).val($(this).val().trim()); });
2nd Workaround create your own helper for rendering textarea markup in views
public static MvcHtmlString FixedTextAreaFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return new MvcHtmlString(htmlHelper.TextAreaFor(expression)
.ToHtmlString()
.Replace(">
", ">" + Environment.NewLine));
}
These articles also suggested that this problem will be fixed in MVC 4 Developer Preview!

Mvc Html.Label or Html.TextBox doesn't create

I'm making a test page for a project I'm working on and I've made desired progress so far but I'm trying to create TextBoxes from a model of List being passed to the view, however, the it seems to just ignore anything I have tried.
<form id="form1" runat="server">
<input id="btnsubmit" type="submit" name="Submit" onclick="Submit" />
<div id="divControls">
<% foreach (TextBox control in (this.Model as List<TextBox>))
{
Html.Label("lblLabel", control.Text);
Html.TextBox(control.ID, control.Text, new { id = control.ID, style = "width:50", name = "txt" + control.ID });
} %>
</div>
</form>
The List isn't null in the Controller on return. I don't have a clue at what the problem could be. If I throw a Something in the for loop it executes the appropriate number of times so why isn't it creating the labels or textboxes?
At first I thought it was that I'm adding them inside a form but I removed the form tags and it still didn't work so I really have no Idea, any help would be much appreciated. I'm relatively new to MVC.
[HttpPost]
public ActionResult Index(FormCollection form)
{
List<TextBox> controls = new List<TextBox>();
foreach (String Key in form.Keys)
{
if (Key.Contains("txt"))
{
TextBox textBox = new TextBox();
textBox.ID = Key;
textBox.Text = form.GetValues(Key)[0];
controls.Add(textBox);
}
}
return View("Index", controls);
}
Here's my Action encase it's helps.
Also encase I wasn't clear enough, I am adding controls to a form at runtime using JQuery and then that Action will be part of the submit so it must send the textboxes back to the view so they are not deleted.
Like I said I'm new to the whole MVC and Asynchronous thing so If there's a better way to do this, advice would be much appreciated.
Your not printing the html
<% foreach (TextBox control in (this.Model as List<TextBox>))
{%>
<%=Html.Label("lblLabel", control.Text)%>
<%=Html.TextBox(control.ID, control.Text, new { id = control.ID, style = "width:50", name = "txt" + control.ID })%>
<% } %>
Your code is looping through the controls and the Html.whaterever is returning a string but your not doing anything with it, just discarding it.
you also don't need to return a whole TextBox object. This is probably inefficient. Just return an struct or a class containing your data
Html.Label returns a string containing a <label> tag.
You're discarding that string.
You need to write it to the page by writing <%= Html.Whatever() %>.

Writing/outputting HTML strings unescaped

I've got safe/sanitized HTML saved in a DB table.
How can I have this HTML content written out in a Razor view?
It always escapes characters like < and ampersands to &.
Supposing your content is inside a string named mystring...
You can use:
#Html.Raw(mystring)
Alternatively you can convert your string to HtmlString or any other type that implements IHtmlString in model or directly inline and use regular #:
#{ var myHtmlString = new HtmlString(mystring);}
#myHtmlString
In ASP.NET MVC 3 You should do something like this:
// Say you have a bit of HTML like this in your controller:
ViewBag.Stuff = "<li>Menu</li>"
// Then you can do this in your view:
#MvcHtmlString.Create(ViewBag.Stuff)
You can use
#{ WriteLiteral("html string"); }
Sometimes it can be tricky to use raw html. Mostly because of XSS vulnerability. If that is a concern, but you still want to use raw html, you can encode the scary parts.
#Html.Raw("(<b>" + Html.Encode("<script>console.log('insert')</script>" + "Hello") + "</b>)")
Results in
(<b><script>console.log('insert')</script>Hello</b>)
You can put your string into viewdata in controller like this :
ViewData["string"] = DBstring;
And then call that viewdata in view like this :
#Html.Raw(ViewData["string"].ToString())
Apart from using #MvcHtmlString.Create(ViewBag.Stuff)
as suggested by Dommer, I suggest you to also use AntiXSS library as suggested phill http://haacked.com/archive/2010/04/06/using-antixss-as-the-default-encoder-for-asp-net.aspx
It encodes almost all the possible XSS attack string.
Complete example for using template functions in RazorEngine (for email generation, for example):
#model SomeModel
#{
Func<PropertyChangeInfo, object> PropInfo =
#<tr class="property">
<td>
#item.PropertyName
</td>
<td class="value">
<small class="old">#item.OldValue</small>
<small class="new">#item.CurrentValue</small>
</td>
</tr>;
}
<body>
#{ WriteLiteral(PropInfo(new PropertyChangeInfo("p1", #Model.Id, 2)).ToString()); }
</body>

Inline Code on Webform Property

Why doesn't this display the date/time when rendered?
<asp:Label runat="server" ID="test" Text="<%= DateTime.Now.ToString() %>" ></asp:Label>
Is there anyway to make this work?
Asp.net server controls don't play well with the <%=, instead you can do:
<span><%= DateTime.Now.ToString() %></span>
Ps. you could alternatively set the label's text on the code-behind. It might work for your scenario to set it on the PreRenderComplete.
I'm not sure if you've got a code behind file, but if you really need to set the label's Text property in the .aspx markup you could add the following code to the page:
<script runat="server">
protected override void OnPreLoad(EventArgs e)
{
if (!Page.IsPostBack)
{
this.test.Text = DateTime.Now.ToString();
base.OnPreLoad(e);
}
}
</script>
This way you can maintain the label control's state on postback.
Put the inline code inside the label's tag as below,
< asp:Label ID="Lbl" runat="server" Text="">
<%= DateTime.Now.ToString() %>
< /asp:Label>
Well the asp tags are rendered. You will have to set the property at runtime. or just do the <%= DateTime.Now.ToString() %>.
The simplest way to make that work would be to use a data-binding expression in place of the code render block...
<asp:Label runat="server" ID="test" Text="<%# DateTime.Now.ToString() %>" ></asp:Label>
Now the Text property will be set whenever Page.DataBind() is called, so in your code-behind you'll want something like
protected override void OnPreRender(EventArgs e)
{
if (!Page.IsPostBack)
{
DataBind();
}
base.OnPreRender(e);
}
The real problem here though is I need to set the property of a WebControl with code on the markup page. The only way I've found to do this is put the whole control in a code block. Its not elegant or suggested but when all else fails this will work.
<%
var stringBuilder = new StringBuilder();
var stringWriter = new StringWriter(stringBuilder);
var htmlWriter = new HtmlTextWriter(stringWriter);
var label = new Label { Text = DateTime.Now.ToString() };
label.RenderControl(htmlWriter);
Response.Write(stringBuilder.ToString());
%>
But this won't work if you need the control to maintain state.
UPDATE:
After researching Kev's answer I did find an even better solution. I don't have a code behind (its an MVC page) but you can still reference a control on the page through a code block so my new solution is the following. Note - You have to place the code block first for this to work.
<%
lblTest.Text = DateTime.Now.ToString();
%>
<asp:label runat="server" ID="lblTest" />
Thanks for the inspiration Kev!

Resources