Order Your ASP.NET Embedded Code Blocks Correctly
As explained here, the code in embedded code blocks gets run as part of the rendering portion of the ASP.NET page life cycle. This caused me some trouble when I tried to set the value of a Literal control after that control had been rendered:
<%@ Page Language="vb" %>
<html>
<head>
<title>Literal First Does Not Work</title>
</head>
<body>
<form runat="server">
<asp:Literal runat="server" ID="litHello" />
<%
litHello.Text = "Hello World"
%>
</form>
</body>
</html>You don’t get an exception to help you out either… the content simply does not render. The reason for this is that the Literal control appears before the embedded code block, which means it gets rendered (i.e., converted to HTML) before the code block is run. So, the code block does set the Text property of the control, but since the control has already been rendered, that Text property is ignored. Here is the correct way to go about doing this:
<%@ Page Language="vb" %>
<html>
<head>
<title>Literal Last Does Work</title>
</head>
<body>
<form runat="server">
<%
litHello.Text = "Hello World"
%>
<asp:Literal runat="server" ID="litHello" />
</form>
</body>
</html>The code block gets run first, so it sets the Text property before it is used to render the Literal control.
Get TinyMCE Value from Server-Side in ASP.NET 4.0
First, download TinyMCE and unzip it. Add the “tiny_mce” folder to a new ASP.NET 4.0 website project. Add a new ASPX page to your project, and add the following code to that page (VB.NET version shown first):
<%@ Page Language="vb" ValidateRequest="false" %>
<script runat="server">
Protected Sub GetValue_Click(ByVal sender As Object, ByVal e As EventArgs)
lblDisplay.Text = txtMain.Text
End Sub
</script>
<html>
<head>
<title>TinyMCE in ASP.net 4.0</title>
<script type="text/javascript" src="/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
mode : "textareas"
});
</script>
</head>
<body>
<form id="frmMain" runat="server">
<div>
<asp:TextBox runat="server" ID="txtMain" TextMode="MultiLine" Rows="20" Columns="100">
This is your initial text.
</asp:TextBox>
<br />
<asp:Button runat="server" Text="Get Value" onclick="GetValue_Click" />
<br />
<asp:Label runat="server" ID="lblDisplay" />
</div>
</form>
</body>
</html>Here’s the C# version:
<%@ Page Language="C#" ValidateRequest="false" %>
<script runat="server">
protected void GetValue_Click(object sender, EventArgs e)
{
lblDisplay.Text = txtMain.Text;
}
</script>
<html>
<head>
<title>TinyMCE in ASP.net 4.0</title>
<script type="text/javascript" src="/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
mode : "textareas"
});
</script>
</head>
<body>
<form id="frmMain" runat="server">
<div>
<asp:TextBox runat="server" ID="txtMain" TextMode="MultiLine" Rows="20" Columns="100">
This is your initial text.
</asp:TextBox>
<br />
<asp:Button runat="server" Text="Get Value" onclick="GetValue_Click" />
<br />
<asp:Label runat="server" ID="lblDisplay" />
</div>
</form>
</body>
</html>If you are using ASP.NET 2.0, you are done. However, in ASP.NET 4.0, you have to modify the web.config by adding requestValidationMode="2.0":
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>If you run into the following error when you click the button on the webpage:
ASP.NET error message:
A potentially dangerous
Request.Formvalue was detected from the client (txtMain=“<p>This is your init…”).
Make sure you have requestValidationMode="2.0" in the web.config and make sure you have ValidateRequest="false" at the top of your page.
Caution: Practically speaking, it is necessary to turn off request validation in order to submit data using the TinyMCE editor, but doing so comes with some caveats. Disabling request validation may make your site more vulnerable to script attacks, depending on how you handle the user input on pages with no request validation. Explaining those risks and the precautions to prevent malicious code is outside the scope of this tip/trick, but you can start to learn more about the issue here.
No More Session Variable Misspellings
Posted as an alternative to another member's tip, so it starts mid-conversation.
This can be automated and streamlined with generics. First, create a SessionVariable class:
public class SessionVariable<T>
{
private string VariableName { get; set; }
private System.Web.SessionState.HttpSessionState Session { get; set; }
public T Value
{
get
{
object sessionValue = this.Session[this.VariableName];
if (sessionValue == null)
{
sessionValue = default(T);
}
return (T)sessionValue;
}
set
{
this.Session[this.VariableName] = value;
}
}
public SessionVariable(string variableName,
System.Web.SessionState.HttpSessionState session)
{
this.VariableName = variableName;
this.Session = session;
}
}Next, create a SessionHelper class:
using System;
using System.Reflection;
public class SessionHelper
{
public static void InitializeSessionVariables(object instance,
System.Web.SessionState.HttpSessionState session, string prefix)
{
foreach (var property in instance.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance))
{
if (property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() ==
typeof(SessionVariable<>))
{
property.SetValue(instance, Activator.CreateInstance(
property.PropertyType, prefix + property.Name, session),
new object[] { });
}
}
}
}You can then add properties to your page (or another suitable class) that act as a simple way to access session. Here is an example:
public partial class Default : System.Web.UI.Page
{
public SessionVariable<string> CompanyName { get; set; }
public SessionVariable<int> EmployeeCount { get; set; }
public SessionVariable<System.Text.StringBuilder> CompanyInformation { get; set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
SessionHelper.InitializeSessionVariables(this, Session, "Default.aspx.");
}
protected void Page_Load(object sender, EventArgs e)
{
CompanyName.Value = "Code Project";
EmployeeCount.Value = 5;
Response.Write(CompanyName.Value);
Response.Write(EmployeeCount.Value.ToString());
Response.Write((CompanyInformation.Value ??
new System.Text.StringBuilder("Company information null")).ToString());
}
}That is my code behind for my Default.aspx page. Notice I added 3 generic properties of type SessionVariable. Next, I initialized those properties using my helper method, InitializeSessionVariables (note that I passed in a prefix to ensure the session variables would not conflict with those used on other pages). Finally, I demonstrated their use in the Page_Load method. This makes creating session variables type safe and prevents mistyping session variable names.
ASP.NET Conditions in Markup Using Bound Data
C# Version
Have you ever tried to use an if statement in combination with data binding? You can’t do this (can’t use an if statement in this type of code block):
<%# if (Eval("YadaYada")) { %>And you can’t do this (can’t data bind in this type of code block):
<% if (Eval("YadaYada")) { %>So how do you combine these concepts? Basically, you can use a PlaceHolder with a Visible property set to a bound value (or the result of a condition based on a bound value). Anything (code blocks or markup) inside an invisible PlaceHolder will not be executed. Here is one way to go about that:
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
// Sample class we can use for binding.
public class Animal
{
public Boolean CanFly { get; set; }
public String Description { get; set; }
}
// Setup binding in page load.
protected void Page_Load(Object sender,System.EventArgs e)
{
rpItems.DataSource = new List<Animal> {
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Duck"},
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Goose!"}};
rpItems.DataBind();
}
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<!-- We use placeholder visibility to use different
markup depending on the bound value. -->
<li>
<asp:PlaceHolder runat="server"
Visible="<%# ((Animal)Container.DataItem).CanFly %>">
<b>I can fly!</b>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server"
Visible="<%# !((Animal)Container.DataItem).CanFly %>">
I can't fly.
</asp:PlaceHolder>
<%# HttpUtility.HtmlEncode(((Animal)Container.DataItem).Description) %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html>Alternatively, you can use the placeholders to set the value of a property or variable, which you can then use in code blocks that aren’t data bound:
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
// Sample class we can use for binding.
public class Animal
{
public Boolean CanFly { get; set; }
public String Description { get; set; }
}
// This property is used in the bound control.
protected Boolean CanFlyTemp { get; set; }
// Setup binding in page load.
protected void Page_Load(Object sender,System.EventArgs e)
{
rpItems.DataSource = new List<Animal> {
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Duck"},
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Goose!"}};
rpItems.DataBind();
}
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<!-- We use placeholder visibility to
conditionally execute code based on a bound value. -->
<% CanFlyTemp = false; %>
<asp:PlaceHolder runat="server"
Visible="<%# ((Animal)Container.DataItem).CanFly %>">
<% CanFlyTemp = true; %>
</asp:PlaceHolder>
<!-- Here we will use different markup
depending on the variable value set above. -->
<li>
<% if (CanFlyTemp) { %>
<b>I can fly!</b>
<% } else {%>
I can't fly.
<% }%>
<%# HttpUtility.HtmlEncode(((Animal)Container.DataItem).Description) %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html> VB.NET Version
Have you ever tried to use an if statement in combination with data binding? You can’t do this (can’t use an if statement in this type of code block):
<%# If Eval("YadaYada") Then %>And you can’t do this (can’t data bind in this type of code block):
<% If Eval("YadaYada") Then %>So how do you combine these concepts? Basically, you can use a PlaceHolder with a Visible property set to a bound value (or the result of a condition based on a bound value). Anything (code blocks or markup) inside an invisible PlaceHolder will not be executed. Here is one way to go about that:
<%@ Page Language="vb" AutoEventWireup="false" %>
<script runat="server">
' Sample class we can use for binding.
Public Class Animal
Public Property CanFly As Boolean
Public Property Description As String
End Class
' Setup binding in page load.
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
rpItems.DataSource = New List(Of Animal) From {
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Duck"},
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Goose!"}}
rpItems.DataBind()
End Sub
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<!-- We use placeholder visibility to use
different markup depending on the bound value. -->
<li>
<asp:PlaceHolder runat="server"
Visible="<%# DirectCast(Container.DataItem, Animal).CanFly %>">
<b>I can fly!</b>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server"
Visible="<%# Not DirectCast
(Container.DataItem, Animal).CanFly %>">
I can't fly.
</asp:PlaceHolder>
<%# HttpUtility.HtmlEncode
(DirectCast(Container.DataItem, Animal).Description) %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html>Alternatively, you can use the placeholders to set the value of a property or variable, which you can then use in code blocks that aren’t data bound:
<%@ Page Language="vb" AutoEventWireup="false" %>
<script runat="server">
' Sample class we can use for binding.
Public Class Animal
Public Property CanFly As Boolean
Public Property Description As String
End Class
' This property is used in the bound control.
Protected Property CanFlyTemp As Boolean
' Setup binding in page load.
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
rpItems.DataSource = New List(Of Animal) From {
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Duck"},
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Goose!"}}
rpItems.DataBind()
End Sub
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<!-- We use placeholder visibility to
conditionally execute code based on a bound value. -->
<% CanFlyTemp = False%>
<asp:PlaceHolder runat="server"
Visible="<%# DirectCast(Container.DataItem, Animal).CanFly %>">
<% CanFlyTemp = True%>
</asp:PlaceHolder>
<!-- Here we will use different markup depending on the variable value set above. -->
<li>
<% If CanFlyTemp Then%>
<b>I can fly!</b>
<% Else%>
I can't fly.
<% End If%>
<%# HttpUtility.HtmlEncode(DirectCast(Container.DataItem, Animal).Description) %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html> Alternating Types in Bound Repeater
Variation: Alternating Data Types
Suppose I wanted to expand the example further to support binding a list of different types of classes (say, Animal and Human). The binding code would get very complicated, as the bound contents inside of placeholders still get evaluated even when the placeholders are not visible.
To simplify the binding code, you can use a repeater to wrap the objects of different types (pay particular attention to the use of the ListWrap function):
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
// Sample class we can use for binding.
public class Animal
{
public Boolean CanFly { get; set; }
public String Description { get; set; }
}
// Another sample class for binding.
public class Human
{
public String Name { get; set; }
public String Description { get; set; }
}
// Setup binding in page load.
protected void Page_Load(Object sender, System.EventArgs e)
{
rpItems.DataSource = new List<Object> {
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Duck"},
new Animal {CanFly = false, Description = "Duck"},
new Animal {CanFly = true, Description = "Goose!"},
new Human {Name = "Elephant Man", Description = "I am not an animal!"}};
rpItems.DataBind();
}
// Helper function to wrap a single item in a list if it is of the specified type.
protected List<Object> ListWrap<SomeType>(Object item)
{
List<Object> returnList = new List<object>();
if (item is SomeType)
{
returnList.Add(item);
}
return returnList;
}
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our main data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%-- This repeater is bound to a list with one or zero animals. --%>
<asp:Repeater runat="server" DataSource="<%# ListWrap<Animal>(Container.DataItem)%>">
<ItemTemplate>
<!-- We use placeholder visibility to use different markup depending on the bound value. -->
<asp:PlaceHolder runat="server" Visible="<%# (Container.DataItem as Animal).CanFly%>">
<b>I can fly!</b>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" Visible="<%# !(Container.DataItem as Animal).CanFly %>">
I can't fly.
</asp:PlaceHolder>
<%# HttpUtility.HtmlEncode(((Animal)Container.DataItem).Description) %>
</ItemTemplate>
</asp:Repeater>
<%-- This repeater is bound to a list with one or zero humans. --%>
<asp:Repeater runat="server" DataSource="<%# ListWrap<Human>(Container.DataItem)%>">
<ItemTemplate>
<%# HttpUtility.HtmlEncode((Container.DataItem as Human).Name)%>:
"<%# HttpUtility.HtmlEncode((Container.DataItem as Human).Description)%>"
</ItemTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html><%@ Page Language="vb" AutoEventWireup="false" %>
<script runat="server">
' Sample class we can use for binding.
Public Class Animal
Public Property CanFly As Boolean
Public Property Description As String
End Class
' Another sample class for binding.
Public Class Human
Public Property Name As String
Public Property Description As String
End Class
' Setup binding in page load.
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
rpItems.DataSource = New List(Of Object) From {
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Duck"},
New Animal With {.CanFly = False, .Description = "Duck"},
New Animal With {.CanFly = True, .Description = "Goose!"},
New Human With {.Name = "Elephant Man", .Description = "I am not an animal!"}}
rpItems.DataBind()
End Sub
' Helper function to wrap a single item in a list if it is of the specified type.
Protected Function ListWrap(Of SomeType)(ByVal item As Object) As List(Of Object)
Dim returnList As New List(Of Object)()
If TypeOf item Is SomeType Then
returnList.Add(item)
End If
Return returnList
End Function
</script>
<html>
<head>
<title>Markup Conditions Using Bound Code Block</title>
</head>
<body>
<form id="frmMain" runat="server">
<!-- This is our main data bound control. -->
<asp:Repeater runat="server" ID="rpItems">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%-- This repeater is bound to a list with one or zero animals. --%>
<asp:Repeater runat="server"
DataSource="<%# ListWrap(Of Animal)(Container.DataItem)%>">
<ItemTemplate>
<!-- We use placeholder visibility to use different markup depending on the bound value. -->
<asp:PlaceHolder runat="server" Visible="<%# DirectCast(Container.DataItem, Animal).CanFly%>">
<b>I can fly!</b>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" Visible="<%# Not DirectCast(Container.DataItem, Animal).CanFly %>">
I can't fly.
</asp:PlaceHolder>
<%# HttpUtility.HtmlEncode(DirectCast(Container.DataItem, Animal).Description) %>
</ItemTemplate>
</asp:Repeater>
<%-- This repeater is bound to a list with one or zero humans. --%>
<asp:Repeater runat="server"
DataSource="<%# ListWrap(Of Human)(Container.DataItem)%>">
<ItemTemplate>
<%# HttpUtility.HtmlEncode(DirectCast(Container.DataItem, Human).Name)%>:
"<%# HttpUtility.HtmlEncode(DirectCast(Container.DataItem, Human).Description)%>"
</ItemTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html>When the item is of the incorrect type, the repeater gets bound to an empty list, and the binding code inside of a repeater bound to an empty collection does not get evaluated.
Call JavaScript in an ASP.NET User Control
In ASP.NET it is easy to call a server-side function on a user control during postback. However, you have to do some custom code if you want to call a JavaScript function that resides inside of a user control without performing a postback.
Suppose you have a user control, Greeter, that shows a message to the user. Now, you’d like to initiate that greeting with some JavaScript that is outside of the Greeter control. For our example, we’ll have the Default page call some JavaScript on the click event of an element in the page. That JavaScript will call a JavaScript function within the Greeter control. Here is the control, Greeter.ascx:
<%@ Control Language="vb" %>
<%-- Server-side code. --%>
<script runat="server">
Private _greeterName As String = Nothing
Public ReadOnly Property GreeterName As String
Get
If _greeterName Is Nothing Then
_greeterName = "Greeter_" + Guid.NewGuid.ToString("N")
End If
Return _greeterName
End Get
End Property
</script>
<%-- JavaScript. --%>
<script type="text/javascript">
window["<%= Me.GreeterName %>"] = function () {
var messageId = "<%= divMessage.ClientID %>";
var messageElement = document.getElementById(messageId);
messageElement.style.display = "block";
};
</script>
<%-- Markup. --%>
<div runat="server" id="divMessage" style="display: none;">
Hello
</div>And here is the page, Default.aspx:
<%@ Page Language="vb" %>
<%@ Register Src="~/Greeter.ascx" TagPrefix="people"
TagName="greeter" %><!DOCTYPE html>
<%-- The doctype is on the above line to prevent preceding whitespace,
which some browsers dislike. --%>
<html>
<head>
<title>Greeter Test</title>
</head>
<body>
<%-- Markup. --%>
<div>
<a runat="server" id="aClicker" href="#">Click!</a>
</div>
<people:greeter runat="server" ID="doorman" />
<%-- JavaScript. --%>
<script type="text/javascript">
(function () {
var clickerId = "<%= aClicker.ClientID %>";
var clickerElement = document.getElementById(clickerId);
clickerElement.onclick = function () {
var fnName = "<%= doorman.GreeterName%>";
var fnHandle = window[fnName];
fnHandle();
return false;
};
})();
</script>
</body>
</html>The Greeter control contains a hidden div that contains the message “Hello.” It also defines a function to show that hidden div. That function is given a random name at runtime, and is assigned to the global scope using the window variable. All that you need to do is figure out a way to call that function.
The default page gets the name of the function from a property on the Greeter control. From there, it gets the function from the window variable, then calls the function (when the anchor tag is clicked).
So, the user clicks an anchor tag, which calls a JavaScript function defined on the Default page. That JavaScript function then finds the name of the Greeter JavaScript function, and calls that function. Using this technique, you can more easily decouple your controls so that the markup can be more varied (i.e., the control doesn’t have to know how its JavaScript gets called, it only needs to provide a means to do so).