Issue with <%: ... %> vs. <%= %> when displaying generated text - c#

I am writing an MVC application with C#. In this one particular section, I have a conditional switch for the navigation to highlight the appropriate tab. Here is the code for that:
<script type="text/C#" runat="server">
string oController;
string oAction;
const string current = "class=\"current_page\"";
protected override void OnLoad(EventArgs e)
{
oController = ViewContext.RouteData.Values["controller"].ToString();
oAction = ViewContext.RouteData.Values["action"].ToString();
base.OnLoad(e);
}
</script>
<div id="menu">
<ul>
<li <%= (oController.Equals("Home") ? current : "") %>>Home</li>
<li>Customer Manager</li>
<!-- <%: oController.Equals("Home") %> -->
<!-- <%: oAction %> -->
</ul>
</div>
On this line (<li <%= (oController.Equals("Home") ? current : "") %>>Home</li>) if I use the <%: %> ASP nugget instead of <%= %> (as is recommended, since the latter is being phased out soon), the generated text comes out as
<li class="current_page">Home</li>
Instead of
<li class="current_page">Home</li>
Any suggestions and/or reasons why this is happening? Thanks!

Because <%: is intended to encode data such as user input. In your case, that is self-generated (trusted) html, so you don't want to encode it; <%= is the correct usage.
<%: is for things like <%:user.Name%>, which conveniently prevents issues for malicious text with xss etc in it.

You could just have the class be empty when the value is not Home. Clearly you are trying to omit it all together, but it would be a solution none the less.
const string current = "current_page";
<li class="<%: (oController.Equals("Home") ? current : "") %>">Home</li>

Related

ASP form parameter names being changed to include the master page contentplaceholder

Here is my page:
<%# Page Language="C#" MasterPageFile="~/FBMaster.master" CodeFile="ViewOffer.aspx.cs" Inherits="ViewOffer" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<%
FlightBookingWS.FlightBookingSoapClient client = new FlightBookingWS.FlightBookingSoapClient();
FlightBookingWS.Offer offer = client.GetOffer(Request.Form["OfferID"]);
if (offer != null)
{
%>
<div class="OfferDiv">
<span><b>Origin Airport: </b><%=offer.OriginAirport ?? "" %></span>
<span><b>Destination Airport: </b><%=offer.DestinationAirport ?? "" %></span>
<span><b>Airline: </b><%=offer.Airline ?? ""%></span>
<span><b>Available Seats: </b><%=offer.AvailableSeats%></span>
<span><b>Number Of Connections: </b><%=offer.NumberOfConnections%></span>
<%
if (offer.Fare != null)
{
%>
<span><b>Fare: </b><%=String.Format("{0:0.00} {1}", offer.Fare.Value, offer.Fare.Currency) %></span>
<form runat="server">
<span>
<input type="hidden" id="OfferIDField" runat="server" />
<input type="hidden" id="MessageField" runat="server" />
<b>Number of Seats: </b>
<asp:TextBox ID="NumSeatsField" runat="server" Text="1" />
<asp:Button runat="server" Text="Book now" />
</span>
</form>
<%
}
}
else
{
%>
Offer not found.
<%
}
%>
<div id="ErrorBox" runat="server"></div>
</div>
</asp:Content>
Whenever I submit the form, the keys used in the post data are changed from the IDs I wrote to the following ones:
Ideally I'd like to access them using the same keys as the IDs of the inputs they came from, like in normal HTML.
That's not how ASP.NET web forms work
When you put markup on a page with the runat="server" attribute, you are not actually writing page markup. You are defining server-side controls that emit page markup. You're not meant to use them like actual HTML elements.
When the page is posted back, the ASP.NET framework looks at the request message and parses all of the values. It then populates the server-side controls with the necessary data so you can retrieve it easily using ASP.NET syntax.
So, instead of
var offerID = Request.Form["ctl100$ContentPlaceHolder1#OfferIDField"]
you should simply use
var offerID = this.OfferID.Text;
This is the way ASP.NET web forms work.
The old-fashioned way
If you'd rather do it the old-fashioned way, remove the runat="server" attribute and write your markup like regular HTML:
<INPUT ID="OfferID" Name="OfferID">
...and then you can read it the "normal" way:
var offerID = Request.Form["OfferID"];

Use model on SharePoint application page .aspx

