April 2006 - Posts

ASP.NET 2.0 FileUpload control - cannot upload more than 4MB by default

I had been wondering. How come my asp.net 2.0 fileupload control can select my jpg image and not my avi video? So I had been wondering, was it that asp.net 2.0 file control could not support avi file extension? That was kinda of crap. I couldn't believe Microsoft would do that right. To prove me wrong. 

So I had decided to search the web again. Geez...

I found out a good tutorial here http://www.c-sharpcorner.com/UploadFile/mahesh/FileUpload10092005172118PM/FileUpload.aspx?ArticleID=79850d6d-0e91-4d7b-9e27-a64a09b0ee6b

He demonstrated that by default you were only able to upload < 4MB.

"The default size of files uploaded by the FileUpload control is 4MB. So if you try to upload the files larger than 4MB, it won't let you do so. To do so, you need to change the default file size in machine.config.comments file for maxRequestLength of httpRuntime tag.  This number is in KB." by Mahesh Chand (from the original article)

So I did learned something from here.

However, he had suggested to modify as below:

"To do so, you need to change the default file size in machine.config.comments file for maxRequestLength of httpRuntime tag.  This number is in KB.

<httpRuntime
executionTimeout = "110" [in Seconds][number
maxRequestLength = "4096" [number]
requestLengthDiskThreshold = "80" [number]
useFullyQualifiedRedirectUrl = "false" [true|false]
minFreeThreads = "8" [number]
minLocalRequestFreeThreads = "4" [number]
appRequestQueueLimit = "5000" [number]
enableKernelOutputCache = "true" [true|false]
enableVersionHeader = "true" [true|false]
apartmentThreading = "false" [true|false]
requireRootedSaveAsPath = "true" [true|false]
enable = "true" [true|false]
sendCacheControlHeader = "true" [true|false]
shutdownTimeout = "90" [in Seconds][number]
delayNotificationTimeout = "5" [in Seconds][number]
waitChangeNotification = "0" [number]
maxWaitChangeNotification = "0" [number]
enableHeaderChecking = "true" [true|false]
/>" by Mahesh Chand.

So I went into my root directory C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG and tried to open that file machine.config.comments file. I tried to search for the keywords as above, and I really could not able to find any. I wondered for a while.

Am I missing something? Am I on a wrong version?

Finally I decided to google again (man, I like the term google). So I found out from here http://channel9.msdn.com/ShowPost.aspx?PostID=106570 This person recommended on this:

"I had this issued when migrating my ASP.Net 1.1 site to ASP.Net 2.0. I found that I couldn't receive file uploads larger than around 80K. It worked fine under 1.1 but failed under 2.0.

There is a new attribute to the httpRunTime element in the web.config for ASP.Net 2.0 that specifies a disk buffer. Changing this to 8192 allowed my code to work.

// Include the code below in your web application web.config

<system.web>
<httpRuntime executionTimeout="90" maxRequestLength="20000" useFullyQualifiedRedirectUrl="false" requestLengthDiskThreshold="8192"/>
</system.web>

http://msdn2.microsoft.com/en-us/library/h2e8928c.aspx

My site was on an intranet. If you're deploying publicly you should be aware that increasing these settings can make your site more vulnerable to a DoS attack." by developer

So I guessed I learned something from there. I had tested and it worked now. :) Cool.

Maybe back to the earlier article, you needed to include those httpRuntime tags into the machine.config.comments instead of modifying it (maybe not for a new user like me since he might had added them last time - my assumption).

Cheers.

Posted by chuawenching with 3 comment(s)

ASP.NET 2.0 Hosting Windows Media Player ActiveX - kinda of nightmare figuring it out

The pre-sales team wanted to have support to view video files on the web page. I am using asp.net 2.0 and I have to attend tomorrow Vista Touchdown program. Well I don't really have much time to work on this.

