How to un-GAC ASP.NET MVC RC2

If you are like me you might have developed lots of web applications using different versions of the ASP.NET MVC framework, and might wonder how the latest installations may affect the ability to run.

When upgrading to the latest Release Candidate 2 these old projects will probably build just fine, but there will most likely be some kind of run time error when running locally, like the one I just got and showing below.

aspnet-mvc-breakage

Why the breakage you might wonder and remembering that you been putting those old versions in your bin-folder and they should not be affected. Dylan Bettie gives us the explanation:

The CLR checks the GAC first when resolving assembly references - and if it finds a matching assembly in the GAC, it won't look anywhere else. The ASP.NET MVC previews and beta release all use the same assembly version, culture and public keys, so the CLR has no way of distinguishing between the preview 3 version of System.Web.Mvc and the beta version of the same assembly. They're different DLLs with different file versions, but because the assembly version is the same, the CLR regards them as the same assembly.

So what you need to do is to remove the ASP.NET MVC assemblies from your GAC and your old projects will run against the old ones in their bin.

Luckily I've done this before from the instructions in Dylans post and it's not that hard. Just make sure you backup your system before you do anything because it involves editing the registry which you knows is not always safe. For my safety I have just made a snapshot of my Windows 7 system I got running in WMware Fusion.

Remove the assembly from the registry

Firstly you need to run regedit and find HKEY_CLASSES_ROOT\Installer\Assemblies\Global and remove the key System.Web.Mvc,version="1.0.0.0",culture="neutral", publicKeyToken="31BF3856AD364E35",processorArchitecture="MSIL"-key

aspnet-mvc-regedit-assembly

Un-GAC it

Fire up a CMD prompt and locate your Gacutil.exe. On my Windows 7 system running team edition of Visual Studio 2008 it can be found here. C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin. Then run the command gacutil /u System.Web.Mvc

un-gac-aspnet-mvc

Test your projects

Your old projects made with the previews or betas should now run just fine as they will use the ddl:s you got in their respective bin folder. Mine is running fine as you can see.

code-odyssey-running

By Jesper Lind

UpdatePanel - TinyMCE Demo with project zip-file

TinyMCE is a nice HTML-Editor which has become very popular. It's easy to use and has a lot of configuration possibillities. But when it come to combining it to Ajax and partial updates - it can be a nightmare...

I have now done a proper test and will provide the source code for anybody who is interested, free of use in any way. I've tested this code successfully in IE7, FF2 and Opera.

But now let the source speak for it self, don't miss out on the complete project download at the bottom.

Default.aspx

<%@ Page Language="C#" ValidateRequest="false" Trace="false" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>MS Ajax UpdatePanel - TinyMCE</title>
<script type="text/javascript">
function SaveMyPreciousValues()
{
tinyMCE.triggerSave(false,true);
TextBox1 = document.getElementById('TextBox1');
alert('Check value when posting: '+ TextBox1.value)
}
</script>
</head>
<body>

<form id="form1" runat="server">
<asp:ScriptManager ID="sm" EnablePartialRendering="true" runat="server">
</asp:ScriptManager>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<p>
<asp:Label ID="Label1" runat="server" Text="Welcome to the MS Ajax UpdatePanel - TinyMCE Demo, Enjoy!"></asp:Label>
</p>
<asp:TextBox ID="TextBox1" Rows="10" Columns="50" TextMode="MultiLine" EnableViewState="false" Text="Write something here..." runat="server"></asp:TextBox>

<p>
<asp:Button ID="Button1" runat="server" OnClick="Button1_OnClick" OnClientClick="SaveMyPreciousValues();" Text="Hit me" />
</p>
</ContentTemplate>
</asp:UpdatePanel>

</form>
</body>
</html>

Default.cs.aspx

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
LoadTinyMCE();
}

private void LoadTinyMCE()
{

//Load tinyMCE
HtmlGenericControl Include = new HtmlGenericControl("script");
Include.Attributes.Add("type", "text/javascript");
Include.Attributes.Add("src", "js/tiny_mce/tiny_mce.js");
this.Page.Header.Controls.Add(Include);


//Config MCE
HtmlGenericControl Include2 = new HtmlGenericControl("script");
Include2.Attributes.Add("type", "text/javascript");
Include2.InnerHtml = "tinyMCE.init({mode : 'textareas' ,language : 'sv',entity_encoding : 'raw'});";
this.Page.Header.Controls.Add(Include2);

}