I am working on SharePoint to create a Feedback questionnaire form using an application page that is basically a aspx page.
I wish to do this by emulating MVC as far as possible. I've set up my model in the code-behind:
public List<QuestionViewModel> modelQuestions = new List<QuestionViewModel>();
Next, I need to display each question and an appropriate input depending on the question type (e.g. single line, multi line, single selection, multiple selection).
I've got it displaying the questions correctly:
<fieldset class="what-went-wrong">
<% for (int i = 0; i < modelQuestions.Count; i++) { %>
<p>
<label for="QuestionText">
<% if (modelQuestions[i].Required) { %>
<span class="req-field indicator">*</span>
<% } %>
<%= modelQuestions[i].QuestionText %>
<% if (modelQuestions[i].Required) { %>
<span class="req-field right">* Required field</span>
<% } %>
</label>
</p>
<% } %>
</fieldset>
This give's me the question text. I'm now trying to construct the appropriate input, but this <% %> tags is not working for this:
<% if(modelQuestions[i].QuestionTypeId == QuestionType.SingleLine) { %>
<input id="modelQuestions_<% i %>" name="modelQuestions[<% i %>]" type="text" placeholder="<% modelQuestions[i].Placeholder %>" />
<% } %>
I can't seem to get it to construct the html element using details from the model (in the value for id, name, placeholder etc.)
Also, I've no idea how to go about posting this back to the server when I get to that point.
Is there any merit in continuing? Are there other controls/methods more appropriate to use in this case with aspx?
You cannot generate HTML markup like this. Even data-binding expressions will not help, because they bind ASP.NET controls' attributes values, not the plain output HTML in the page.
You should generate the markup in the "code behind", like this:
Page markup:
<div id='AnswersPanel'>
<div>
Page code behind:
protected void PageLoad(...)
{
AnswersPanel.InnerHtml = "";
AnswersPanel.InnerHtml += string.Format("<input id='modelQuestions_{0}' name='modelQuestions[{0}]' type='text' placeholder='{1}' />",
i.ToString(),
modelQuestions[i].Placeholder);
}

session verification masterpage (?) asp.net c#

