Subscribe

Archive for ASP.NET:

Make Forms Authentication work in IIS 7

When experiencing Forms Authentication problems in IIS 7, step through this list to make sure everythings in place for Forms Authentication to work:

  1. Make sure Forms Authentication is enabled for your website in IIS.
    In IIS 7, browse to your website, go to Authentication and make sure Forms Authentication is set to Enabled, like this:

    Forms Authentication set to enabled in IIS 7

  2. Make sure your Web.Config settings looks something like this:

    <authentication mode="Forms">
    	<forms name="aspxFormsAuth" defaultUrl="/Admin"
    		   loginUrl="/Admin/Signin.aspx" protection="All" timeout="90" />
    </authentication>

    Also, make sure you've not missed the location element:

    <location path="admin">
    	<system.web>
    		<authorization>
    			<deny users="?"/>
    		</authorization>
    	</system.web>
    </location>
  3. Make sure <modules> in <system.webServer> has the runAllManagedModulesForAllRequests attribute set to true:

    <system.webServer>
    	<modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>

    If you got the 403.14 error, this might solve it.

  4. Finally, you could try the ordinary iisreset or aspnet_regiis -i command. Make sure you run aspnet_regiis -i on c:\Windows\Microsoft.NET\Framework\v4.0.30319 (or Framework64 if you're running a 64 bit OS).

How to Keep Visual Studio Debugging Alive

If you, like me, like to take a deep plunge into Visual Studio debugging, you might've encountered the dreaded Web server process termination error, "The web server process that was being debugged has been terminated by Internet Information Services":

Visual Studio web server process termination during debugging

It's very irritating when you're in the middle of a debugging session and it's stopped by the error message above. But - there's a solution! As the error message tells us, you can configure application pool settings in IIS.

This is how to do make sure you'll be able to debug forever:

  1. Pop up your IIS and find the correct Application Pool
  2. Right click and choose Advanced Settings
  3. Below Process Model, find Ping Enabled and make sure it says False:
    Disable ping for application pool in IIS 7
  4. Done!
If you have trouble finding the correct application pool, have a look at resolving w3wp processes by Daniel Berg. It'll help!

How to solve unknown server tag 'asp:ListView'

Recently I got this error message, basically telling me I was using an unknown server control. In this case, the ListView control. First thing that comes to mind is if the control itself exists in .NET 3.5, which I was using. Of course it does!

Next thing, I was reading about the solution to this being to completely reinstall .NET Framework 3.5 and .NET Framework 3.5 SP1.

However, I solved it by adding two lines to the Web.Config controls element instead, saving me a lot of time.

Here's the code:

<pages>
  <controls>
	  <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
	  <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  </controls>
</pages>

ASP.NET and improving web standards

Developers often ask me what they can do to improve web standards on their ASP.NET website. There are a number of tricks available and I thought I'd share them with you.

Web.Config magic

First thing to do, is to make sure you've got your Web.Config ready for web standards. This is really simple, as there's only some copy and paste needed. What you want to do is setting xhtmlConformance mode to Strict and make use of browserCaps, both in the system.web section, like this:

<system.web>
<xhtmlConformance mode="Strict" />
<browserCaps>
  <case match="W3C_Validator*">
    TagWriter = System.Web.UI.HtmlTextWriter
    W3CDomVersion = 1.0
  </case>
</browserCaps>

....
</system.web>

Use the best .NET controls at your disposal

Countless of times you see .NET controls such as Label and Panel used. Not good, since both render extra HTML output. A label renders an extra span and a Panel renders an extra div, thus affecting the markup of the website - and at worst even breaking the layout.

To the rescue, comes the Literal and PlaceHolder controls. The Literal and PlaceHolder don't render extra markup, and I've never ran into a single problem using them instead.

Also, I like to use the Repeater as often as I can, since I don't always trust third party controls.

Set CSS class on the first listing item

You might have seen class="first" set on the first item in a listing, a number of times. For some, this is a pain to address. However, nothing could be easier than setting a specific CSS class on the first item in a listing. You just have to use the onItemDataBound event on your control. Here's how it might look:

<asp:Repeater ID="rptListing" OnItemDataBound="cssAddons" runat="server">
<ItemTemplate>
	<li<asp:Literal ID="cssClass" Visible="false" runat="server"> class="first"</asp:Literal>>
		<%#Eval("Item") %>
	</li>
</ItemTemplate>
</asp:Repeater>

And the codebehind:

protected void cssAddons(object sender, RepeaterItemEventArgs e)
{
	ListItemType type = e.Item.ItemType;

	if (type == ListItemType.Item)
	{
		if (e.Item.ItemIndex == 0)
		{
			Literal litCssClass = (Literal)e.Item.FindControl("cssClass");
			if (litCssClass != null) litCssClass.Visible = true;
		}
	}
}

You should never be forced to rebuild a project when doing layout changes - that's why one would prefer to use a hidden Literal with the CSS class in the ItemTemplate, and toggling the visibility if it's the first item in a listing.

Customized web controls and CompositeControl

A lot of you are perhaps writing your own web controls. Take note though, inheriting from CompositeControl will make your web controls render an extra span. There's a simple solution to this - just override the Render method in your control, like this, and you're set:

protected override void Render(HtmlTextWriter writer)
{
	RenderContents(writer);
}

Some reminders - naming conventions and id's

When it comes to ASP.NET and naming web controls, things can get messy. You want to name your controls as short as possible, without making the name totally meaningless. You particularly want to name your ContentPlaceHolders in a smart way, to avoid id's like this:

ctl00_ContentPlaceHolderContent_ContentPlaceHolderMain_ContentPlaceHolderWidePageWithoutTopImage_ContentPlaceHolderWidePage_ContentPlaceHolderPageContent_ButtonSend

I regularly prefix my web controls, rpt for Repeater, cph for ContentPlaceHolders and so on.

Another problem in ASP.NET Web Forms is id's. If you use runat="server" with a HTML element, the id might look like in the example above. You must avoid this as much as you can, since the altered id's might break the layout. Some might say you should use CSS classes instead, but that's not the way to go. CSS classes aren't meant to be used instead of id's.

In ASP.NET 4, you can actually choose how your id's are rendered, through the ClientIdMode property. A welcome change!

More reading

Remember this is aimed at ASP.NET Web Forms websites, even though part of the tricks can be used in an MVC environment too!

Add controls and namespaces to Web.Config for easier maintenance

Very often you add a namespace or register an assembly on top of an ASP.NET page, like this:

<%@ Page Language="C#"
	AutoEventWireup="True"
	CodeBehind="Default.aspx.cs"
	Inherits="ProjectName._Default" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="ProjectName.Classes" %>
<%@ Register Assembly="ProjectName" Namespace="ProjectName.Controls" TagPrefix="cc" %>

It works to do once or twice, but when you need to add these namespaces and controls on several different pages, it quickly becomes maintenance hell.

What to do? Use Web.Config instead.

You just have to declare your namespaces and controls in the system.web section, like this:

<system.web>
	<pages>
		<namespaces>
			<add namespace="System.IO" />
			<add namespace="ProjectName.Classes" />
		</namespaces>
		<controls>
			<add assembly="ProjectName" namespace="ProjectName.Controls" TagPrefix="PN" />
		</controls>
	</pages>
</system.web>

Then you will be able to write code like

<%=Toolbox.FormatHtml("....") %>

instead of code like

<%=ProjectName.Classes.Toolbox.FormatHtml("....") %>

A clear improvement. You also won't need to register your controls everywhere to use them.

If you haven't been using this feature (it already came in ASP.NET 2.0!) it's time now!

How to add a control to a StringBuilder

When you want to put together a number of strings in ASP.NET, the StringBuilder is very handy. Instead of using concatenation, StringBuilder both looks better and improves performance. You can simply append a set of strings to the StringBuilder and return it, like this:

public static string BuildNumbers()
{
	StringBuilder sb = new StringBuilder();
		sb.Append("<ul>");
	
		for (int i=0; i<500; i++)
		{
			sb.Append(string.Format("<li>{0}</li>",i));
		}

		sb.Append("</ul>");

	return sb.ToString();
}

However, sometimes you might want to add a web control to the StringBuilder. A bit more tricky.

What you want to do, is to dynamically create the control and use StringWriter together with HtmlTextWriter to render the control inside the StringBuilder. Like this, when you want a LinkButton:

public static string BuildNumbers()
{
	StringBuilder sb = new StringBuilder();
		sb.Append("<ul>");
	
		for (int i=0; i<500; i++)
		{
			sb.Append(string.Format("<li>{0}</li>",i));
		}

		LinkButton lnkBtn = new LinkButton();
			lnkBtn.ID = "lnkBtnSubmit";
			lnkBtn.Text = "Submit";

		using (StringWriter sw = new StringWriter(sb))
		{
			using (HtmlTextWriter tw = new HtmlTextWriter(sw))
			{
				lnkBtn.RenderControl(tw);
			}
		}
	
	sb.Append("</ul>");

	return sb.ToString();
}

How to install .NET developer tools on Windows 7

I ran into problems with IIS and ASP.NET after I installed Windows 7, so I thought I'd share my then successful installation process with you.

Clean install of Win 7

First of all, a clean installation of Windows 7 is preferred. I recommend you this because it's otherwise possible you encounter a strange problem which has to do with an upgrade.

A clean installation of Windows 7 will always minimize your problems, plus it's the best start you can get.

First instructions

To minimize upcoming problems, the best thing to do is to install the .NET developer tools before you install anything else.

Make sure you install these tools before anything else and your installation will probably as smooth as anything.

My successful installation process went like this:

  1. Enable IIS and ASP.NET
  2. Install SQL Server 2008 + Management Studio (plus ASP.NET MVC)
  3. Install Visual Studio 2008 + Service Pack 1

Enable IIS and ASP.NET

After the installation of Windows 7 is done, it's first time for IIS and ASP.NET.

You'll have to enable these features through Windows Features which is located under Programs and Features in the Control Panel.

In the Windows Features window, make sure the following options are ticked:

  • Internet Information Services (you can also activate IIS 6 under Web Management Tools->IIS 6 Management Compatibility)
  • ASP.NET (under World Wide Web Services->Application Development Features)

Turning on IIS and ASP.NET in Windows Features

Use Web Platform Installer to install SQL Server and ASP.NET MVC

Microsoft Web Platform Installer is an awesome tool which will help you install programs, modules and much more related to .NET development. Use Web Platform Installer to install the following:

  • SQL Server 2008 + SP1
  • SQL Server Management Studio Express
  • ASP.NET MVC

Once you've downloaded and installed Web Platform Installer, activate the features under the Web Platform tab:

Microsoft Web Platform Installer, the Web Platform tab

The installer will automatically download and install all your selected features. Gone are the days with meaningless steps in the SQL Server installation process!

Mind, you can also choose to install a whole lot of other features, but I recommend you to save them for later.

Install Visual Studio 2008 + SP1

Final step is to install Visual Studio 2008 and Service Pack 1.

Once this is done, you should be set and everything should be fine.

If problems occur

If you encounter any problems, it's always a good shot to use your search engine to find anything related to the problem.

I tried a lot of different solutions though and no solution helped me - a clean installation and the above installation flow solved my problems.

Twitter module in ASP.NET for download

If you've been looking for an ASP.NET Twitter module, look no further. I've coded a C# module in order to consume a given Twitter feed. Download the Twitter module for easy use in your own project.

How to use

You can either show the latest Twitter message or any given number of Twitter messages with this module - all you have to do is to point out a Twitter username and the number of messages to show.

Here's a code example on how you can show 5 Twitter messages in a Repeater.

Code-behind:

string userName = "dileno";

List<TwitterFeed> messages = TwitterFeed.Fetch(userName, 5);

if (messages.Count>0)
{
rptTwitterMessages.DataSource = messages;
rptTwitterMessages.DataBind();
}

Repeater in code-front (aspx/ascx):

<asp:Repeater ID="rptTwitterMessages" runat="server">
<HeaderTemplate><ul></HeaderTemplate>
<FooterTemplate></ul></FooterTemplate>
<ItemTemplate><li><%#((TwitterFeed)Container.DataItem).Message %> (<a href="<%#((TwitterFeed)Container.DataItem).Link %>"><%#((TwitterFeed)Container.DataItem).PubDate %></a>)</li></ItemTemplate>
</asp:Repeater>

Download the Twitter module

You can download the C# module with complete source code and code examples:

Download Twitter module (zip, 16 kB)

Short instructions for implementation

  • Drop the TwitterFeed.cs file into your project.
  • Use the code in Default.aspx.cs to customize the Twitter messages.
  • Update your appSettings.Config with the key TwitterFeedUrl, which you find in this project's appSettings.Config file.

Dealing with different website and database locales

Using different locales

When I developed this blog, I wanted to use the en-GB locale to be able to present correct formats for dates and numbers.

It is simple to set a specific locale for a whole web application - you just have to add the <globalization> tag under <system.web> in Web.Config and set the culture and uiCulture attributes, like this:

<globalization culture="en-gb" uiCulture="en-gb"/>

So far - so good. Dates and numbers have the correct format and everything looks well - until in comes the database.

I use Sweden's best web hosting provider (according to a study published in 2009) and this means the SQL Server database's collation is set to Finnish_Swedish_CI_AS - as it should be.

Having a website and a database with different locales gives you problems. Trust me.

Out-of-range datetime value

The main problem I ran into was a database insert of an incorrect date - the date I tried to insert obviously had an en-GB format while my database expected a date with sv-SE format. This generated an out-of-range datetime value error.

At first, I tried rewriting the date to a correct format, but quickly realized it was wrong to do so. I ended up with one of the two correct solutions for this problem.

Solutions

The two solutions are:

  • Update database collation to match your website locale
  • Update SQL query to use parameters

I ended up with the latter one - updating my SQL query to use paremeters instead.

This is also how you want to insert and update your database tables - by using parameters with your command object (unless you use any ORM solution like NHibernate, but that's another blog post).

Here's a SQL query where parameters are used (disregard the lousy error handling):

string strSQL = "INSERT INTO mytable(user,password) VALUES(@user,@password)";

SqlConnection objConn = new SqlConnection(connString);
SqlCommand objCmd = new SqlCommand(strSQL, objConn);

objCmd.Parameters.AddWithValue("@user", "username");
objCmd.Parameters.AddWithValue("@password", "secretpassword");

try
{
objConn.Open();
objCmd.ExecuteNonQuery();
}
catch { }
finally
{
objConn.Close();
}

Conclusion

When developing a database driven website, make sure you know the website's locale and the database's collation. Also, use parameters with your SQL queries, not only when dealing with dates and numbers, but always. You don't know what input might try to sneak into the database otherwise.

Improve performance by using explicit cast instead of DataBinder.Eval

The DataBinder.Eval method is often used when you want to bind data to a control's template. What DataBinder.Eval really does is to cast Container.DataItem to its specific type, like this:

<%# DataBinder.Eval(Container.DataItem, "Heading") %>

DataBinder.Eval uses .NET reflection in order to cast Container.DataItem to its specific type. The use of reflection in this method will give you a performance loss.

If performance is of importance in your application or if you know what type Container.DataItem is, it's better to use an explicit cast instead:

<%# ((DbDataRecord)Container.DataItem)["Heading"] %>

To the top