Complete Dump of Asp.net WebRequest

Alternate way of dumping logs
Here’s a simple but very handy method that lists out all relevant data for a Asp.net web request. Posted Parameters, Query String, Http Headers, Cookies and Session variables are returned – and can be logged out to file/console etc.
Note that this static method can be called anywhere from your code – it does not have to be inside a aspx/ashx etc. The only requirement is that the code must run inside IIS and a web request must be assosiated with the current thread.
public static string DumpRequest() { StringBuilder sb = new StringBuilder(); sb.AppendLine(""); sb.AppendLine("------------- PostedParameters --------------"); foreach (string key in HttpContext.Current.Request.Form.Keys.Cast<string>().OrderBy(f => f)) { sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Params[key]); } sb.AppendLine(""); sb.AppendLine("------------- Query String ------------------"); foreach (string key in HttpContext.Current.Request.QueryString.Keys.Cast<string>().OrderBy(f => f)) { sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.QueryString[key]); } sb.AppendLine(""); sb.AppendLine("------------- Http Headers -------------------"); foreach (string key in HttpContext.Current.Request.Headers.Keys.Cast<string>().OrderBy(f => f)) { sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Headers[key]); } sb.AppendLine(""); sb.AppendLine("-------------- Cookies -------------------------"); foreach (string key in HttpContext.Current.Request.Cookies.Keys.Cast<string>().OrderBy(f => f)) { sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Cookies[key].Value + " - ExpireDate: " + HttpContext.Current.Request.Cookies[key].Expires); } sb.AppendLine(""); sb.AppendLine("--------------- Session ------------------------"); foreach (string key in HttpContext.Current.Session.Keys.Cast<string>().OrderBy(f => f)) { sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Session[key]); } return sb.ToString(); }
The result looks like this::
----------------------------------------- PostedParameters -----------------------------------------
----------------------------------------- Query String ---------------------------------------------
username : ted@example.com
----------------------------------------- Http Headers ---------------------------------------------
Accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset : ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding : gzip,deflate,sdch
Accept-Language : en-US,en;q=0.8
Cache-Control : max-age=0
Connection : keep-alive
Cookie : timeOffset=-120; gs_u=1746198188:22843:26224:1320393450549; LANG=en; USER=a33f8…
Host : dev.filemail.com
User-Agent : Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome..
----------------------------------------- Cookies --------------------------------------------------
__utma : 155161261.1943841533.1313506820.1324476330.1325070578.60 - ExpireDate: 01.01.0001 00:00:00
__utma : 155161261.1943841533.1313506820.1324476330.1325070578.60 - ExpireDate: 01.01.0001 00:00:00
__utmc : 260895642 - ExpireDate: 01.01.0001 00:00:00
__utmz : 155161261.1313506820.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) - ExpireDate:
__utmz : 155161261.1313506820.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) - ExpireDate:
ASP.NET_SessionId : a2xlln05ibzzd2ajywhpizc0 - ExpireDate: 01.01.0001 00:00:00
gs_u : 1746198188:22843:26224:1320393450549 - ExpireDate: 01.01.0001 00:00:00
LANG : en - ExpireDate: 01.01.0001 00:00:00
timeOffset : -120 - ExpireDate: 01.01.0001 00:00:00
USER : a33f8a58568f430e8a0d48115ac7b13c - ExpireDate: 01.01.0001 00:00:00
----------------------------------------- Session --------------------------------------------------
- : -
UserObject :
WebClient // HttpWebResponse – Problems with Chunked Transfer encoding
Doing a HTTP POST to a webserver using C# is pretty easy using the System.Net.HttpWebRequest. However - if you need to retrieve the answer/reply from the webserver - you'll often get an exception:
Exception: 'Unable to read data from the transport connection: The connection was closed.'
When looking at the HttpWebResponse in the debugger - the length of the response is -1, so something strange is going on here.
When investigating further in the VS 2010 debugger/ Fiddler, I found out that the webserver (IIS 7 in this case) is sending the response using Transfer-Encoding: Chunked - which is relatively common in HTTP 1.1. It means that the length of the message isn't specified in the HTTP Header Content-Length, but in the message itself.
Nothing wrong with this - but apparently HTTPWebResponse does not support Chunked Transfer Encoding (and thereby not HTTP 1.1).
The easiest way to fix this is to make sure the HttpWebRequest is sent using HTTP 1.0 - this way the server will reply with a HTTP Header specifying Content-Length.
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("http://www.degree.no");
wr.ProtocolVersion = Version.Parse("1.0");
An easier/alternative way of doing HTTP Communication in the .NET framework is the System.Net.WebClient class. But since it uses HttpWebRequest under its hood, the same problem occurs here.
There is no way (afaik) to specify WebClient to use HTTP 1.0 - so use HttpWebRequest with HTTP 1.0 if you need to POST something to a server and read the response.
ImageGen resize functionality for free!