I have a blank page with two buttons.
the first button's click code is this:
Session["permissionUser"] = "1";
and here's the second button code:
Session["permissionUser"] = "2";
and then i have a hyperlink which redirects to the "main" website.
my objective is to adapt the menu bar which is on the masterpage based on the permission saved in the session. here's part of my code in the masterpage:
<body>
<div id="menuBar">
Home
<% if (Session["permissionUser"] == "1"){ %>
PERMISSION 1 LINK
<% } %>
<% if (Session["permissionUser"] == "2"){ %>
PERMISSION 2 LINK
<% } %>
</div>
<div id="content">
<asp:ContentPlaceHolder ID="websiteContent" runat="server"></asp:ContentPlaceHolder>
</div>
</body>
the problem is when i run the application, even if i click any of the buttons the menu doesnt adapt at all. it just shows the hyperlink "Home" and not any of the others which were supposed to be shown since the session is either 1 or 2 (depending on which button i clicked)
i cant really see what im doing wrong so if you guys have any suggestions i'd be really grateful
Your code is very PHPish. That is to say, it's ugly. And unwieldy. Let's put the logic in the code behind. We also need a form so we can have controls that run on the server.
public void Page_Load(object sender, EventArgs e)
{
//you should probably also check to make sure the session has "permissionUser" in it
if (Session["permissionUser"] == "1")
{
Permission1HL.Visible=true;
}
else if(Session["permissionUser"] == "2")
{
Permission2HL.Visible=true;
}
}
And change your ASPX page to this.
<body>
<form runat="server">
<div id="menuBar">
Home
<asp:HyperLink runat="server" id="Permission1HL" Text="Permission 1 Link" Visible="false" />
<asp:HyperLink runat="server" id="Permission2HL" Text="Permission 2 Link" Visible="false" />
</div>
<div id="content">
<asp:ContentPlaceHolder ID="websiteContent" runat="server"></asp:ContentPlaceHolder>
</div>
</form>
</body>
I suggest that you make a serverside hyperlink control instead, and set the text and navigateurl from codebehind
<asp:HyperLink id="hyperlink1"
NavigateUrl="http://mydefaulturl.com"
Text="DefaultText"
runat="server"/>
from code behind:
if (Session["permissionUser"] == 1)
{
hyperlink1.NavigateUrl = "#"
hyperlink1.Text = "Permission 1 link"
}...
This will allow you to better control and debug your values.
I would actually be more specific in the if statement
<% if (Session["permissionUser"].toString() == "1"){ %>
with null checks
<% if (Session["permissionUser"] != null && Session["permissionUser"].toString() == "1"){ %>

ASP.net - The name 'pageNumber' does not exist in the current context

I'm trying to create a pager in ASP.net and am running into an error.
Trying to do this in my markup:
<div class="pager">
<% foreach(int pageNumber in this.PageCollection) { %>
<% if( pageNumber == this.PageIndex ) { %>
<span class="current"><%= pageNumber %></span>
<% } else { %>
<asp:LinkButton ID="lnkGoToPage" runat="server" OnClick="lnkGoToPage_Click"><%= pageNumber %></asp:LinkButton>
<% } %>
<% } %>
I am getting the following error:
Compiler Error Message: CS0103: The name 'pageNumber' does not exist in the current context
The error is happening on the LinkButton line. It works fine on the first if case...but for some reason my variable does not exist on the else case.
Does anyone have any idea why this is not compiling or how I could do the same thing differently.
It's been a while since I have done regular ASP.net and I am used to the MVC way.
You can't place <%= pageNumber %> inside a LinkButton.
Alternatively, use the Repeater control and the OnItemDataBound event to add logic such as pageNumber == this.PageIndex in the code behind.
<asp:Repeater ID="Pager" runat="server">
<ItemTemplate>
<asp:Literal ID="ltlGoToPage" runat="server" Visible="false"></asp:Literal>
<asp:LinkButton ID="lnkGoToPage" runat="server" OnClick="lnkGoToPage_Click" Visible="false"></asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
You can toggle the visibilty of the controls in the OnItemDataBound event.
In the code behind, reference the controls and apply any logic:
var ltlGoToPage = (Literal)e.Item.FindControl("ltlGoToPage");
var lnkGoToPage = (Literal)e.Item.FindControl("lnkGoToPage");
<div class="pager">
<% foreach(int pageNumber in this.PageCollection) {
if( pageNumber == this.PageIndex ) { %>
<span class="current"><%= pageNumber.ToString() %></span>
<% } else { %>
<asp:LinkButton ID="lnkGoToPage" runat="server" OnClick="lnkGoToPage_Click"><%= pageNumber.ToString() %></asp:LinkButton>
<% }
} %>
This will help eliminate some of the markup. Also, called ToString() on page number as that's just common practice for me, but you might not want it that way.
This is not how you do things in asp.net web forms, you should do the loop in the code behind.
The error is caused by the fact that the problem <%= pageNumber %> is in the middle of a control.
Sorry about my previos post. I wanted to say the way I see it is to use Text property of the control.
This should work:
<div class="pager">
<% foreach(int pageNumber in this.PageCollection) { %>
<% if( pageNumber == this.PageIndex ) { %>
<span class="current"><%= pageNumber %></span>
<% } else { %>
<asp:LinkButton ID="lnkGoToPage" runat="server" OnClick="lnkGoToPage_Click"></asp:LinkButton>
<%
lnkGoToPage.Text = pageNumber.ToString();
} %>
<% } %>
Also, you should think about giving sdifferent IDs to the LinkButtons to make sure they are different. But, conceptually, the code above should work

Asp.Net MVC form, with unknown parameters for Controller

I'm building a questionnaire mvc webapp, and i cant figure out how to pass an unknown number of arguments to the controller from the form.
My form is something like:
<% using (Html.BeginForm())
{ %>
<div id="Content">
<% foreach (var group in ViewData.Model.QuestionGroups)
{ %>
<div class="Group">
<%=group.Description %>
<% foreach (var question in group.Questions)
{%>
<div class="Question">
<div class="QuestionTitle">
<%=question.Title %>
</div>
<%=Html.Hidden("Id", question.ID) %>
<div class="QuestionText">
<%switch (question.TypeAsEnum)
{
case QuestionTypeEnum.Text:%>
<%=Html.TextBox("somename") %>
<% break;
case QuestionTypeEnum.Number:%>
<%=Html.TextBox("somename") %>
<% break;
case QuestionTypeEnum.PhoneNumber:%>
<%=Html.TextBox("somename")%>
<% break;
case QuestionTypeEnum.Email:%>
<%=Html.TextBox("somename")%>
<% break;
case QuestionTypeEnum.Date:%>
<%=Html.TextBox("somename")%>
<% break;
case QuestionTypeEnum.YesNo:%>
<%=Html.RadioButton("somename", true)%>
<%=Html.RadioButton("somename", false)%>
<% break;
case QuestionTypeEnum.Alternative:%>
<%=Html.DropDownList("somename", question.Answers)%>
<% break;
}%>
</div>
</div>
<% } %>
</div>
<% } %>
</div>
<div id="submittButton">
<%=Html.SubmitButton()%></div>
<% } %>
Now what i need in my controller is List< ResponseAnswer >,
where ResponseAnswer has the properties:
string questionID,
string AnswerText,
bool AnswerBool,
number AnswerNumber,
...
So how can i pass an unknown number of items containing questionID, AnswerType and Answer to the controller.
In webforms i solved this by rendering the form with repeaters instead of foreach, and then iterating through the question repeater checking the control id, each repeater item containing a hidden questionid element and a input with id=AnswerType.
But this will seriously break Separation of concern in mvc?
So is there any way of getting my controller to accept List< ResultAnswer > and somehow build this list without breaking soc, and if not, how do i pass the entire formresult back to the controller so i can do the iteration of the form data there instead of in the view.
You can add an argument to your action like
public ActionResult MyAction(FormCollection form)
Then the form parameter will contain all the data from the posted form. From that you can do what you want.
You could probably implement a binder that could map to ResponseAnswers but I have no experience of doing that so I'll leave that to someone else.
Garry's answer will work (and hence, up voted). However, you can model bind directly to a list, and I think it's a bit more elegant. There are instructions in this blog post.
To clarify gary's answer, you can then easily walk through all fields of the form like this
foreach (string s in Request.Form.Keys)
{
if (s.Contains("number"))
number = int.Parse ((Request.Form[s]));
//do something
}

Categories