Showing posts with label ASP. Show all posts
Showing posts with label ASP. Show all posts

Wednesday, 28 January 2009

Getting to grips with EPiServer

A week ago I was in London for a 3 day training course for EPiServer CMS.

I really enjoyed the course and learning about the CMS, it looks like EPiServer could be one of the best commercial CMS's out there.

It comes with integration packages for Visual Studio which make using the features a doddle and I'm looking forward to using it on some projects in the future.

Watch this space for any tips and tricks I pick up along my way.

Wednesday, 12 November 2008

Book Review : ASP.NET 2.0 Step by Step

Just over a month ago I moved in with Smithy, during the expected packing and unpacking I came across a book that I bought close to 3 years ago when I started working at twentysix Leeds and was forced to learn .NET.

The book is "ASP.NET 2.0 Step by Step" from the Microsoft Press which and I've got to say, my initial opinion was not a good one, after getting just over half way through, I became disenchanted with and put to one side. I have since spent the last 8 months looking high and low for it, and even accusing my co-workers of losing it for me :S (sorry guys) as I found a desire to finish it.

My first attempt at reading the book was not a good one. I was coming from a solid 5 years of scripting things like Lingo, ActionScript, JavaScript and most importantly PHP; I was struggling with the structured and strict way that ASP.NET works when compared to (loose and, dare I say, sloppy) PHP pages. It also seemed a bit wordy for my liking. Some of my favourite programming books are the O'Reilly cookbook series which give you examples based around short, concise scenarios.

So, armed with my now solid 2 years of experience with C# and the .NET Framework I picked up the book again, found my old bookmark still stuck in at the end of chapter 13 and decided to have a little flick.

It just so happened that the next couple of chapters concerned subjects that have been on the agenda quite a bit recently, namely the caching of data and output within a web application.

These two chapters give a good introduction and now, with just over two years experience with C# and the .NET framework I find these chapters to be just enough to get me going on a subject. I now know how and where to look for further information on a subject from my time searching the usual places.

Having re-read the first 13 chapters I take back most of what I thought about it in the first place and can see that my original lack of enthusiasm for the book was not down to the book, but due to my inexperience with ASP.NET and all its in's and outs. I actually love this book now as it gives you insights into many of the key tools that you might use day to day in a ASP.NET web app.

Good book, get it read!

Tuesday, 11 November 2008

The ASP.NET Singleton, Singleton classes for ASP.NET

This is a little trick I learned recently. I had a situation where I needed to use a static class in one of my ASP.NET web apps. I wanted it to provide functionality on a per-user basis, but when I put this in to practice I got some funny results and then I realised the obvious. Static classes are shared throughout any single instance of a .NET application, and each website runs within it's own w3wp.exe process, as a self contained application. This explained the funny behaviour.


So I did a little digging around and found the following code, which adapts the singleton pattern to store the instance in a per-user manner.

Each user is assigned an HttpContext for thier time visiting an ASP.NET web application. This Context object allows you to store objects.

So a classic Singleton might look something like this




class Singleton {

// private instance field
private static Singleton _instance;

// public read-only instance property
public static Singleton Instance {
get{
if(_instance == null){
_instance = new Singleton();
}

return _instance;
}
}

// private constructor
private Singleton() {
// constructor logic here
}
}


All we have to do is to replace the private field for an Item in the HttpContect object, like so...





class Singleton {

// public read-only instance property
public static Singleton Instance {
get{
if(HttpContext.Current.Items["SingltonInstance"] == null){
HttpContext.Current.Items.Add("SingltonInstance", new

Singleton());
}

// cast the item to a singleton because it is stored as a generic object
return (Singleton)HttpContext.Current.Items["SingltonInstance"];
}
}

// private constructor
private Singleton() {
// constructor logic here
}
}

Thursday, 26 June 2008

