Wednesday, May 27, 2009
There are two ways to disable the CSS Friendly Adapters in ASP.NET:
1. In the Browser file
Adapters for a specific control type can be disabled by just commenting out (deleting) the type of control adapter in the browser file. The effect is global and will affect all the controls of this type.
For examle, to disable the adapter for GridView type:
<!--<adapter controlType="System.Web.UI.WebControls.GridView"
adapterType="CSSFriendly.GridViewAdapter" />-->
2. At the control level
Adapter can be disabled for a specific control in the control definition in aspx file by specifying AdapterEnabled="false" property. The effect is local and will only affect the control for which it is specified.
Tuesday, May 26, 2009
.NET's SqlDataReader class is based on an active connection to the database. This means that while the SqlDataReader is in use, the SqlConnection that is serving the SqlDataReader is open and cannot be used anywhere else.
That is why, returning an SqlDataReader from a method is not stright forward like returning a DataTable or a DataSet. To read more about SqlDataReader, please see SqlDataReader class.
Though it is not straight forward, it is very simple. Here's a piece of code that would let you return a SqlDataReader from a method:
public SqlDataReader GetData(string item1, string item2)
{
SqlDataReader reader = null;
SqlConnection connection = new SqlConnection(ConnectionString);
try
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "YOUR_SPROC_NAME";
command.Parameters.Add("@Item1", SqlDbType.VarChar, 255).Value = item1;
command.Parameters.Add("@Item2", SqlDbType.VarChar, 255).Value = item2;
command.Connection = connection;
connection.Open();
reader = command.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
connection.Close();
Response.Write(ex.Message);
}
return reader;
}
Wednesday, April 29, 2009
Found a nice post by Mr.Polite for compressing JPEG images. Here's the link:
http://www.vbforums.com/showthread.php?p=2038463
Posting the code here for my reference in case the original post gets deleted or changed.
Image myImage = //... load the image somehow
// Save the image with a quality of 50%
SaveJpeg (destImagePath, myImage, 50);
//add this!
using System.Drawing.Imaging;
/// <summary>
/// Saves an image as a jpeg image, with the given quality
/// </summary>
/// <param name="path">Path to which the image would be saved.</param>
// <param name="quality">An integer from 0 to 100, with 100 being the
/// highest quality</param>
public static void SaveJpeg (string path, Image img, int quality)
{
if (quality<0 || quality>100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
// Encoder parameter for image quality
EncoderParameter qualityParam =
new EncoderParameter (Encoder.Quality, quality);
// Jpeg image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save (path, jpegCodec, encoderParams);
}
/// <summary>
/// Returns the image codec with the given mime type
/// </summary>
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for(int i=0; i<codecs.Length; i++)
if(codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
Tuesday, March 17, 2009
Hyperlink to Remote Desktop (RDP) session:
I had some IP addresses on a web page which would be used internally by our company users and wanted to display them as hyperlinks. When a user clicks an IP address, a Windows RDP session should start.
The simplest way I could think of was to transfer an RDP file to the client, which she can open or save via regular HTTP File Transfer.
An RDP file can be edited by a simple text editor. If you open an RDP file with notepad, you will see all the settings. The one we are interested in is full address:s:
I use ASP.NET LinkButton control as the hyperlink and use the Text property of the LinkButton to modify the full address:s: setting.
My code uses a Default.rdp file located in Download directory in the root of my web site. I open the file, modify the full address property, save it and transfer the file to the client.
Here’s the piece of code. I agree it is not polished yet, but I know you can do it.
C# Code:
protected void LinkButton_Click(object sender, EventArgs e)
{
// Default RDP file
string fileName = "Default.rdp";
if ((fileName != ""))
{
// Get absolute path of the file
string filePath = Server.MapPath("~/Download/" + fileName);
// Update RDP file
LinkButton linkButton = (LinkButton)sender;
UpdateRDPFile(linkButton.Text, filePath);
// Download RDP file
DownLoadFile(filePath);
}
else
{
Response.Write("Please provide a file to download.");
}
}
private void UpdateRDPFile(string IPAddress, string filePath)
{
StringBuilder newFile = new StringBuilder();
string temp = "";
string[] fileToUpdate = File.ReadAllLines(filePath);
foreach (string line in fileToUpdate)
{
if (line.Contains("full address:s:"))
{
temp = temp.Insert(0, "full address:s:" + IPAddress);
newFile.Append(temp + "\r\n");
continue;
}
newFile.Append(line + "\r\n");
}
File.WriteAllText(filePath, newFile.ToString());
}
private void DownLoadFile(string filePath)
{
// get file object as FileInfo
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
// -- if the file exists on the server
if (file.Exists)
{
// set appropriate headers
Response.Clear();
Response.AddHeader("Content-Disposition", ("attachment; filename=" + file.Name));
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(file.FullName);
Response.End();
// if file does not exist
}
else
{
Response.Write("This file does not exist.");
}
}
ASPX Markup:
<table style="border: 1px solid #BBB; border-collapse: collapse; width: 520px;" rules="all"
cellspacing="0" cellpadding="3">
<tr style="background-color: #FF9900; color: #FFF">
<td colspan="2">
RDP
</td>
</tr>
<tr style="background-color: #ECECEC; color: #000">
<td>
Description
</td>
<td>
Link
</td>
</tr>
<tr>
<td>
RDP1:
</td>
<td>
<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton_Click">127.0.0.1</asp:LinkButton>
</td>
</tr>
<tr>
<td>
RDP2:
</td>
<td>
<asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton_Click">127.0.0.2</asp:LinkButton>
</td>
</tr>
<tr>
<td>
RDP3:
</td>
<td>
<asp:LinkButton ID="LinkButton3" runat="server" OnClick="LinkButton_Click">127.0.0.3</asp:LinkButton>
</td>
</tr>
</table>
Monday, February 02, 2009
Previously I posted an example on how to download multiple images or files using DotNetZip library
here.
Today I will explain how we can use the same library to unzip images from a zipped folder and insert them into an SQL Server table.
Note: I have used NeatUpload library developed by Dean Brettle to display import progress to the user which can be found
here. If you don’t want to use it, remove the namespace from the code and modify the code to not use NeatUpload controls.
Libraries used:
Here is the piece of code:
using System;
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;
using System.Data;
using System.Data.OleDb;
using System.IO;
/* Other NameSpaces*/
using Ionic.Utils.Zip;
using Brettle.Web.NeatUpload;
public partial class Admin_Photos_aspx : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Add triggers to ProgressBar1 (optional)
ProgressBar1.AddTrigger(uxZipImport);
ProgressBar1.AddTrigger((ImageButton)FormView1.FindControl("AddNewPhotoButton"));
}
protected void DeleteFiles(string folderName)
{
string folderPath = folderName;
string[] files = Directory.GetFiles(folderPath);
foreach (string fileName in files)
{
File.Delete(fileName);
}
}
protected void uxZipImport_Click(object sender, ImageClickEventArgs e)
{
string rootFolderPath = "C:/Inetpub/Temporary/FriendUpload";
// Create Temporary User directory to store images
DirectoryInfo di = CreateUserDirectory(rootFolderPath);
string serverFilePath = di.FullName + @"\" + FileUpload1.FileName;
if (FileUpload1.HasFile && FileUpload1.ContentLength > 0)
{
// Store uploaded zip file in User folder in FriendUpload folder
// NeatUpload requires you to move the file to a permanent location
// Uncomment the following FileUpload1.SaveAs and comment FileUpload1.MoveTo if you don’t want to use NeatUpload
//FileUpload1.SaveAs(serverFilePath);
FileUpload1.MoveTo(Path.Combine(di.FullName, FileUpload1.FileName), Brettle.Web.NeatUpload.MoveToOptions.Overwrite);
}
else
{
return;
}
// Get the path of zipped file to unpack
string ZipToUnpack = serverFilePath;
// Where to unpack
string TargetDir = di.FullName;
string extractedFolderName = "";
using (ZipFile zip1 = ZipFile.Read(ZipToUnpack))
{
// here, we extract every entry, but we could extract
// based on entry name, size, date, etc.
foreach (var entry in zip1)
{
entry.Extract(TargetDir, true);
// Get the extracted file name, this can include folder name also
string extractedFileName = entry.FileName;
// remove file name to get the folder name
if (entry.FileName.Contains("/"))
{
extractedFolderName = extractedFileName.Remove(extractedFileName.LastIndexOf("/"));
}
else
{
extractedFolderName = "";
}
}
}
DirectoryInfo d;
if (string.IsNullOrEmpty(extractedFolderName))
{
d = new DirectoryInfo(TargetDir);
}
else
{
d = new DirectoryInfo(TargetDir + @"/" + extractedFolderName);
}
int count = 0;
// ProgressInfo (optional)
ProgressInfo progress = ProgressBar1.ProcessingProgress = new ProgressInfo(d.GetFiles("*.jpg", SearchOption.TopDirectoryOnly).Length, "Images");
foreach (FileInfo f in d.GetFiles("*.jpg"))
{
using (FileStream fileStream = f.OpenRead())
{
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, (int)fileStream.Length);
PhotoManager.AddPhoto(Convert.ToInt32(Request.QueryString["AlbumID"]), f.Name, buffer);
}
// Displaying the number of images processed to the user
count++;
progress.Value = count;
}
progress.Text = "Import complete.";
GridView1.DataBind();
// Delete temporary files after processing (optional)
di.Delete(true);
}
/* Create temporary User Directory to store images and zipped file. */
public DirectoryInfo CreateUserDirectory(string directoryPath)
{
string userName = System.Guid.NewGuid().ToString("N");
if (!string.IsNullOrEmpty(User.Identity.Name))
{
userName = User.Identity.Name;
}
string userDirectoryName = directoryPath + "\\" + userName;
DirectoryInfo di;
if (!Directory.Exists(userDirectoryName))
{
di = System.IO.Directory.CreateDirectory(userDirectoryName);
return di;
}
else
{
di = new DirectoryInfo(userDirectoryName);
}
return di;
}
}
/* PhotoManager.AddPhoto method */
public static void AddPhoto(int AlbumID, string Caption, byte[] BytesOriginal) {
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Personal"].ConnectionString)) {
using (SqlCommand command = new SqlCommand("AddPhoto", connection)) {
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("@AlbumID", AlbumID));
command.Parameters.Add(new SqlParameter("@Caption", Caption));
command.Parameters.Add(new SqlParameter("@BytesOriginal", BytesOriginal));
command.Parameters.Add(new SqlParameter("@BytesFull", ResizeImageFile(BytesOriginal, 600)));
command.Parameters.Add(new SqlParameter("@BytesPoster", ResizeImageFile(BytesOriginal, 198)));
command.Parameters.Add(new SqlParameter("@BytesThumb", ResizeImageFile(BytesOriginal, 100)));
connection.Open();
command.ExecuteNonQuery();
}
}
}
// Helper Functions
private static byte[] ResizeImageFile(byte[] imageFile, int targetSize) {
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile))) {
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format24bppRgb)) {
using (Graphics canvas = Graphics.FromImage(newImage)) {
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
/* Stored procedure AddPhoto */
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[AddPhoto]
@AlbumID int,
@Caption nvarchar(50),
@BytesOriginal image,
@BytesFull image,
@BytesPoster image,
@BytesThumb image
AS
INSERT INTO [Photos] (
[AlbumID],
[BytesOriginal],
[Caption],
[BytesFull],
[BytesPoster],
[BytesThumb] )
VALUES (
@AlbumID,
@BytesOriginal,
@Caption,
@BytesFull,
@BytesPoster,
@BytesThumb )
RETURN
Wednesday, January 21, 2009
Aashish Gupta has posted a nice list of shorcuts in Visual Studio.
Here's the link:
http://smallworkarounds.blogspot.com/2008/12/visual-studio-2008-tips-tricks-for.html
Friday, January 09, 2009
How to download multiple images (/files) from SQL Server to client using ASP.NET and DotNetZip?
Here is a simple way you can use to let your web site users download multiple images or files at once. For this article, I will be focused on images but the same technique can be used for downloading files also. I will be describing how to zip all the images in a folder and send the zipped file to the client.
In my case, the images were stored in SQL Server as binary data so I had to come up with a process to first get the images out of the database and then zip them.
I was working on the Personal Website Starter kit available at
www.asp.net. It has an Album section where users can view and download pictures. The download method available in the starter kit is not very user friendly. The user has to click the “Download Photo” button which opens the image in a browser window. The user can then right click the image and do a Save Picture As…
What my method does is it zips all the images in the current album and then sends it to the client by just a click of a button. When the user clicks the Download button, she/he is presented with an “Open, Save, Cancel” message box for the download. For now, this method sends all the images in an album to the client but can be easily modified to send only the selected images or selected albums or selected files or whatever.
To summarize the steps:
1. Create temporary User Directory to store images and zipped file.
2. Get all photos by album id.
3. Store images in the folder
4. Zip the folder
5. Download the zipped file
6. Delete all temporary files and folders (optional).
To start: You should create a folder in your web site directory to store temporary images and zipped files. I created a folder named “Download” just for that.
This is how it will work. My code creates temporary directories by user names for the registered users when they try to download an album. If a user is not registered and is trying to download a public album, I create a folder using GUID so that the folder names do not interfere with each other.
Now down to business: Here’s the code:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Data.SqlClient;
using Ionic.Utils.Zip;
public partial class Photos_aspx : System.Web.UI.Page
{
int albumID = -1;
protected void Page_Load(object sender, EventArgs e)
{
albumID = Convert.ToInt32(Request.QueryString["AlbumID"]);
}
protected void DownloadButton_Click(object sender, ImageClickEventArgs e)
{
if (albumID == -1)
{
return;
}
string folderName = Server.MapPath("~/") + "\\Download\\";
// Create a temp directory for the logged in user
DirectoryInfo di = CreateUserDirectory(folderName);
// Get images from database into a dataset on webserver
DataSet ds = GetPhotosByAlbumID(albumID);
// Store the images from dataset to a folder
StoreImagesInFolder(ds, di.FullName);
// Zip contents of the folder
string fileName = ZipFolder(di.FullName);
Download(fileName);
di.Delete(true);
}
/* Create temporary User Directory to store images and zipped file. */
public DirectoryInfo CreateUserDirectory(string directoryPath)
{
// Initialize userName by GUID
string userName = System.Guid.NewGuid().ToString("N");
// If user is registered, use the new userName else use GUID
if (!string.IsNullOrEmpty(User.Identity.Name))
{
userName = User.Identity.Name;
}
string userDirectoryName = directoryPath + "\\" + userName;
DirectoryInfo di;
// Create a directory for the user
if (!Directory.Exists(userDirectoryName))
{
di = System.IO.Directory.CreateDirectory(userDirectoryName);
return di;
}
else
{
di = new DirectoryInfo(userDirectoryName);
}
return di;
}
/* Get all photos by album id */
public DataSet GetPhotosByAlbumID(int AlbumID)
{
//Initialize SQL Server connection.
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Personal"].ConnectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
using (SqlCommand command = new SqlCommand("GetPhotos", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("@AlbumID", AlbumID));
bool filter = !(HttpContext.Current.User.IsInRole("Friends") || HttpContext.Current.User.IsInRole("Administrators"));
command.Parameters.Add(new SqlParameter("@IsPublic", filter));
connection.Open();
adapter.SelectCommand = command;
DataSet dataSet = new DataSet();
adapter.Fill(dataSet, "Photos");
return dataSet;
}
}
}
/* Store images in the folder */
public void StoreImagesInFolder(DataSet ds, string folderName)
{
foreach (DataRow row in ds.Tables["Photos"].Rows)
{
// Get the image caption
string FileName = row["Caption"].ToString();
FileStream outStream;
if (FileName.Contains(".JPG") || FileName.Contains(".jpg"))
{
outStream = File.OpenWrite(folderName + "\\" + FileName);
}
else
{
outStream = File.OpenWrite(folderName + "\\" + FileName + ".JPG");
}
//Get the original image data
byte[] imageData = (byte[])row["BytesOriginal"];
//Read image data into a memory stream
using (MemoryStream ms = new MemoryStream(imageData, 0, imageData.Length))
{
ms.WriteTo(outStream);
outStream.Flush();
outStream.Close();
}
}
}
/* Zip the folder */
private string ZipFolder(string folderName)
{
// This call is just to get the Album name, you can skip this and name it anything, like may be use GUID again
System.Collections.Generic.List<Album> list = PhotoManager.GetAlbumByAlbumID(albumID);
string albumName = list[0].Caption;
//string fileName = folderName + "\\" + System.Guid.NewGuid().ToString("N") + ".zip";
string fileName = folderName + "\\" + albumName + ".zip";
using (ZipFile zip = new ZipFile("MyZipFile.zip"))
{
// add this file into the "images" directory in the zip archive
zip.AddDirectory(folderName);
zip.Save(fileName);
}
// Return zipped file name
return fileName;
}
/* Download the zipped file */
public void Download(string fileName)
{
System.IO.FileInfo file = new System.IO.FileInfo(fileName);
//-- if the file exists on the server
//set appropriate headers
if (file.Exists)
{
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(file.FullName);
Response.Flush();
Response.Close();
}
else
{
Response.Write("This file does not exist.");
}
}
}
Here's the Stored Procedure GetPhotos:
CREATE PROCEDURE [dbo].[GetPhotos]
@AlbumID int,
@IsPublic bit
AS
SELECT *
FROM [Photos] LEFT JOIN [Albums]
ON [Albums].[AlbumID] = [Photos].[AlbumID]
WHERE [Photos].[AlbumID] = @AlbumID
AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
ORDER BY [Photos].[Caption]
RETURN
If you notice, instead of using Response.End() in the Download method I have user Response.Flush() with Response.Close(). This is important if you want to delete the folders after you are done. If you want to keep all the files after sending it to the client, you can just replace those two lines with Response.End().
I hope this helps someone.
Monday, January 05, 2009
There might be other reasons for this error but this is what I found out:
You might get the error when you have a databound AJAX reorderlist and you are trying to persist the reordering using database.
The SELECT and UPDATE methods should have the same number of fields, even if they are not used in UPDATE, the signature of both the methods should be matching else you will get this error.
Here is very good article on how to use AJAX Reorderlist with ObjectDataSource by Justin Saraceno.
http://weblogs.asp.net/justinsaraceno/archive/2008/02/22/reorderlist-with-objectdatasource.aspx
Friday, January 02, 2009
Scenario - My stored procedure just returns some integer values depending on different conditions. There are no OUT or any other parameters involved for returning values from the stored procedure.
e.g.
IF (EXISTS( SELECT * FROM TableName WHERE UserId = @UserId AND RoleId = @RoleId))
RETURN(1)
ELSE
RETURN(0)
If you notice, there are no output parameters involved here. The return value can be accessed from code (C# for example), like this:
SqlParameter returnValueParam = command.Parameters.Add("@return_value", SqlDbType.Int);
returnValueParam.Direction = ParameterDirection.ReturnValue;
command.ExecuteNonQuery();
int returnValue = (int)returnValueParam.Value;
Thursday, December 25, 2008
Joe Stagner posted this very useful link for a free C# and VB coding standards reference documents by Clint Edmonson. I really appreciate Clint Edmonson's effort.
Free C# and VB Coding Standards Reference Documents