ImageGen is a great little .NET library that basically resizes images on the fly. The typical use of it is on websides, blogs etc - where a image is resized just before sending it to the browser. It is often used in Umbraco CMS sites, but it can be used just as easily in any Asp.net site.
Here's an example:
http://server.degree.no/media/39263/untitled-19.png (original image)

http://server.degree.no/umbraco/ImageGen.aspx?image=/media/39263/untitled-19.png&width=150 (resized by ImageGen)

It is often very useful to resize a image to a height of e.g. 60 pixels while also ensuring that the width should not be greater than e.g. 200px.
ImageGen offers this in its PRO version:

This feature is the only true useful feature of the PRO version ($199 per domain!) I have ever had use for. Here's a trick to achieve maxHeight / maxWidth functionality with the free version:
http://server.degree.no/umbraco/ImageGen.aspx?image=/media/39263/untitled-19.png&width=150&height=50&constrain=true
This resizes the image to a width of max 150px, height of max 50px, while preserving the aspect ratio.
Happy resizing!
Configuring Log4net from code!

Photo: A more traditional way of logging.
The first thing I do when creating a new .NET website/app is to add Log4net. I usually find some old code, and
- copy the log4net.dll,
- copy the log4net.config
- copy the c# code that loads the config file
For a lot of the smaller projects/solutions I am working on - there is no need at all to change log levels / appenders etc. during run time - so I configure log4net directly from my c# code. This means that I can drop the log4net.config file.
Here is a piece of code that creates a simple FileAppender. It can easily be modified to handle RollingFileAppenders etc..
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.RemoveAllAppenders(); /*Remove any other appenders*/
FileAppender fileAppender = new FileAppender();
fileAppender.AppendToFile = true;
fileAppender.LockingModel = new FileAppender.MinimalLock();
fileAppender.File = Server.MapPath("/") + "log.txt";
PatternLayout pl = new PatternLayout();
pl.ConversionPattern = "%d [%2%t] %-5p [%-10c] %m%n%n";
pl.ActivateOptions();
fileAppender.Layout = pl;
fileAppender.ActivateOptions();
log4net.Config.BasicConfigurator.Configure(fileAppender);
//Test logger
ILog log =LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
log.Debug("Testing!");
The result of the log test is:
2010-11-13 14:52:46,611 [20] DEBUG [_Default ] Testing!
A good place to put this code is in the entrypoint of your App (the Main(string[] args) method), or in the Global.asax if you are creating a web app (remember to grant the NETWORK SERVICE user write access to the folder you are logging to).
Happy logging!
-N
Upgrading Umbraco from 4.5.1 to 4.5.2

Umbraco is a Content Management System (CMS) developed in Microsoft .NET.
Some of its advantages is that it offers full design freedom, it's free to use, and perhaps most importantly - you can write your own user controls using the allmighty .NET Framework. A disadvantage with Umbraco (and a lof of other open-source solutions) is the hassle with upgrading to newer versions.

When attempting to upgrade a Umbraco 4.5.1 to 4.5.2 I followed this generic upgrade guide - which basically told me to overwrite some files and folder.The first thing I did was to do a full backup of the site (files + MS SQL database). Then, I copied the files, and opened the site in my browser.
A upgrade page was displayed - so far so good. I finished the different steps in the guide - it told me the upgrade had gone perfect!I tried to enter the site again to make sure the content was being displayed ok. But I was redirected to the Upgrade page again...where I tried to log in..
Problem: Admin can not log in after upgrading Umbraco
Possible Cause: Earlier versions of Umbraco handled password in clear text, current version uses hashing.
Possible Solution: Open web.config file - remove the passwordFormat="Hashed"
<add name="UsersMembershipProvider" type="umbraco.providers.UsersMembershipProvider" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
Problem: Site is not displayed at all after upgrade
Possible Cause: Upgrade bug?
Possible Solution: Log into Admin and republish entire site