protected void Button1_OnClick(object sender, EventArgs e)
{

//Get the contect of the TextBox
string inputText = Request.Form["TextBox1"];

//Print all Form-values when testing
/*for (int i = 0; i<Request.Form.Count;i++ )
{
string itemName = Request.Form.AllKeys[i];
string itemValue = Request.Form.GetValues(i)[0];
Label1.Text = Label1.Text + "<br />" + itemName + ":" + itemValue;
}*/

Label1.Text = "Content posted from TextBox1: " + inputText;

//Register some javascript to redraw the editor.
//Very important to reset the id-counter to "0", or else strange things will happen..
ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "init", "tinyMCE.idCounter=0;tinyMCE.execCommand('mceAddControl', false, 'TextBox1');", true);
}
}

zip-icon UpdatePanelTinyMCE.zip (C#)

Update: Joakim has rewritten the example to VB.NET, read more on his blog.

By Jesper Lind

More about the bad support for URL-rewrite in ASP.NET

I really love developing on ASP.NET with C# and will definitely continue using this technique from Microsoft. But everything can not be perfect. The greatest shortcoming of the framework is to me that there isn't any good native support for URL-rewriting. I have written a bit about it before.

It's especially in the IIS 6 web server that the limitations exists. In the newer IIS 7 that will be released together with the Longhorn server there will be better solutions to create rules for URL rewrites. But there are some time left until this system will be released, so that doesn't help us right now.

What you can do at the moment is to use ASAPI-filters but that postulates that you are running your own dedicated server or are on a web host that will install it for you. Jeff Atwood at Coding Horror writes more about the two most common ASAPI-solutions for IIS.

One of the greatest critics of the situation is probably Mike Schinkel. This is the guy that started the wiki.welldesignedurls.org and the companion blog which contains a lot of great resources on the subject.

On his personal blog Mike is not holding back on the critizism. In a recent post with the headline "IIS 7.0: Too Little, Too Late?" another Mike (Program Manager för Microsoft’s IIS team) enters the discussion and is expressing his regrets over the bad situation.

The first Mike is continuing in another post to make a list of all the alternative server-techniques and asks his readers which one they recommed he will switch to instead of ASP.NET.

I think it's really good that a lot of developers pays attention to the problem. Microsoft tells us that IIS 7 will not be available for Windows 2003 and that's a real pity. The new techniques are to deep related to the Longhorn system that are saying.

But who knows, after all this begging from developers perhaps Microsoft can spare some resources on it. I would be absolutely wonderful. My tip is to try to do a simpler upgrade to IIS 6 and try to make an implementation of the same URL-rewrite as in the upcoming web server. Name it something like IIS 6.5.

By Jesper Lind

Beautiful URL:s with ASP.NET (we're not there yet)

Some time ago I wrote about how to do URL rewrite with ASP.NET (and about the problems that are involved). Many developers has tried to tackle the problem and I will not go to ddep into the technical stuff this time. I will how ever save a few new links I found on the subject.

First an article that isn't related to ASP.NET but shows how well-designed urls should look like.

Then an link to an Wiki completely dedicated to well designed urls, where you can read "ASP.NET - Well Designed Urls Wiki".

My conclusion is that it's probably smartest to wait until IIS 7 is released. Unfortunatly it doen't seems like we will get this web server for Windows 2003. We will probably have to wait for the new Longhorn server.

IIS 7.0 will have much better support for URL-rewrite as you can read on Scott Guthrie's blog:

Several people have asked why the built-in URL Mapper in ASP.NET 2.0 doesn't support regular expressions. There were actually a few reasons for this -- one of the big ones being that just about the time we were about to consider adding it my team started also working on IIS7. We realized that a full-featured version would want/need to take advantage of some of the new features in IIS7 as well as the support all content types (in particular -- images and directories). So we postponed making it feature rich until a future version.

I am rather happy that I havn't started to try to rewrite URLs with IIS 6 yet, especially when I read reports as "Making URL rewriting on IIS 7 work like IIS 6".

The question is if one really can wait. To have nicely formatted URLs is really tempting, especially from an SEO-perspective. But if you are going to use one of this tecniques just bear in mind that you might have to redo everything once IIS 7 is released.

If you want to have some thought from someone who has started using URL-rewrite with IIS 7 on Vista, you can read Dennis blog.

By Jesper Lind

A class that generates passwords

This is an example of a class that generates passwords. I have used it for so long that i forgot where I found it originally. If you recognize the code, please let me know the origin and I will add a reference.
using System; using System.Data; using System.Configuration; using System.Web; using System.Text; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; /// /// Summary description for PasswordGenerator /// public class PasswordGenerator : Page { private char[] characterArray; private Int32 passwordLength = 10; Random randNum = new Random(); public PasswordGenerator() { characterArray = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray(); } private char GetRandomCharacter() { return this.characterArray[(int)((this.characterArray.GetUpperBound(0) + 1) * randNum.NextDouble())]; } public string Generate() { StringBuilder sb = new StringBuilder(); sb.Capacity = passwordLength; for (int count = 0; count <= passwordLength - 1; count++) { sb.Append(GetRandomCharacter()); } if ((sb != null)) { return sb.ToString(); } return string.Empty; } }
By Jesper Lind

Troubleshooting: A potentially dangerous Request.Form value was detected from the client

This is an error which is caused by posting html-code in a textbox. The text doesn't need to contain valid HTML, just anything with opening and closing angled brackets ("<...>").

The complete error:

Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. This value may indicate an attempt to compromise the security of your application, such as a cross-site scripting attack. You can disable request validation by setting validateRequest=false in the Page directive or in the configuration section. However, it is strongly recommended that your application explicitly check all inputs in this case.

Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (ctl00$mainContentPH$fvFaq$tbFaqBody_sv-SE="...the link <a href="http://www....").

Solution
There are two ways to disable request validation.

1. Turn it off in the Web.config file

<system.web>
<pages ValidateRequest="false"/>
</system.web>

2. Turn it off on the page it self

<%@ Page ValidateRequest="false" ... %>

A warning for injection
The validation is there for a reason. If you turn it off, visitors can post code like this, and that's not wanted in most cases.

alert('I am posting some dangerous code')

More info on the web site of Brian Cryer.

By Jesper Lind

Procedure ... expects parameter ... which was not supplied : ADO.NET Error

I had some problems with figuring out the cause about this error.

Procedure <procedure name> expects parameter <parameter name>, which was not supplied : ADO.NET Error

At last I found the solution on Data Mining Developers.

Example of the problem

string ColumnName = null;
//error will be thrown if the variabe ColumnName is null
if(ColumnName ==null)
ColumnName=string.Empty;
SqlParameter param = new SqlParameter("@ColumnName", SqlDbType.NVarChar, 100);
param.Value = ColumnName;
cmd.Parameters.Add(param);
cmd.Execute();

By Jesper Lind

Get currency rates using Web Service

Update: The web service used in this example is not availible any more.

I was inspired by an article about currency conversion on Code Project when I made my own example. Please read the article in the link below to find out how to add an Web Service to your project. I am using a Web Service from xmethods.net.

<%@ Page Language="C#" Trace="true" validateRequest="false" EnableSessionState="True" EnableViewState="true" SmartNavigation="false"%>
<script Language="c#" runat="server">
protected void Page_Load(object sender, EventArgs e)
{
try
{
Rate_WS.CurrencyExchangeService to_currency = new Rate_WS.CurrencyExchangeService();
float Euro_Dollar = to_currency.getRate("euro", "united states");
float Dollar_Sek = to_currency.getRate("united states", "sweden");
float Euro_Sek = to_currency.getRate("euro", "sweden");
float Sek_Yen = to_currency.getRate("sweden", "japan");

lblEuro_Sek.Text = Euro_Sek.ToString();
lblDollar_Sek.Text = Dollar_Sek.ToString();
lblEuro_Dollar.Text = Euro_Dollar.ToString();
lblSek_Yen.Text = Sek_Yen.ToString();
}
catch (Exception) { }
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Currency converter in ASP.NET</title>
<link rel="stylesheet" href="../example.css" type="text/css" />

</head>

<body>
<div id="content">
<b>Currency example using web service</b>
<br /><br />

1 US Dollar = <asp:Label ID="lblDollar_Sek" runat="server" /> SEK
<br /><br />
1 Euro = <asp:Label ID="lblEuro_Sek" runat="server" /> SEK
<br /><br />
1 Euro = <asp:Label ID="lblEuro_Dollar" runat="server" /> US Dollar
<br /><br />
1 SEK = <asp:Label ID="lblSek_Yen" runat="server" /> Yen

</div>
</body>
</html>

By Jesper Lind

Create a RSS-feed

RSS is getting popular and is a great way to let the users subscribe to the content of your web site. This is how you create an feed in Asp.Net.

//Funktion som skapar RSS flöde
protected void GenerateRss()
{
try
{

//Fysisk sökväg på servern (Byt ut mot den på din server)
string strXMLPath = "C:/ . . . /rss.xml";

FileStream objFileStream = new FileStream(strXMLPath,FileMode.Create);
XmlTextWriter xtw = new XmlTextWriter(objFileStream,System.Text.Encoding.GetEncoding("iso-8859-1"));
xtw.Formatting = Formatting.Indented;
xtw.WriteStartDocument();

//skriv ut <rss version="2.0">
xtw.WriteStartElement("rss");
xtw.WriteAttributeString("version","2.0");

//skriv ut <channel>
xtw.WriteStartElement("channel");

//skriv ut element som tillhör <channel>
xtw.WriteElementString("title","Codeodyssey.se");
xtw.WriteElementString("link","http://www.codeodyssey.se/");
xtw.WriteElementString("description","Code Odyssey - expanderar webben");
xtw.WriteElementString("language","sv-SE");
xtw.WriteElementString("copyright","Copyright (c) 2004-2006 Code Odyssey");

OleDbConnection conn = new OleDbConnection (strConn);
bool boolPermission = false;
OleDbDataReader objDataReader=null;
try
{
string strSQL = "SELECT Blog.Id, Blog.Title, Blog.Body, Blog.PublishDate FROM Blog ORDER BY Blog.PublishDate DESC";

conn.Open();

OleDbCommand objCommand = new OleDbCommand(strSQL, conn);
objDataReader = objCommand.ExecuteReader();
while (objDataReader.Read() == true)
{
int Id = Convert.ToInt32(objDataReader["Id"]);
string Title = Convert.ToString(objDataReader["Title"]);
string Body= Convert.ToString(objDataReader["Body"]);
//Se till att datum följer RFC-822 standard
string PublishDate = Convert.ToString( ((DateTime)objDataReader["PublishDate"]).ToString("r"));


//skriv ut <item> och dess innehåll
xtw.WriteStartElement("item");
xtw.WriteElementString("title",Title);
xtw.WriteElementString("link","http://www." + strUrl.ToLower() + "/Blog.aspx?id=" + Id);
xtw.WriteElementString("guid","http://www." + strUrl.ToLower() + "/Blog.aspx?id=" + Id);
xtw.WriteElementString("description",Body);
xtw.WriteElementString("pubDate",PublishDate);
xtw.WriteEndElement();
}
objCommand.Dispose();
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
finally
{
if(objDataReader!=null)
{
objDataReader.Close();  
}
onn.Close();
}

//skriv ut </channel>
xtw.WriteEndElement();

//skriv ut </rss>
xtw.WriteEndElement();

//Stäng xml skrivaren
xtw.Close();
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
}

This is how to add the icon in the browser.

<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="xml/rss.xml" />

This is how to add such a link from the code behind:

//Add RSS link HtmlLink link = new HtmlLink();
link.Attributes.Add("type", "application/rss+xml");
link.Attributes.Add("rel", "alternate");
link.Attributes.Add("href", "feed/rss.xml");
this.Page.Header.Controls.Add(link);

By Jesper Lind