So I just googled as usual (or maybe msn) hehe. I found out this nice article http://steveorr.net/articles/StreamingMedia.aspx. Keep up the good work Steve. I appreciated your effort on that.

I tried on VS .NET 2003, it was kinda of amazing. I was happy with the output. Kudos.

So I told myself maybe I tried not be too happy first. It might not work on ASP.NET 2.0.

So I tried to include the MediaPlayers.csproj files into my solution. Hmm, well you kinda got some project error, but no worries. There weren't any compilations errors.

Basically it is an UI control. So you can add 2 controls into your toolbox. Try to find your MediaPlayers.dll and it will add 2 controls:

a) Audio Control

b) Media Player Control

When you tried to drag the Mesia Player control on the asp.net 2.0 web form. You will see the control looks weird, like you include an image control but you do not set the image filename path. It was like the control not working properly. You can see some differences when running this in VS .NET 2003 and VS 2005.

So I just prayed to god, hope nothing was wrong with it. No compilation error .. yes yes. I tried to run the program. Now the control was loaded. Yes yes. But wait a second, why wasn't the video loaded automatically? Since you had set the control property AutoStart = true. It worked very fine on VS .NET 2003.

Weird. Weird. So what was wrong with it?

I tried to debug the web application, but I was not able to figure what went wrong.

So I decided to follow his tutorial (which was based on asp.net 1.x). I tried to copy the object tags manually into my default.aspx (asp.net 2.0 web form). Suprisingly it worked.

Since I had tried to specify this:

<div>

<object id="Player" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" viewastext>

<param name="autoStart" value="true" />

<param name="URL" value="Wedding - Photo Album.avi" /> // Points to the video file directly

<param name="rate" value="1" />

<param name="balance" value="0" />

<param name="enabled" value="true" />

<param name="enabledContextMenu" value="true" />

<param name="fullScreen" value="false" />

<param name="volume" value="100" />

</object>

</div>

I had tried to call the video directly. It worked. Well the control still looked funny in VS 2005 designer but it worked fine.

So where was the problem? I had figured out maybe it was the file name path.

I had compared between the VS.NET 2003 and VS 2005 sample. I had found out a difference between both of them.

Example,

VS.NET 2003 FileName = Video/Wedding - Photo Album.avi (missing tilt + slash) - functioning

VS 2005 FileName = ~/Videos/Wedding - Photo Album.avi - not functioning

I had tried a few times (in case I was still in the dream land) to make sure I was correct in analyzing this problem. So in VS 2005, it would worked if you exlcude this "~/" (2 characters).

Hope this is useful to other people looking for such solution to work on VS 2005.

Thanks to Steve for such a good tutorial again. If not, I won't be able to figure out by myself. Except there are alternatives ways to achieve that :)

Lastly, do correct me if I am wrong in anywhere. Since I am still quite new to this area. Cheers.

Posted by chuawenching with no comments

Set Param.Size when expecting fixed datatype output

I learned it yesterday so probably would like to share this beginner tips.

Example, when you are expecting an output from your stored procedure like below:

(

 @varOutput      VARCHAR(10)   OUTPUT

)

If you do not place the param.size of this @varOutput, you will receive an error like this:

String[1]: The Size Property has an invalid size of 0

So remember to set the size exactly like what you have configured inside your database table.

Cheers.

Posted by chuawenching with no comments

My next findings on Dynamic SQL + OpenRowSet

Aaaahhhh. I took so long to figure this out. But thanks to 2 of my colleagues sharing their debugging skills. LOL.

1) When working with Dynamic SQL and OpenRowSet, be careful with double quotes when you concatenate T-SQL and your variable.

Say NO to: // 1 quote between the variable

SET @SQLString = 'INSERT INTO myTable ( FileName, FileType, SomeDate, Document ) ' +

'SELECT ' + @str1 + ' as FileName, ' +

@str2 + ' as FileType, ' +

cast(@test1 as varchar(100)) + ' as SomeDate, ' +