Problem: XSLT is not working at all/behaving weird after upgrade
Possible Cause: New XSLT Schema! Data elements with Alias Attributes are no longer used!
Possible Solution 1: Set <UseLegacyXmlSchema>true</UseLegacyXmlSchema> in config/umbracoSettings.config
Possible Solution 2 (better): Replace XSLT code looking like this
$currentPage/descendant-or-self::node[string(data[@alias='umbracoNaviHide']) != '1']
with this
$currentPage/descendant-or-self::*[umbracoNaviHide != '1']
Tip: If you are unsure what the data(document/node) that you are trying to process with XSLT looks like - then insert this:
<textbox><xsl:copy-of select="$currentPage"/></textbox>
Problem: Umbraco installation contains different sites (hostnames), but only one of them works after upgrade
Possible Cause: Wrong setting in config/umbraco.config which got owerwritten during upgrade
Possible Solution: Set <ensureUniqueNaming>True</ensureUniqueNaming> in config/umbracoSettings.config
Thats about it I think - good luck upgrading!
ASP.NET Large file uploads using FileUpload controller
If you are using a FileUploader component on your webpage you will soon realize the ~4MB limit, which triggers an ugly exception for users that attempt to transfer files larger than that.
Before you start implementing a bit stream functionality or splitting up the files client side (which in some cases sure would be a good solution) at least consider if the easy way will work for you. There is a default 4MB limit set in the machine.config file, which like most other settings can be overridden by the application web.config (and therefore also web.config for sub folders). Add the following line to the system.web tag:
<system.web>
<!-- increate the max upload limit to 20MB -->
<httpRuntime executionTimeout="240" maxRequestLength="20480" />
</system.web>
Be aware that the upload limit is there for a reason.. One possibility is denial of service attacks using large files to choke your server, so use this with some caution.
PS: It would be unethical of me not to mention another option if you want to transfer large files: use Filemail.com ! Their business IS large file transfers – be sure to check it out!
ASP.NET MVC 3 Beta
ASP.NET MVC 3 Beta was released earlier this month. I tried to install it through the Web Platform Installer, but got the message: "The product you are trying to install is not supported on your operating system". I run Windows 7 32 bit and that is of course supported. The solution is to download the installation files from this web site.
If you encounter the message: "This product requires Microsoft ASP.NET Web Pages 1.0. Please install the missing component, then try to install this product again." when running the MVC 3 beta installation, go back to the same website and download the AspNetWebPages.msi file and install this first.
Alvorlig sikkerhetshull i Asp.net
Microsoft annonserte for under en uke siden at det er oppdaget et relativt alvorlig sikkerhetshull i Asp.net / IIS som gjør at private filer som f.eks. web.config kan lastes ned. I disse filene ligger det ofte sensitiv informasjon som brukernavn / passord til databaser osv - så dette kan potensielt få store konsekvenser.
Inntil Microsoft lanserer en patch via Windows Update, anbefales det å slå på CustomErrors i Web.Config - som forhindrer angriperen i å bryte seg inn.
Se Scott Guthries blogg for detaljer:
http://weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx
Microsoft IIS innstillinger og Asp.net session timeout
Her om dagen fikk jeg en forespørsel som i all enkelhet gikk ut på å justere Session Timeout for en ASP.NET webside. Denne instillingen spesifiserer bl.a. hvor lenge en nettleser kan stå innlogget på en webside før man blir logget ut. Har gjort dette mange ganger før, så burde gå som fot i hose.
Jeg gikk inn i web.config og endret session timeout verdien til 120 (minutter).
<sessionState cookieless="UseCookies" mode="InProc" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" stateConnectionString="tcpip=127.0.0.1:42424" timeout="120" />

Så gikk jeg inn i login siden og justerte loginTicket'en der til også å vare i 120 minutter (websiden bruker forms authentication).
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(“authTicketName”, false, 120); //120 minutes timeout.
Dermed burde alt være i skjønneste orden. Jeg logget inn på websida, surfet rundt litt.. og gikk til lunch. Når jeg kom tilbake 30 minutter senere prøvde jeg å surfe videre.. men ble redirected til loginsiden med en gang. Jeg var altså blitt logget ut.. etter ca 30 minutter.. what?
Etter å ta tenkt meg litt om (aka. googlet) fant jeg ut at årsaken til dette ligger i webserveren - Microsoft IIS 7. I App Pool'en her er det nemlig spesifisert at webserver prosessen skal avsluttes etter 20 minutters inaktivitet. Så mens jeg var midt i karbonadene døde prosessen.. og tok med seg session'en (og authticket'en) i dragsuget. Etter å ha endret denne verdien til 120 fungerer det som forventet.
På en webside med flere besøkende, så vil w3wp.exe prosessen sjelden/aldri stå på tomgang i 20 minutter.. slik at man ikke trenger å konfigurere dette i IIS. Men har du en webside med begrenset trafikk så bør Idle Time-out verdien justeres til Session sin timeout verdi (eller større).
Forskjellige nettlesere behandler et enter-trykk på forskjellige måter avhengig av antall tekstbokser og antall knapper på siden. Dette gjør at vi må styre hvilke knapp som skal behandle et enter-trykk i web applikasjonen. Løsninger som å disable enter knappen med et javascript kan få uheldige konsekvenser som f.eks i en Text Area komponent hvor linjeskift ikke vil virke lenger.