Hash in Html.BeginForm - c#

This is the row I'm having problems with:
<% using(Html.BeginForm("Create#result", "Report", FormMethod.Post)) { %>
Using C# 3.5 and MVC2 the form was rendered like this:
<form action="/Report.aspx/Create#result" method="post">
Now with C# 4.0 and MVC2 the form is rendered like this:
<form action="/Report.aspx/Create%23result" method="post">
This causes problems:
System.Web.HttpException (0x80004005): A public action method 'Create#result' was not found
I think the new behaviour is problematic and I don't want the hash escaped.
Where does it occur?
Can I change the behaviour?
The MVC version should be updated at some time, but I was working on another part when this behaviour started causing problems.
Update
I solved it by updating the form action using jquery on the client.
The form
<% using(Html.BeginForm("Create", "Report", FormMethod.Post, new { id = "frmReport" })) { %>
Javascript
var frmReport = $("#frmReport");
if (0 < frmReport.length) {
var action = frmReport.attr("action");
action = action + "#result";
frmReport.attr("action", action);
}

This occurs deep within a MVC class System.Web.Mvc.TagBuilder meaning that there probably isn't a lot you can do about it. I wouldn't be surprised if this code hasn't changed, but that the underlying html encoding function was modified with .NET 4 instead.
private void AppendAttributes(StringBuilder sb)
{
foreach (KeyValuePair<string, string> current in this.Attributes)
{
string key = current.Key;
if (!string.Equals(key, "id", StringComparison.Ordinal) || !string.IsNullOrEmpty(current.Value))
{
string value = HttpUtility.HtmlAttributeEncode(current.Value);
sb.Append(' ').Append(key).Append("=\"").Append(value).Append('"');
}
}
}
That said I'm surprised this was working for you in the first place, I believe some browsers (IE) don't support hashtags in form postbacks.

Related

What references should I add to this Razor based ASP.NET sample

I'm trying to learn Razor / ASP.NET. I have some sample code that I'm trying to get to run. I can't seem to figure out what references to add.
I get errors on: IsPost below
#{
ViewData["Title"] = "Home Page";
#using Newtonsoft.Json;
#using System.Net;
#using System.IO;
List<string> files = new List<string>();
if (IsPost)
{
string GetURL = "http://demo.azurewebsites.net/api/File";
WebClient client = new WebClient();
Stream dataStream = client.OpenRead(GetURL);
StreamReader reader = new StreamReader(dataStream);
var results = JsonConvert.DeserializeObject<dynamic>(reader.ReadLine());
reader.Close();
foreach (var item in results)
{
files.Add((string)item.filename);
}
}
}
It is possible that you are typing this in a view without enclosing it in #{...}. In your view, you should have it enclosed in #{...} to tell Razor the code block is a C# (or VB, whichever is the case for your project).
Having said that, inserting too much code in the View is not ideal. Views should only be responsible in presenting data, not in extracting them.
UPDATE
Your issue is likely a duplicate of this SO item:
Razor-based view doesn't see referenced assemblies
See the answers by #qes and #V.B.
Well, based on the link you provided in your comment in a prior answer, you're using ASP.Net WebPages - which is a great lightweight way of getting an ASP.Net site up using Razor syntax. It's not however MVC so for one thing you won't have things like ViewData, but that's ok - you can use Page or PageData.
This would be how an entire page would look like (though typically you'd use _layout file in combination with "content files"):
#using Newtonsoft.Json;
#using System.Net;
#using System.IO;
#{
/*
Page or PageData instead of ViewBag/ViewData
*/
Page.Title = "Hello World"; //this is typically used with a _layout.cshtml where the<title> Tag would be
//You can create/name Page properties/data as needed
Page.Whatever = "whatever I want";
Page.H1TagForSeo = "this is the h1 tag";
Page.SomeInteger = 100;
Page["MyPageData"] = DateTime.UtcNow;
List<string> files = new List<string>();
if (IsPost)
{
//IsPost test - this will only run if this page is requested via POST
for (int i = 0; i < 10; i++)
{
files.Add(i.ToString());
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>#Page.Title</title>
</head>
<body>
<h1>#Page.H1TagForSeo</h1>
<p>The time is #Page["MyPageData"]</p>
<p>
You can use <code>##Page propertes/data similar to ViewBag/ViewData</code> #Page.Whatever was viewed #Page.SomeInteger times
</p>
#if (IsPost)
{
<div>Post Test</div>
<p>This entire section will only be displayed when requested via POST</p>
<p>#string.Join(",", files)</p>
}
</body>
</html>
Hth...

Convert ActionResult and PartialView IEnumerable results to return json objects

What is the best approach to take when converting a basic ActionResult to JSON objects and rendering them in a PartialView? My objective is to modify the application so that instead of the page rendering only the comments in the db at the time of the page request to a type of data service that updates thePartialView to add any incoming comments that may have been posted since the last page request. I think the solution I am looking for will use OData in json format and then bind that data using knockout.js, but not sure.
Here is the Controller ActionResult which returns an IEnumerable list of objects from the repository to a PartialView:
[ChildActionOnly]
public ActionResult GetCommentsById(int AId = 0)
{
if (AId == 0)
return HttpNotFound();
return PartialView("_CommentsPartial",
_unitOfWork.ArticleRepository.GetCommentsByArticleId(AId));
}
Here is a snippet of the PartialView to keep things short:
#model IEnumerable<BlogSite.Models.Comment>
#using BlogSite.Helpers;
<ul id="comments-list">
#{
foreach (var comment in Model)
{
<!--Grabs Parent Comment and then all replies w/ParentCommentId b4 grabs new Parent Comment -->
if (comment.isRoot && comment.ParentCommentId == null)
{
<!-- Comment -->
int counter = 0; foreach (var c in Model) { if (c.ParentCommentId == comment.CommentId) { counter += 1; } }
<li id="#comment.CommentId" itemscope itemtype="http://schema.org/UserComments" class="comment-container" tabindex="#comment.CommentId">
Then I call it from the Details view:
<div id="comments-panel" class="panel-box">
<div class="show-comments"><div id="upNdown"></div><span id="showNhide">Show Comments</span></div><br /> <br />
<div id="comments-partial" style="display:none;">
#Html.Action("AddComment", "Comment", new { AId = Model.ArticleId })
#Html.Action("GetCommentsById", "Article", new { AId = Model.ArticleId })
</div>
</div>
How can I make this conversion as painless as possible? Thanks in advance!
I think I gather from your question that the controller already did its work and that you simply want to "consume" the data output from it as if it were an AJAX request using the same js code. You can do this fairly easily by just serializing the data in the model using the Newtonsoft Json.NET api and extensions provided by Forloop.HtmlHelpers. These can be installed as nuget packages if you haven't already.
First, you would place this in your partial view
Note: If you don't want to install the Newtonsoft package you can replace JsonConvert.SerializeObject with the System.Web.Helpers method Json.Encode
#{
using (var context = Html.BeginScriptContext())
{
Html.AddScriptBlock("var jsonData=" + JsonConvert.SerializeObject(Model) + ";");
}
}
Then in your layout page, to ensure that your script block is rendered at the appropriate time, add this call to Html.RenderScripts
#Scripts.Render("~/bundles/jquery")
#*Add any other dependency scripts*#
#Html.RenderScripts()
#RenderSection("scripts", required: false)
This is why you need the Forloop.HtmlHelpers package, these extension methods help mitigate out-of-order script code getting rendered in the partial view before jQuery or anything else has started up.
Hope that helps

cshtml c# not listening to assigned id for some reason?

So I have a basic CRUD I am working on, and Im trying to get Jquery validation working on it. I have it almost all set up except I need to give my form an id. I am using cshtml in visual studio and try to assign the id to the form using the following code:
#using (Html.BeginForm( new { id = "daftform" })) {
#Html.ValidationSummary(true)
<fieldset>
<legend>News</legend>
However the generated html looks like this:
<form action="/News/Create/daftform" method="post"> <fieldset>
<legend>News</legend>
I am pretty sure this is how to assign an id to an element as I use this method to assign classes in a similar way. Can anyone tell me where im going wrong?
I just want it to assign 'daftform' as an id not as an action.
Sorry if its a simple answer, fairly new to c#.
Use this overload
public static MvcForm BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName,
FormMethod method,
Object htmlAttributes
)
So your code can be changed to
#using (Html.BeginForm("Create","News",FormMethod.Post, new { id = "daftform" }))
{
//form elements
}
This will create a form tag with Id property set to "daftform"
#using (Html.BeginForm(,"actionname","controllername",formmethod.post/get, new {id = "yourId"})
is the way to go

Is it a Bad idea to use `<%=` in a WebControl

Recently I've started using <%= more often in my Web Controls. Typically I'll set String properties in the Code Behind and then spit them out onto the form.
Is this a bad idea?
eg.
Code Behind:
Properties:
public string TheTitle { get; set; }
public string TheBody { get; set; }
public ContentItem TheContent { get; set; }
public string ContentId {
get
{ return "content" + (TheContent != null) ? TheContent.Id.ToSTring() : "0"; }
}
Page_Load:
TheTitle = TheContentItem.Title;
TheBody = TheContentItem.Body;
On Page:
<div id='<%= ContentID %>'>
<h2 class='title'><%= TheTitle ?? "No Title" %></h2>
<p><%= TheBody %></p>
</div>
It is only a problem when the data is not validated.
Using .NET 4's <%: TheBody %> syntax is an effective way to encode potentially-untrusted data. In earlier versions of the framework, you can use <%= HttpUtility.HtmlEncode(TheBody) %> to the same effect.
It is bad if the data comes from an user input as your site will be vulnerable to XSS.
No it's not a problem* because it will be scoped to your control. You don't have to worry about anything conflicting in your case but if you were writing out server controls with IDs you could run into problems.
How your using it, ok (*assuming you have cleaned the data before assigning it to your variable). Just keep in mind there are times when it can be an issue with duplication of IDs, controls, scripts, etc...
Edit: Before assigning it to your varible you could use HttpUtility.HtmlEncode or if you using ASP.NET 4 you can use the <%: syntax depending on what you are outputting. This fall under the same rules as doing it an aspx, it's ok but you just need to be careful. This is also how much of ASP.NET MVC is used. The views can be literred with <%= and <%: Obviously using any type of encoding on any HTML itself would not be useful.

How can I not render a button in my view if a given property off my model has no value?

I'm new to web development. In my view, I want to conditionally show a button if Model.TemplateLocation (which is a string) is not null or empty. Below is the code that is rendering the button currently:
<div class="WPButton MyButton">
<%=Html.ActionLink(Model.TemplateLinkName, "DownloadTemplate", "ExternalData", new ArgsDownloadTemplate { Path = Model.TemplateLocation, FileName = Model.TemplateFileNameForDownload }, new{})%>
</div>
Can I wrap some C# code in the <% %>'s to test for Model.TemplateLocations value before I render that? I was told to look into #style = "display:none" somehow. Could that be what I need?
You can add control statements in code blocks to conditionally output HTML.
<% if (Model.SomeCondition) { %>
<div>
<ul>
<%=Html.ActionLink(Model.TemplateLinkName, "DownloadTemplate", "ExternalData", new ArgsDownloadTemplate { Path = Model.TemplateLocation, FileName = Model.TemplateFileNameForDownload }, new{})%>
</ul>
</div>
<% } %>
Incidentally, the <%= %> version of the tag is simply a shortcut for a code call to Response.Write(). So this will accomplish the exact same thing:
<% if (Model.SomeCondition) {
Response.Write("<div><ul>");
Response.Write (Html.ActionLink(Model.TemplateLinkName, "DownloadTemplate", "ExternalData", new ArgsDownloadTemplate { Path = Model.TemplateLocation, FileName = Model.TemplateFileNameForDownload }, new{}));
Response.Write("</ul></div>");
} %>
Much debate exists as to the correctness of either method. Many people hate the number of ASP tags they have to use to do the first way, many people feel the second way is incorrect for whatever reason. I find I use both when it offers simpler reading of the code.

Categories