'BulkColumn FROM OPENROWSET(BULK ' +

@varPicturePath + ', SINGLE_BLOB) AS Document';

Say YES to: // 3 quotes between the variables

SET @SQLString = 'INSERT INTO myTable ( FileName, FileType, SomeDate, Document ) ' +

'SELECT ''' + @str1 + ''' as FileName, ''' +

@str2 + ''' as FileType, ''' +

cast(@test1 as varchar(100)) + ''' as SomeDate, ' +

'BulkColumn FROM OPENROWSET(BULK ''' +

@varPicturePath + ''', SINGLE_BLOB) AS Document';

2) Remember to convert DateTime to varchar in your dynamic sql. If normal t-sql, there is no issue.

Say NO to:

SET @SQLString = 'INSERT INTO myTable ( FileName, FileType, SomeDate, Document ) ' +

'SELECT ''' + @str1 + ''' as FileName, ''' +

@str2 + ''' as FileType, ''' +

@test1 + ''' as SomeDate, ' +

'BulkColumn FROM OPENROWSET(BULK ''' +

@varPicturePath + ''', SINGLE_BLOB) AS Document';

EXEC (@SQLString)

Say YES to:

SET @SQLString = 'INSERT INTO myTable ( FileName, FileType, SomeDate, Document ) ' +

'SELECT ''' + @str1 + ''' as FileName, ''' +

@str2 + ''' as FileType, ''' +

-- cast here

cast(@test1 as varchar(100)) + ''' as SomeDate, ' +

'BulkColumn FROM OPENROWSET(BULK ''' +

@varPicturePath + ''', SINGLE_BLOB) AS Document';

EXEC (@SQLString)

3) Be careful with the positions of each data you want to pass in. Don't get mix up.

Example

-- Section 1

SET @SQLString = 'INSERT INTO myTable ( FileName, FileType, SomeDate, Document ) ' +

-- Section 2

'SELECT ''' + @str1 + ''' as FileName, ''' +

@str2 + ''' as FileType, ''' +

cast(@test1 as varchar(100)) + ''' as SomeDate, ' +

'BulkColumn FROM OPENROWSET(BULK ''' +

@varPicturePath + ''', SINGLE_BLOB) AS Document';

Make sure the section 1 and section 2 orders the same.

Note: You don't have to follow exactly like the Database Table column name.

4) OpenRowSet statement must always the last ... try to avoid as below:

Say NO to:

INSERT myTable ( [FileName], FileType, SomeDate, [Document] )

SELECT 'Haha' as FileName,

'Hehe' as FileType,

BulkColumn FROM OPENROWSET(BULK 'C:\wenching.jpg', SINGLE_BLOB) AS Document, GETDATE() as SomeDate

Say YES to:

INSERT myTable ( [FileName], FileType, SomeDate, [Document] )

SELECT 'Haha' as FileName,

'Hehe' as FileType, GETDATE() as SomeDate,

BulkColumn FROM OPENROWSET(BULK 'C:\wenching.jpg', SINGLE_BLOB) AS Document

Phew, what a tough day battling with this problem. Hope you find it useful :) Do correct me if I am wrong. I am far more willing to learn and fix it :)

Thanks.

 

Posted by chuawenching with 2 comment(s)

ASP.NET 2.0 - My Findings on Read/Write Images into SQL Server 2005

Cool. I finally come out with a solution and I will love to share this with my friends who read my blog.

I will like to thank Wee Hyong, Feelite and Serena for posting your feedbacks in my thread located in SgDotNet ASP.NET forums.

I was planning to post a document on this, but I felt that it would take a lot of time to proof check and edit it. So I just blog it. Plus I am not posting any screenshots. I will illustrate as details as I can. Do bear with my broken english. :(

Software - Microsoft Visual Studio 2005 Team Edition, Microsoft SQL Server 2005 Developer Edition (I guess you can use other editions, but I am not that sure about SQL Server Express)

1)

Assuming I have a database table like this:

CustomerImage Table

PrimaryID INT NOT NULL Primary Key

Picture VARBINARY(MAX) NOT NULL (You need to have the MAX keyword here, read Wee Hyong's blog)

2)

After you have created that database (either using T-SQL or through SQL Server Management Studio), time for you to write 2 stored procedures.

a) Write Images

Note: I had choosen this way due to 2 reasons:

i) I had tried a lot of ways, and I had problems with it.

One example, if you try saving this file (it works) but when you try to execute it (it won't). Full of suprises haha :)

CREATE Procedure usp_TestWriteImage

(

@varPicturePath VARCHAR(max)

)

AS

SET NOCOUNT ON

BEGIN

INSERT INTO CustomerImage ( Picture )

SELECT * FROM OPENROWSET(BULK ''' +