How to move the viewstate to the bottom of your page source (C# ASP.NET 2.0, 3.0, 2.5, Visual Studio 2005, Visual Studio 2008)

Last week one of our new SEO bod, Ryan, asked Sel to move the viewstate to the bottom of the page source for the rest assured site. This helps to improve your SEOness as a lot of search engines only take so much of your source into account when spidering. So you really don't want to be feeding them 32k of base64 encoded gibberish when you could be giving them some beautifully crafted copy!

Andy did a couple of Google's and found some code which did the trick perfectly.
protected override void Render(System.Web.UI.HtmlTextWriter writer) {
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);

base.Render(htmlWriter);
string html = stringWriter.ToString();

int StartPoint = html.IndexOf("<input type="hidden" name="__VIEWSTATE");

if (StartPoint >= 0) {
int EndPoint = html.IndexOf("/>", StartPoint) + 2;
string viewstateInput = html.Substring(StartPoint, EndPoint - StartPoint);
html = html.Remove(StartPoint, EndPoint - StartPoint);
int FormEndStart = html.IndexOf("</form>") - 1;
if (FormEndStart >= 0) {
html = html.Insert(FormEndStart, viewstateInput);
}
}
writer.Write(html);
}


This was ace and so today when I was asked to upload some ammends to a couple more of our clients sites I thought I would implement this for the same reasons as it only takes two seconds.

While it worked a treat on one of the sites, the other was not so good. Here's what the page should look like:

And here's what I got:


What has happened is this. The un-styled UL that you can see at the top of the page is the top half of the left hand navigation you can see in the 1st picture. This menu was implemented as a .NET user control and as such is treated like a page all of its own. The reason this happened is because the page was rendering out via our overridden method, but the control was not. So the HTML that the control generated was getting written to the output stream before the HTML of the Page ("Page" in the .NET Class sense, not the "web page" sense).

So this got me thinking, wouldn't it be nice to be able to have a single piece of code that could be applied to a site once, regardless of UserControls, MasterPages or any other intricacy, that would take care of moving the ViewState on every page of the site!?!

The answer: Yes!
The solution: an HttpModule...

An HttpModule is a piece of code that sits between your web application and IIS on the web server. What this module is going to do is intercept every response our application makes to a client and then, if the response is a HTML (read ASPX) page, look for and move the ViewState.

To do this we will filter the response stream using the Response.Filter property. I'll leave the full code until the end of the post but here are the main bits.

1) Create a new class that implements IHttpModule.
public sealed class IHttpViewstateMover : IHttpModule {

2) Add an event handler to the current request. This even then decides weather to add our filter to the response stream based on if it is outputting HTML.

public void Init (HttpApplication context) {
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);
}

void context_ReleaseRequestState (object sender, EventArgs e) {
HttpResponse response = HttpContext.Current.Response;

if ( response.ContentType == "text/html" ) {
response.Filter = new ViewstateMover(response.Filter);
}
}

3) If the entire HTML file has been output ...

Regex eof = new Regex("</html>", RegexOptions.IgnoreCase);

