Custom Virtual Folder Image Upload System Complete

Tips submitted by ASP.NET Maker users

Custom Virtual Folder Image Upload System Complete

Postby xgis » Thu Dec 19, 2013 9:24 am

The following post details the code required to implement a custom image upload solution to virtual folders located outside the generated web application folder.
The same solution can be easily modified to work within the application folder.
The solution uses 6 Table Specific Common Events, some Global Code and a small amount of Javascript.
The solution primarily enables image upload to custom folders, including generation and display of JPG thumbnails.
Image types supported include; JPG, JPEG, GIF, BMP, PNG, TIFF and TIF. Each image file is converted to its same type.
All image types display in the browser except TIF, however the thumbnail generated is JPG which does display.
Grid display rates are enhanced due to the use of thumbnails.

The template modification is minor and simple and is suited to all subsequent projects that required custom folder uploads to 2Gb.
Instructions for this are located in this post; viewtopic.php?f=45&t=33638&p=96209#p96209

ANM10.x Project settings;
Only 2 database text fields are required for this solution. for MSSQL 2 X nvarchar(255) should suffice.
Image Size and Width fields may also be added but not required.
The "Upload folder" field in the 'File Upload' part of the ANM10 project is left blank.
Read this post to learn how to implement this solution: viewtopic.php?f=45&t=33645

The'WebImageResize' extension is turned on.
The "Resize Image" checkbox is required and checked for the main image, but not the thumbnail.
The 'General Options' Tab | "File Upload" Tab | Checkbox "Delete file on update/delete" is NOT Checked.
The code language is C#

Events are listed in order of implementation within the AGX Project CODE;
The Required "Server Events" | "Global" | "All Pages" Events;
Global Code
The Required "Server Events" | "Table Specific" | "Common" Events;
Row_Deleting, Row_Inserting, Row_Inserted, Row_Rendered, Row_Updating, Row_Updated
The Required "Client Scripts" | "Global" | "Pages with header/footer" Events;
Global Code

The codes have been tested extensively. The biggest deficiency is proper error reporting, but error handling is OK.
This has been developed against MSSQL server 2012, but should be relevant for at least MSSQL 2008.
Other database types will need minor "ew_ExecuteScalar" script modifications to work.

The 1st Global Code is used to identify the next unique identity record to be created in the table so it can create a custom folder to store the images.

The 1st Global Code C#;