-- It doesn't understand @varPicturePath

@varPicturePath + ''', SINGLE_BLOB) AS Picture

END

ii) And you know I am very weak in Database. So someone could have solved as above. Haha.

This is my implementation. It really cracks my brain :(

ALTER PROCEDURE dbo.usp_WriteImages

(

@varPicturePath VARCHAR(MAX)

)

AS

BEGIN

DECLARE @SQLString NVARCHAR(max)

SET NOCOUNT ON

-- Assign into a temporary variable

SET @SQLString = N'INSERT INTO CustomerImage ( Picture ) ' +

'SELECT BulkColumn FROM OPENROWSET(BULK ''' +

@varPicturePath + ''', SINGLE_BLOB) AS Picture';

-- Execute this temporary variable

EXEC sp_executesql @SQLString

END

Yes, Yes. It works. For your information, you can do this:

i) SELECT * FROM OPENROWSET ...

OR

ii) SELECT BulkColumn FROM OPENROWSET

I think people prefer the 2nd way, maybe with the best practices - avoid using * in your T-SQL Statement.

b) Read Images

CREATE PROCEDURE dbo.usp_ReadImages

AS

SET NOCOUNT ON

SELECT Picture FROM CustomerImage

WHERE PictureID = 5

RETURN

Okay, not you see me playing cheat here. Haha. I actually specified a PictureID = 5. Take note, I am just writing an example here. So I am not going to waste my time figuring out how to write a complex example.

3)

Cool. Database stuff alread finished. Time to work on asp.net 2.0 codes. Take note, you don't have to write sql managed to achieve all this. :)

4)

Create a standard website in vs 2005.

In your default.aspx you have to drag some controls.

(I wish I have a table to display the item belows :( )

Controls (Top to bottom):

a) Header Text (H1) with text "This is an upload and download of images"

b) 1 Horizontal Rule

c) (H2) with text "Upload"

d) Image Control from Standard Toolbar - name this imgUpload

e) FileUpload Control from Standard Toolbar - name this fuUpload

f) Button Control from Standard Toolbar - name this btnUpload and text "Upload"

g) Button Control from Standard Toolbar - name this btnSave and text "Save"

h) 1 Horizontal Rule

i) (H2) with text "Download"

j) Image Control from Standard Toolbar - name this imgDownload

k) Button Control from Standard Toolbar - name this btnDownload and text "Load Image"

For this source code, you can get it below:

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<h1>

This is an upload and download of images

</h1>

<hr />

<h2>

</h2>

<h2>

</h2>

<h2>

Upload</h2>

<p>

Select a file to upload:

</p>

<p>

<asp:Image ID="imgUpload" runat="server" Height="150px" Width="140px" />&nbsp;</p>

<p>

<asp:FileUpload ID="fuUpload" runat="server" Width="304px" />&nbsp;</p>

<p>

<asp:Button ID="btnUpload" runat="server" Text="Upload" Width="119px" OnClick="btnUpload_Click" />&nbsp;</p>

<p>

<asp:Button ID="btnSave" runat="server" OnClick="btnSave_Click" Text="If you confirm, save"

Width="171px" />&nbsp;</p>

<hr />

<h2>

Download</h2>

<p>

<asp:Image ID="imgDownload" runat="server" Height="150px" Width="140px" />&nbsp;</p>

<p>

<asp:Button ID="btnDownload" runat="server" Text="Load Image" OnClick="btnDownload_Click" />&nbsp;</p>

<p>

&nbsp;</p>

<p>

&nbsp;</p>

</div>

</form>

</body>

</html>

5)

Cool. I have a nice layout. Let's move on to write my ConnectionManager class.

Create a class and place it inside App_Code folder.

Name this class as ConnectionManager.cs

Note: I will break it separately as it is quite fundamental. If you are a noob like me, there are comments in the code for you to read.

ConnectionManager.cs

// Developed by: Chua Wen Ching

// Reference:

// Obtains inputs from SgDotNet Community

// http://community.sgdotnet.org/forums/thread/25548.aspx

// Note: Not tested with performance

// Do let me know for further enquiries, chuawenching@yahoo.com

using System;

using System.Data;

using System.Data.SqlClient;

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;

/// <summary>

/// Summary description for ConnectionManager

/// </summary>

public static class ConnectionManager

{

static ConnectionManager()

{

//

// TODO: Add constructor logic here

//

}

/// <summary>

/// Execute stored procedures to insert image

/// </summary>

/// <param name="imagePath"></param>

public static void writeImageToDB(string imagePath)

{

// Open Connection upon reading connection strings from web.config

using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["TestConnectionString"].ToString()))

{

// "usp_WriteImages" is the stored procedure

SqlCommand command = new SqlCommand("usp_WriteImages", conn);

// Specify type of command - for this case Stored Procedure

command.CommandType = CommandType.StoredProcedure;

// Add 1st parameter

// You need to pass in the picture path

SqlParameter pathParam = new SqlParameter();

pathParam.ParameterName = "@varPicturePath";

pathParam.Value = imagePath;

pathParam.DbType = DbType.String;

command.Parameters.Add(pathParam);

// Open Connection

conn.Open();

// Execute the stored procedure

command.ExecuteNonQuery();

// Close connection, cleans things up

conn.Close();

conn.Dispose();

}

}

/// <summary>

/// Execute stored procedure to read image

/// </summary>

/// <returns></returns>

public static byte[] readImageFromDB()

{

SqlDataReader dr = null;

byte[] image = null;

// Open Connection upon reading connection strings from web.config

using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["TestConnectionString"].ToString()))

{

// "usp_ReadImages" is the stored procedure

SqlCommand command = new SqlCommand("usp_ReadImages", conn);

command.CommandType = CommandType.StoredProcedure;

// Open Connection

conn.Open();

// Get the return results from the stored procedure

// and pass into SqlDataReader

dr = command.ExecuteReader();

dr.Read();

// Return the read value and cast into byte array

image = (byte[])dr.GetValue(0);

// Close datareader and connections, cleans things up

dr.Close();

conn.Close();

dr.Dispose();

conn.Dispose();

}

// Return the byte array to the caller

return image;

}

}

6) Time to write some events handling code in your main Default.aspx

7) Open your code behind which is Default.aspx.cs

Add additional namespaces as below:

using System.IO;

using System.Drawing;

using System.Drawing.Imaging;

8)

btnUpload_Click event

Basically I want to achieve here is:

- Get the file anywhere on your machine

- Store it temporary in your local web server

- Store the location of the file within your Profile

/// <summary>

/// Upload to a temporary location

/// Load it to the image control

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnUpload_Click(object sender, EventArgs e)

{

// Check if the file is available

if (fuUpload.HasFile)

{

// Temporary location to store the images

// It is advisable to have this folder within your web application

string tempLocation = @"~\TempImages\" + fuUpload.FileName;

// Need the exact path to save this image.

// You cannot just load from the tempLocation.

// This path is also crucial when passing down to the stored procedure

string exactLocation = @"C:\Inetpub\wwwroot\DatabaseUploadDownload\TempImages\" + fuUpload.FileName;

// Save this image

fuUpload.SaveAs(exactLocation);

// Display the image

imgUpload.ImageUrl = tempLocation;

// Need to store into profile, if page postback

// fuUpload.FileName value will be empty

Profile.imagePath = exactLocation;

}

}

9)

Time to save your image. In this process I will be:

- Get the Profile path

- Pass this path into my ConnectionManager writeImageToDB function

- Delete this image from the tempImages folder

- Clear the Profile

- Set the imgUpload to a empty url

/// <summary>

/// This is the actual implementation of saving the file into the database

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void btnSave_Click(object sender, EventArgs e)

{

// Obtain values from Profiles

// You can pass around Profile.ImagePath if you want it to.

// I just want to reduce my time typing it.

string imagePath = Profile.imagePath;

// Write Image into database

ConnectionManager.writeImageToDB(imagePath);

// Remove Temporary image

// You don't need this image since it will be stored inside the database

File.Delete(imagePath);

// Clear Profile imagePath

Profile.imagePath = string.Empty;

// Clear Image Control

imgUpload.ImageUrl = string.Empty;

}

10)

Download the image from the database and display in the imgDownload

Note: Don't forget to read the comments.

protected void btnDownload_Click(object sender, EventArgs e)

{

using (MemoryStream mStream = new MemoryStream(ConnectionManager.readImageFromDB()))

{

string strDefaultFileName = "Default.jpg";

string strDefaultFileLocation = @"C:\Inetpub\wwwroot\DatabaseUploadDownload\TempImages\";

string strTempLocation = @"~\TempImages\";

byte[] imageFromDatabase = new byte[mStream.Length];

mStream.Read(imageFromDatabase, 0, imageFromDatabase.Length);

// I have to manually specify System.Drawing.Image, as it will get mix

// between System.Drawing.Image and System.Web.UI.WebControls

System.Drawing.Image displayImage = System.Drawing.Image.FromStream(mStream);

// 1st, you need to specify the exact path, cannot use "~\tempImages\",

// it won't work, you will receive some GDI+ error

displayImage.Save(strDefaultFileLocation + strDefaultFileName, ImageFormat.Jpeg);

// Alternative: If you want to display on the HTTP OutputStream

// Use this

// displayImage.Save(Response.OutputStream, ImageFormat.Jpeg);

// Display this image

imgDownload.ImageUrl = strTempLocation + strDefaultFileName;

}

}

11) Compile your webapp.

12) Trust me that you will see 2 errors. Why?

- No connectionstring inside your web config

- No profile properties in your web.config

Let's work on this:

a) ConnectionString

<connectionStrings>

<add name="TestConnectionString" connectionString="Data Source=MSROCKS;Initial Catalog=Test;Integrated Security=True;Pooling=False"

providerName="System.Data.SqlClient" />

</connectionStrings>

b) Profile

- I set allow annonymous, so you will expect this

<anonymousIdentification enabled="true" />

<profile>

<properties>

<add name="imagePath" allowAnonymous="true" type="System.String" />

</properties>

</profile>

- If you say no annoymous, just write this

<profile>

<properties>

<add name="imagePath" type="System.String" />

</properties>

</profile>

If you read about my other post, you have to set a full type for imagePath property. You can't have the type="String". You have to place full path like this type="System.String"

13) Ola. Before you want to start running this examples. You have to configure a few things.

a) Make sure your aspnet account is within your new database.

b) Make sure your server roles \ bulk admin contains aspnet account. This is very important. By default aspnet does not have access to this bulk admin.

c) Make sure your aspnet account have read and write access to tempimages folder.

14) Time to run.

I guess this will be useful for everyone. Do correct me if I am wrong. I want to learn too like many others.

Cheers and have fun.

Posted by chuawenching with 4 comment(s)