if ( !eof.IsMatch(strBuffer) ) {
// code to follow...

re-position the viewstate and output the altered HTML to the stream.

    string finalHtml = _output_buffer.ToString();

int StartPoint = finalHtml.IndexOf("<input type="hidden" name="__VIEWSTATE");
if ( StartPoint >= 0 ) {
int EndPoint = finalHtml.IndexOf("/>", StartPoint) + 2;
string viewstateInput = finalHtml.Substring(StartPoint, EndPoint - StartPoint);
finalHtml = finalHtml.Remove(StartPoint, EndPoint - StartPoint);
int FormEndStart = finalHtml.IndexOf("</form>") - 1;
if ( FormEndStart >= 0 ) {
finalHtml = finalHtml.Insert(FormEndStart, viewstateInput);
}
}


byte[] data = UTF8Encoding.UTF8.GetBytes(finalHtml);

_output_stream.Write(data, 0, data.Length);
Simple as!

Now all you need to do us take the full code listing (below) and paste it into a C# file. Then add the following to your web.config inside the element:





So here's the code.
// Source code for IHttpViewstateMover.cs
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

/// <summary>
/// IHttpViewstateMover is a HttpModule that moves the viewstate
/// to the bottom of the HTML source to help with SEO
/// </summary>
public sealed class IHttpViewstateMover : IHttpModule {
// the class is sealed so it cannot be inherited

public void Dispose () {
// nothing to dispose
}

public void Init (HttpApplication context) {
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);
}

void context_ReleaseRequestState (object sender, EventArgs e) {
HttpResponse response = HttpContext.Current.Response;

// Uncomment the following line if you only want to recieve a single call to ViewstateMover.Write
// context.Response.Buffer = true;

if ( response.ContentType == "text/html" ) {
response.Filter = new ViewstateMover(response.Filter);
}
}


/// <summary>
/// ViewstateMover is the workhorse of the IHttpViewstateMover
/// </summary>
private class ViewstateMover : Stream {
// this class is private as it serves no real purpose outside this implementation

private Stream _output_stream;
private long _position;
private StringBuilder _output_buffer;

/// <summary>
/// Creates a new instance of the ViewstateMover class
/// </summary>
/// <param name="input_stream">The HttpResponse.Filter to work with</param>
public ViewstateMover (Stream input_stream) {
_output_stream = input_stream;
_output_buffer = new StringBuilder();
}

#region Stream Members

public override bool CanRead {
get { return true; }
}

public override bool CanSeek {
get { return true; }
}

public override bool CanWrite {
get { return true; }
}

public override void Close () {
_output_stream.Close();
}

public override void Flush () {
_output_stream.Flush();
}

public override long Length {
get { return 0; }
}

public override long Position {
get { return _position; }
set { _position = value; }
}

public override long Seek (long offset, SeekOrigin origin) {
return _output_stream.Seek(offset, origin);
}

public override void SetLength (long length) {
_output_stream.SetLength(length);
}

public override int Read (byte[] buffer, int offset, int count) {
return _output_stream.Read(buffer, offset, count);
}
#endregion

public override void Write (byte[] buffer, int offset, int count) {
string strBuffer = UTF8Encoding.UTF8.GetString(buffer, offset, count);

// check for the closing HTML tag
Regex eof = new Regex("</html>", RegexOptions.IgnoreCase);

if ( !eof.IsMatch(strBuffer) ) {
_output_buffer.Append(strBuffer);
} else {
_output_buffer.Append(strBuffer);
string finalHtml = _output_buffer.ToString();

// original code from http://www.hanselman.com/blog/MovingViewStateToTheBottomOfThePage.aspx
int StartPoint = finalHtml.IndexOf("<input type="hidden" name="__VIEWSTATE");
if ( StartPoint >= 0 ) {
int EndPoint = finalHtml.IndexOf("/>", StartPoint) + 2;
string viewstateInput = finalHtml.Substring(StartPoint, EndPoint - StartPoint);
finalHtml = finalHtml.Remove(StartPoint, EndPoint - StartPoint);
int FormEndStart = finalHtml.IndexOf("</form>") - 1;
if ( FormEndStart >= 0 ) {
finalHtml = finalHtml.Insert(FormEndStart, viewstateInput);
}
}


byte[] data = UTF8Encoding.UTF8.GetBytes(finalHtml);
// write the page countents out to the user
_output_stream.Write(data, 0, data.Length);
}
}
}
}

As ever, the code is provided as is, with no kind of waranty so please test thoroughly before you place in a production environment. You use this code at your own risk.

Wednesday, 20 February 2008

Downloading and Deleting Temporary Files

Recently while working on some functionality for one of our clients I found myself in a position where I needed to add some images to a zip file. This zip file then needed to be sent to the end user as a download (Content-disposition: attachment;).

Once the user had downloaded the file, the zip file needed to be deleted so as not to leave temp files on the servers disk.

I tried a few things like calling File.Delete("path/to/file.zip") after doing Response.TransferFile() or Response.WriteFile() but I found that the page never loaded. I guess it was deleting the file bfore it had chance to stream the file to the client.

Eventually I came up with the code below which reads the entire file into a BinaryWriter and the write it out to the Response's OutputStream. The stream is then flushed and the file can be deleted.
    string theFile = "path/to/your.file";
FileInfo theFileInfo = new FileInfo(theFile);

if(theFileInfo.Exists) {
// Clear any output
Response.Clear();
Response.BufferOutput = true;
// should be the MIME-Type of your file
Response.ContentType = "application/x-zip-compressed";
// set the name of the file as it will be downloaded
Response.AddHeader("Content-Disposition", "attachment; filename=the.file");

// Open the OutputStream into a BinaryWriter
BinaryWriter br = new BinaryWriter(Response.OutputStream);
// Read the entire temporary file and write it into the BinaryWriter
br.Write(File.ReadAllBytes(theFileInfo.FullName));
// Flush and Close the Writer
br.Flush();
br.Close();

// Fulsh the Response object
Response.Flush();

// Delete the temporary file
File.Delete(theFileInfo.FullName);
// End the execution of the page
Response.End();
}

While this does get the job done it isn't perfect. The entire file is read into memory before being sent to the client. This means if you are sending large files to many clients at the same time you could have some trouble with the server running out of memory and all manner of other crazy things happening (possibly).

As ever, use at your own risk.

Tuesday, 5 February 2008

ASP.net Image Upload and Resize (in C# .net 2.0, 3.0, 3.5, visual studio 2005, visual studio 2008)

Please excuse the ridiculously long title but I kinda want to make search engines love this post because I keep having to google for it.

What follows is what I have found to be the simplest and most elegant method of uploading, resizing and saving an image in ASP.NET. So let's get to it.

Ok, lets assume we have a FileUpload control (named fuImageFile) and a Button control (btnUpload) and we're going to upload the image when we click our button. The simplest method of uploading our file might look something like this

protected string savePath = "~/uploaded/";

protected void btnUpload_Click (object sender, EventArgs e) {
string fileName = fuImageFile.FileName;
string saveName = Server.MapPath(savePath) + fileName;
fuImage.SaveAs(saveName);
}


So now we can upload an image to our server, what about resizing that image? For this to work you will need to add a using directive for System.Drawing and System.Drawing.Imaging

using System.Drawing;
using System.Drawing.Imaging;

Next we'll look at how we go about resizing an image (in the form of a Bitmap object) and then at how to integrate that into our upload page.

public Bitmap ResizeBitmap (Bitmap src, int newWidth, int newHeight) {
Bitmap result = new Bitmap(newWidth, newHeight);
using ( Graphics g = Graphics.FromImage((System.Drawing.Image)result) ) {
g.DrawImage(src, 0, 0, newWidth, newHeight);
}
return result;
}


This method takes a Bitmap object and two numbers specifying the height and width of the required image. We then create a new empty Bitmap at the desired size (result) , we then obtain a Graphics object from it (NB: the Graphics object remains associated with the Bitmap) and draw our source image into it.

When we return the result we have an Bitmap object with the image data we drew into the Graphics object.

So now lets work it into our page

protected void btnUpload_Click (object sender, EventArgs e) {
string fileName = fuImageFile.FileName;

// Get the bitmap data from the uploaded file
Bitmap src = Bitmap.FromStream(fuImageFile.PostedFile.InputStream) as Bitmap;

// Resize the bitmap data
Bitmap result = ResizeBitmap (src, 200, 200);

string saveName = Server.MapPath(savePath) + fileName;
result.Save(saveName, ImageFormat.Jpeg);
}
What we do here is take the InputStream of the FileUpload's PostedFile property and create a Bitmap with it, once we have this bitmap object we can call it's Save method to save it to the local disk.

Proportional Resizing

The problem with this ResizeBitmap is that it will stretch and pull your input image to fit the dimensions supplied which 99% of the time is not what we will want. We usually want to scale an image keeping its proportions. Take a look at the ProportionallyResizeBitmap method below:


public Bitmap ProportionallyResizeBitmap (Bitmap src, int maxWidth, int maxHeight) {
// original dimensions
int w = src.Width;
int h = src.Height;

// Longest and shortest dimension
int longestDimension = (w>h)?w: h;
int shortestDimension = (w<h)?w: h;

// propotionality
float factor = ((float)longestDimension) / shortestDimension;

// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth/factor;

// if height greater than width recalculate
if ( w < h ) {
newWidth = maxHeight / factor;
newHeight = maxHeight;
}

// Create new Bitmap at new dimensions
Bitmap result = new Bitmap((int)newWidth, (int)newHeight);
using ( Graphics g = Graphics.FromImage((System.Drawing.Image)result) )
g.DrawImage(src, 0, 0, (int)newWidth, (int)newHeight);
return result;
}

This method takes a maxWidth and a maxHeight instead of a newWidth and newHeight, it then does a bit of maths to figure out which is the longest, the original height or the original width, works out the ratio of these two numbers and applies them appropriatley to the target size and resizes the image accordingly.

Just like ResizeBitmap, ProportionallyResizeBitmap returns a Bitmap object so you can simply substitute the call to ResizeBitmap in the button click method and it will all play nicely!

Gotchas

If you get a "Generic Error from GDI +" like Exception Details: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+ then you should check the following points:
  • Make sure the destination folder exists
  • Make sure the the local machine user ISS_WPG has write permissions to the destination folder
  • Make sure the save path is correctly escaped
[more to follow maybe]

See the Microsoft Knowlage Base article http://support.microsoft.com/?id=814675 for more posibilities