public static int NextRowID()
{
// Static Function for ANM10 Tools | Extensions to obtain the next IDENTITY Increment in the database
//This public static int function is entered like so; CurrentUserName(),..ew_CurrentDateTime(),NextRowID()

// The following code also resolves table upload issues where no existing data exists
// The following code also calculates the next IDENTITY for ADDing records using Row_Inserting

// Customisation1 - Change "SiteID" to your Identity Column Field Name e.g. "YourID"
// Customisation2 - Change "DMPDB" to your Schema eg "dbo"
// Customisation3 - Change "DMP_Sites" to your Table Name eg "YourTableName"

int NextRowID = 0;
try
{
//The following code checks if the table is empty. If so it returns a value of 1 for the 1st custom folder
int count = Convert.ToInt32(ew_ExecuteScalar("SELECT IDENT_CURRENT('DMPDB.DMP_Sites') AS SiteID FROM DMPDB.DMP_Sites"));
if (count == 0)
{
return 1;
}
}
catch (SystemException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}

try
{
//The next line of code is for the Row_Inserting event. It returns the NEXT IDENTITY Value for the Table
NextRowID = Convert.ToInt32(ew_ExecuteScalar("SELECT IDENT_CURRENT('DMPDB.DMP_Sites')+ IDENT_INCR('DMPDB.DMP_Sites')"));
{
return NextRowID;
}
}
catch (SystemException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
return 0;
}



The Next Event is Row_Deleting used to remove the specific folder and all uploaded files to that folder for the specific row record.
To customise the SQL in this event refer to the 3rd reply of this post viewtopic.php?f=45&t=33684

Row Deleting Event CODE;

// Recordset Deleting event
public bool Row_Deleting(OrderedDictionary rs)
{
object SelectedRowID;
SelectedRowID = ew_ExecuteScalar("SELECT SiteID FROM DMPDB.DMP_Sites WHERE SiteID =" + Convert.ToString(SiteID.CurrentValue));
string PhysicalUploadPath = ew_Server.MapPath("/App_Data_Sites/" + SelectedRowID + "/");

if (SelectedRowID != null && Directory.Exists(PhysicalUploadPath))
{
string WildcardCleanupFiles = "*.*";
foreach (FileInfo f in new DirectoryInfo(PhysicalUploadPath).GetFiles(WildcardCleanupFiles))
{
f.Delete();
}
Directory.Delete(PhysicalUploadPath, true);
}
else
{
ew_Write("The folder does not exist!");
}
return true;
}


The Row Inserting event;

This event is required for the creation of a folder for new row records and their related images or content.
The code is designed for multiple image upload scenarios and verbose names are used for easier to understand code implementation and subsequent modification.
This code has dependencies as it needs to identify the next ID from the database so it can create a folder to store the new images.
Refer to the 4th POST at this link to implement the required dependency viewtopic.php?f=45&t=33633
This process also relies on the WebImageResize extension to correctly resample images within the limits of the application image resampling capabilities.
Thumbnails are created separate to this event in a subsequent event due to workflow requirements.
To duplicate this code for subsequent images where more than 1 images are loaded per row record simply copy the code between and including the // sections for Image 1.
Paste this code into an editor, eg notepad, and use REPLACE to replace 1 with 2... and so on. This method applies to all codes posted here. Considerations will be noted where required.

The Row_Inserting Event CODE;

// Row Inserting event
public bool Row_Inserting(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{
string PhysicalUploadPath = ew_Server.MapPath("/App_Data_Sites/" + NextRowID() + "/");
string RelativeUploadPath = "/App_Data_Sites/" + NextRowID() + "/";

//Image1 Row Inserting Code START
if (Image1 != null)
{
Image1.UploadPath = RelativeUploadPath;
string OriginalNameFileUpload1 = Convert.ToString(rsnew["Image1"]);
rsnew["Image1OriginalName"] = OriginalNameFileUpload1;
string OriginalExtensionFileUpload1 = System.IO.Path.GetExtension(OriginalNameFileUpload1).ToLower();
string NewNameFileUpload1 = "Site_" + NextRowID() + "_Image1";
rsnew["Image1"] = NewNameFileUpload1 + OriginalExtensionFileUpload1;
}
else
{
return false;
}
//Image1 Row Inserting Code FINISH
return true;
}


The Row Inserted event;

This event is required for Thumbnail creation post image Row_Insertion and Image resampling.
It creates a standard sized thumbnail and is limited to Landscape images based on PHI proportions.
More advanced thumbnail generation code could be implemented for proportional resizing.
All thumbnails are of type JPG for web support, small file size. PNG may be considered where transparencies are required.
There are some potential redundancies in this code and the error handling is limited as well as exception reporting untested, but otherwise it works fine.

The Row_Inserted Event CODE;

// Row Inserted event
public void Row_Inserted(OrderedDictionary rsold, OrderedDictionary rsnew){

//Shared File Upload <ID> Code (Get Unique Row ID)
//Conversion of all image file types to JPG ensures thumnbnail display is of type JPG and not altered to .PNG
object SelectedRowID;
SelectedRowID = ew_ExecuteScalar("SELECT SiteID FROM DMPDB.DMP_Sites WHERE SiteID =" + Convert.ToString(SiteID.CurrentValue));
string PhysicalUploadPath = ew_Server.MapPath("/App_Data_Sites/" + SelectedRowID + "/");

//Image1 Row Inserted Code START
string OriginalNameFileUpload1 = Convert.ToString(rsnew["Image1OriginalName"]);
if(!string.IsNullOrEmpty(OriginalNameFileUpload1)){
string PreTrimNewName = Convert.ToString(rsnew["Image1"]);
string sList;
sList = PreTrimNewName.Substring(0, PreTrimNewName.Length - 4);
string NewNameThumbnailFileUpload1 = sList + "_thumb.jpg";

try
{
Image image = Image.FromFile(PhysicalUploadPath + Convert.ToString(rsnew["Image1"]));
Image thumb = image.GetThumbnailImage(150, 102, () => false, IntPtr.Zero);
thumb.Save(PhysicalUploadPath + NewNameThumbnailFileUpload1, ImageFormat.Jpeg);
}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
}
else
{ //Do Something else
}
//Image1 Row Inserted Code FINISH
}


The Row_Rendered Event;

The purpose of this code is to implement rapid thumbnail image display and enable the user to view the re-sampled image via the browser after upload.
TIF images are NOT rendered but the user can save them to their machine for viewing in other applications.
Further additions of revisions may be made here also to improve functionality and efficiency.

The Row_Rendered Event CODE;

// Row Rendered event
public void Row_Rendered(){
//Shared Code
string RelativeUploadPath = "App_Data_Sites/" + SiteID.DbValue + "/";
//Codes Used to Display Newly Generated JPG Thumbnails for each uploaded image

//Image1 Row Rendered Code START
if (SiteID.DbValue != null)
{
string PreTrimNewName1 = Convert.ToString(Image1.Upload.DbValue);
if(PreTrimNewName1.Length!=0)
{
string Prefix1 = PreTrimNewName1.Substring(0, PreTrimNewName1.Length - 4);
string NewNameThumbnailFileUpload1 = Prefix1 + "_thumb.jpg";
Image1.ViewValue = RelativeUploadPath + NewNameThumbnailFileUpload1;
Image1.EditValue = RelativeUploadPath + NewNameThumbnailFileUpload1;
Image1.HrefValue = RelativeUploadPath + Image1.Upload.DbValue;
}
}
else { Image1.ViewValue = "";
}
//Image1 Row Rendered Code FINISH
}


The Row Updating Event;

This event is important because it enables you to capitalise on out of the box features of ANM10.x and KEEP, REMOVE or REPLACE Images
The code has been extensively tested and works very well. Duplication and further customisation is simple.
The use of Try-Catch assist with execution logic and basic checks that need to be made prior to tasks being performed.

The Row Updating Event CODE;

// Row Updating event
public override bool Row_Updating(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{

//Shared File Upload <ID> Code (Get Unique Row ID)
object SelectedRowID;
SelectedRowID = ew_ExecuteScalar("SELECT SiteID FROM DMPDB.DMP_Sites WHERE SiteID =" + Convert.ToString(SiteID.CurrentValue));
string VirtualRootPath = "/App_Data_Sites/";
string PhysicalUploadPath = ew_Server.MapPath("/App_Data_Sites/" + SelectedRowID + "/");
string RelativeUploadPath = "/App_Data_Sites/" + SelectedRowID + "/";
string UploadRadioButtonPrefix = "a_"; //this is used in conjunction with control names on the rendered forms.

//Image1 Row Updating Code START
//File Upload Code - File Upload 1 - Field Name "Image1" - Generic <NameUploadField1>
object ExistingDBRecordFileUpload1;
ExistingDBRecordFileUpload1 = ew_ExecuteScalar("SELECT Image1 FROM DMPDB.DMP_Sites WHERE SiteID =" + Convert.ToString(SiteID.CurrentValue));
string ExistingDatabaseFileUpload1 = Convert.ToString(ExistingDBRecordFileUpload1);
string NewNameFileUpload1 = "Site_" + SelectedRowID + "_Image1";
string NewNameThumbFileUpload1 = "Site_" + SelectedRowID + "_Image1_thumb";
//Logic to integrate existing radio buttons for upload 1 file management
if (CurrentPageID() == "edit")
{

string UploadRadioButtonFieldNameSuffix1 = "Image1";
int UploadRadioButtonValuesFileUpload1 = Convert.ToInt32(HttpContext.Current.Request.Form[UploadRadioButtonPrefix + UploadRadioButtonFieldNameSuffix1]);

//KEEP Upload Image1
if (UploadRadioButtonValuesFileUpload1 == 1) //Double check this number when using Find/Replace where code is copied for multiple uploads. The same goes for values 2 and 3 in this same event below.
{//Do nothing;
}

//REMOVE Upload Image1
else if (UploadRadioButtonValuesFileUpload1 == 2)
{
try
{
System.IO.File.Delete(PhysicalUploadPath + ExistingDatabaseFileUpload1);
rsnew["Image1OriginalName"] = "";
rsnew["Image1"] = "";
if (!Directory.Exists(PhysicalUploadPath))
{
Directory.CreateDirectory(PhysicalUploadPath);
}
else
{
string WildcardCleanupFileUpload1 = NewNameFileUpload1 + ".*";
foreach (FileInfo f in new DirectoryInfo(PhysicalUploadPath).GetFiles(WildcardCleanupFileUpload1))
{
f.Delete();
}

//Delete Thumbnail Image
string WildcardCleanupThumbFileUpload1 = NewNameThumbFileUpload1 + ".*";
foreach (FileInfo f in new DirectoryInfo(PhysicalUploadPath).GetFiles(WildcardCleanupThumbFileUpload1))
{
f.Delete();
}
}
}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
}

//REPLACE Upload Image1
else if (UploadRadioButtonValuesFileUpload1 == 3)
{
try
{
if (!Directory.Exists(PhysicalUploadPath))
{
Directory.CreateDirectory(PhysicalUploadPath);
}
else
{
string WildcardCleanupFileUpload1 = NewNameFileUpload1 + ".*";
foreach (FileInfo f in new DirectoryInfo(PhysicalUploadPath).GetFiles(WildcardCleanupFileUpload1))
{
f.Delete();
}

//Delete Thumbnail Image
string WildcardCleanupThumbFileUpload1 = NewNameThumbFileUpload1 + ".*";
foreach (FileInfo f in new DirectoryInfo(PhysicalUploadPath).GetFiles(WildcardCleanupThumbFileUpload1))
{
f.Delete();
}
}
Image1.UploadPath = RelativeUploadPath;
string OriginalNameFileUpload1 = Convert.ToString(rsnew["Image1"]);
rsnew["Image1OriginalName"] = OriginalNameFileUpload1;
string OriginalExtensionFileUpload1 = System.IO.Path.GetExtension(OriginalNameFileUpload1).ToLower();
rsnew["Image1"] = NewNameFileUpload1 + OriginalExtensionFileUpload1;

}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
//Create New thumbnail image of it.

}

//Error handling File Upload 1
else
{
return false;
}
//Image1 Row Updating Code FINISH
} // This fishbrace may be a remnant of the dual upload sample. It may need to be removed if you get an "@Function error".
return true;
}



The Row_Updated Event;
This event is required for thumbnail management and replacement after an image is replaced.

The Row_Updated Event CODE;

// Row Updated event
public void Row_Updated(OrderedDictionary rsold, OrderedDictionary rsnew) {
//Shared File Upload <ID> Code (Get Unique Row ID)
object SelectedRowID;
SelectedRowID = ew_ExecuteScalar("SELECT SiteID FROM DMPDB.DMP_Sites WHERE SiteID =" + Convert.ToString(SiteID.CurrentValue));
string PhysicalUploadPath = ew_Server.MapPath("/App_Data_Sites/" + SelectedRowID + "/");

//Thumbnail Creation Code - Row_Inserted Event - Image 1
string OriginalNameFileUpload1 = Convert.ToString(rsnew["Image1OriginalName"]);
string OriginalExtensionFileUpload1 = System.IO.Path.GetExtension(OriginalNameFileUpload1).ToLower();
if(!string.IsNullOrEmpty(OriginalExtensionFileUpload1)){

string PreTrimNewName = Convert.ToString(rsnew["Image1"]);
string sList;
sList = PreTrimNewName.Substring(0, PreTrimNewName.Length - 4);
string NewNameThumbnailFileUpload1 = sList + "_thumb.jpg";
try
{
Image image = Image.FromFile(PhysicalUploadPath + Convert.ToString(rsnew["Image1"]));
Image thumb = image.GetThumbnailImage(150, 102, () => false, IntPtr.Zero);
thumb.Save(PhysicalUploadPath + NewNameThumbnailFileUpload1, ImageFormat.Jpeg);
}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
}
else {
}
//Image1 Row Updated Code FINISH
}


The Second Global Code (Javascript);

JAVASCRIPT Client Code to Update the Grid after images have been replaced.
Sometimes the grid may NOT refresh and the old image displays from the browser cache or web history.
This script should refresh the browser every 10 seconds.
It is located here; "Table Specific | Common Events | Global Code"


// Write your client script here, no need to add script tags
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
}
// -->
</script>
<body onload="JavaScript:timedRefresh(10000);">
// JS Global Code Complete

That is it. Task complete. You will obviously need to make some changes to table, field and ID field names but the code is designed to be generic and easy to read.
There is nothing complex here, just a bit of copy and paste.
Undoubtedly the codes could be more efficient but it works fine and has been tested many times.
Visual studio may be used to enhance code layout after edits. Code re-formats just by pasting it into a blank C# class page.
It may then be copied straight back to ANM10 to render the code format structure.

This code can be easily adapted to suit any uploadable file types, eg PDF etc.
xgis
 
Posts: 87
Joined: Thu Jan 17, 2013 10:40 pm

Re: Custom Virtual Folder Image Upload System Complete

Postby Savvy » Thu Dec 19, 2013 12:31 pm

Hello XGIS,

That is an absolutely fantastic solution.

You are a legend and scholar keep up the good work.
Savvy
 
Posts: 5
Joined: Wed Oct 16, 2013 7:55 am

Re: Refined Row Inserted and Row Updated Event Codes

Postby xgis » Fri Dec 20, 2013 6:19 am

The code updates here are designed to improve parts of the previous code avoid potential Length errors.

New Codes;

UPDATED Row_Inserted Event;

//Thumbnail Creation Code - Row_Inserted Event - Image 1
string PreTrimNewName1 = Convert.ToString(rsnew["Image1"]);
if(!string.IsNullOrEmpty(PreTrimNewName1)){
string sList1;
sList1 = PreTrimNewName1.Substring(0, PreTrimNewName1.Length - 4);
string NewNameThumbnailFileUpload1 = sList1 + "_thumb.jpg";

try
{
Image image = Image.FromFile(PhysicalUploadPath + Convert.ToString(rsnew["Image1"]));
Image thumb = image.GetThumbnailImage(150, 102, () => false, IntPtr.Zero);
thumb.Save(PhysicalUploadPath + NewNameThumbnailFileUpload1, ImageFormat.Jpeg);
}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
}
else
{ //Do Something else
}
// FINISH Row_Inserted Event - Image 1


UPDATED Row Updated event

//Thumbnail Creation Code - Row_Updated Event - Image 1
string PreTrimNewName1 = Convert.ToString(rsnew["Image1"]);
if(!string.IsNullOrEmpty(PreTrimNewName1)){
string sList;
sList = PreTrimNewName1.Substring(0, PreTrimNewName1.Length - 4);
string NewNameThumbnailFileUpload1 = sList + "_thumb.jpg";
try
{
Image image = Image.FromFile(PhysicalUploadPath + Convert.ToString(rsnew["Image1"]));
Image thumb = image.GetThumbnailImage(150, 102, () => false, IntPtr.Zero);
thumb.Save(PhysicalUploadPath + NewNameThumbnailFileUpload1, ImageFormat.Jpeg);
}
catch (FileNotFoundException ex)
{
HttpContext.Current.Response.Write(ex.Message);
}
}
else {
}
// FINISH Row_Updated Event - Image 1
xgis
 
Posts: 87
Joined: Thu Jan 17, 2013 10:40 pm


Return to User Submited Tips (ASP.NET Maker)