Friday, September 26, 2008

How to get rid of the alert "The following module was built either with optimizations enabled or without debug information"

If you have a solution in Visual Studio which consists of both web- and class library projects, then you might get an alert box with the following message:


"The following module was built either with optimizations enabled or without debug information:

....

To debug this module, change its project build configuration to Debug mode. To suppress this message, disable the 'Warn if no user code on launch' debugger option."

Do this to get rid of the alert:
1. Right click the project giving the alert, choose "Properties".
2. Choose "Build" and then "Advanced..."
3. Set Debug info to "full".

Now the alert should be gone.

Response.Redirect not working within an UpdatePanel?

If you get an exception when doing a Response.Redirect within an UpdatePanel then you are most probably missing the following lines in your web.config:

<httpModules>
  <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>

Sunday, September 7, 2008

FCKEditor 2.x: How to add a new button with custom javascript to the toolbar

In this tutorial we will have a look at how to add a new button with custom javascript to a FCKeditor toolbar. In this example our custom button will simply open a link in a new window when it's clicked.

1. Start by finding the "plugins" folder which is located below the "fckeditor\editor" folder.
2. Create a new folder, name it "openurl".
3. Add an icon within the "openurl" folder, name it "openurl.gif".
4. Create a new file within the "openurl" folder, name it "fckplugin.js", and add the following code:


// Our method which is called during initialization of the toolbar.
function OpenUrl()
{
}

// Disable button toggling.
OpenUrl.prototype.GetState = function()
{
 return FCK_TRISTATE_OFF;
}

// Our method which is called on button click.
OpenUrl.prototype.Execute = function()
{
 window.open('http://www.kindblad.com');
}

// Register the command.
FCKCommands.RegisterCommand('openurl', new OpenUrl());

// Add the button.
var item = new FCKToolbarButton('openurl', 'Open URL');
item.IconPath = FCKPlugins.Items['openurl'].Path + 'openurl.gif';
FCKToolbarItems.RegisterItem('openurl', item);

5. Now we need to define where we want our button to be shown in the toolbar. Open up "fckeditor\fckconfig.js" and look for:


FCKConfig.ToolbarSets["Default"] = [
 ['Source'],
 ['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'], 
 ...

Add 'openurl' anywhere in the toolbar definition, e.g.:


FCKConfig.ToolbarSets["Default"] = [
 ['openurl,'Source'],
 ['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'], 
 ...

6. And lastly, we need to tell FCKeditor to load our plugin, we do this by finding the following string in the "fckeditor/fckconfig.js".

FCKConfig.PluginsPath = FCKConfig.BasePath + 'plugins/' ;

Add the following code below the line above:

FCKConfig.Plugins.Add('openurl');

That's it.

FCKeditor 2.x: How to get an instance of the editor using javascript

This is how you get an instance of the editor when you are within the page that loads the editor:


FCKeditorAPI.GetInstance([instanceName]);

E.g.:


var editor = FCKeditorAPI.GetInstance('ctrArticle');

And this is how you get the editor instance when you are inside the editor instance:


var editor = FCK;

And lastly, this is how you get the name (DOM id) of the editor instance (get the instance using either of the methods above):


alert(editor.Name);

Monday, August 18, 2008

How to convert from string to enum using C# and generics

In order to convert from a string to an enumeration in .NET you can use the method Enum.Parse as follows:


public enum SortExpressions
{
 FirstNameAsc,
 FirstNameDesc,
 LastNameAsc,
 LastNameDesc
}

var value = "lastnameasc";
var sortExpression = (SortExpressions) Enum.Parse(typeof(SortExpressions), value, true);

Since this operation is often needed we should make a ConvertToEnum method so we can reuse it. But instead of returning it as the typical object type, we should rather use generics to return it as the actual type:


/// 
/// Converts a string to the specificed enumeration.
/// 
public T ConvertToEnum(string value, T defaultEnum)
{
 try
 {
  return (T) Enum.Parse(typeof(T), value, true);
 }
 catch
 {
  return defaultEnum;
 }
}

A try/catch is used instead of the method Enum.IsDefined as it's case-sensitive.

And this is how you can use our new ConvertToEnum method:


var value = "lastnameasc";
var sortExpression = ConvertToEnum(value, SortExpressions.FirstNameAsc);

Wednesday, June 4, 2008

Handling comma separated strings in stored procedures

Imagine you have a user interface with a list of products. On the side of each product you have a delete checkbox and then a delete button below the list. Even though a user can delete multiple products at once, you only want to query the database once. One way to achieve this is by sending a comma separated string with product id's to a stored procedure. The stored procedure will then loop through the string, grab each id and delete the corresponding row in the product table.

Here's a stored procedure which does this:


CREATE PROCEDURE DeleteProducts
(
 @values varchar(8000)
)
AS
BEGIN
 SET NOCOUNT ON;

 declare @value int
 declare @pos1 int
 declare @pos2 int

 -- Append , at the end of string.
 if substring(@values, len(@values), 1) <> ','
 begin
  set @values = @values + ','
 end

 -- First position.
 set @pos1 = 1
 set @pos2 = charindex(',', @values, 1)

 while (@pos1 > 0 and @pos2 > 0)
 begin
  set @value = cast(substring(@values, @pos1, @pos2 - @pos1) as int)

  delete from Product
  where ProductId = @value;

  -- Next position.
  set @pos1 = charindex(',', @values, @pos1) + 1
  set @pos2 = charindex(',', @values, @pos1)
 end
END

And this is how you would execute it:


exec DeleteProducts '1,20,30,100,250,1000';

Monday, May 12, 2008

Extending IDataReader implementations using extension methods

In my post How to extend classes using extension methods, I write about how to extend classes with your own methods. This time we will extend the IDataReader interface with some new methods to save some typing. Since we extend the interface, our methods will be available in all the classes implementing the IDataReader interface, such as the SqlDataReader.

The IDataReader interface provides methods for getting field values for a given type:


string email = reader.GetString(0);

The problem with these methods are that they only accept the index-position and not the field name. Instead, I would prefer to write the code above like this:


string email = reader.GetString("Email");

In order to do this, we need to create a new static class, which defines some new extension methods:


using System;
using System.Data;

/// 
/// Provides extension methods for the IDataReader interface.
/// 
public static class IDataReaderExtension
{
 public static bool GetBoolean(this IDataReader reader, string name)
 {
  return (bool) reader[name];
 }
 public static Guid GetGuid(this IDataReader reader, string name)
 {
  return (Guid) reader[name];
 }
 public static int GetInt(this IDataReader reader, string name)
 {
  return (int) reader[name];
 }
 public static double GetDouble(this IDataReader reader, string name)
 {
  return (double) reader[name];
 }
 public static string GetString(this IDataReader reader, string name)
 {
  return (string) reader[name];
 }
 public static bool IsDBNull(this IDataReader reader, string name)
 {
  if (reader[name] == DBNull.Value)
   return true;

  return false;
 }
}

Since we didn't put our static class within a namespace, then our extension methods will be available at once. However, if you want to use a namespace, then you need to import the namespace in every class where you want to use these extension methods.

Sunday, May 11, 2008

How to add reflection to texts, shapes and pictures in Powerpoint 2007

Text reflection:
1. Start by adding some text to your Powerpoint slide.
2. Select the text you want to add reflection to.
3. Click on the tab Format.
4. Select Text Effects, then Reflection and choose the reflection variant you prefer.

Shape reflection:
Same as text reflection, but choose Shape Effects instead.

Picture reflection:
Same as text reflection, but choose Picture Effects instead.

Sunday, May 4, 2008

How to extend classes using extension methods

In .NET 3.5 there is a new functionality called extension methods. Extension methods let you extend any classes in the .NET framework, 3rd party frameworks or your own frameworks with your own methods. Let's look at an example where we extend the System.String class with two new methods, to get the first five and last five characters of a string:

public static class StringExtension
{
 /// 
 /// Returns the first five characters of a string.
 /// 
 public static String GetFirstFiveCharacters(this String myString)
 {
  return myString.Substring(0, 5);
 }
 /// 
 /// Returns the last five characters of a string.
 /// 
 public static String GetLastFiveCharacters(this String myString)
 {
  return myString.Substring(myString.Length - 5, 5);
 }
}

In the example above, we use a class with the name StringExtension. However, you can name this class whatever you like: StringExtension, StringMethods, StringHelper, Helper etc. The only important thing is that your methods follow the pattern for extension methods:


public static  MethodName(this  variableName)

Now, let's produce some code using our extension methods:


String helloWorld = "Hello World";
String hello = helloWorld.GetFirstFiveCharacters(); // contains Hello
String world = helloWorld.GetLastFiveCharacters(); // contains World

Of course, extension methods are shown in the intellisense in Visual Studio.

Thursday, May 1, 2008

The C# using statement

In C#, when you want to make sure an object is disposed, then you might place you're code within a try finally block as follows:
SqlCommand command = new SqlCommand();
try
{
 command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
 command.CommandText = "delete from dbo.Customer;";
 command.Connection.Open();
 command.ExecuteNonQuery();
}
finally
{
 command.Dispose();
}
However, a nicer and shorter way of writing the exact same code is by using the using statement as follows:
using (SqlCommand command = new SqlCommand())
{
 command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
 command.CommandText = "delete from dbo.Customer;";
 command.Connection.Open();
 command.ExecuteNonQuery();
}
The using block will only work with objects of classes implementing the IDispose interface. In the case of the SqlCommand used in the code above, the Dispose method closes the database connection if it's open and clears any resources used.

Wednesday, April 30, 2008

How to write to the Windows event log using .NET

In the .NET framework you have the System.Diagnostics.EventLog class which provides static methods for working with the Windows event log.

In order to write a new entry to the event log, you can use the WriteEntry method as follows:

using System.Diagnostics;

...

EventLog.WriteEntry("My Application", "My message", EventLogEntryType.Error);

The EventLogEntryType enumeration has the following members: Error, FailureAudit, Information, SuccessAudit, Warning.

If the event source "My Application" doesn't exist, then the WriteEntry method will try to create it. However, if the current process runs under a non-admin account, then this may fail due to lack of permissions. In that case, you can create a console application, which creates the event source by using the CreateEventSource method:

using System;
using System.Diagnostics;

namespace CreateEventSource
{
 class Program
 {
  static void Main(string[] args)
  {
   if (args.Length == 0)
   {
    Console.WriteLine("The event source name is required as an argument.");
    return;
   }
   
   string source = args[0];
   
   try
   {
    if (!EventLog.SourceExists(source))
    {
     EventLog.CreateEventSource(source, "Application");
     Console.WriteLine("The event source {0} was successfully created.", source);
    }
    else
    {
     Console.WriteLine("The event source {0} already exists.", source);
    }
   }
   catch(Exception ex)
   {
    Console.WriteLine("The event source {0} was not created due to: \n{1}", source, ex.ToString());
   }
  }
 }
}

During installation of your application, you run this console application to register the necessary event source(s). Make sure you are logged in as the admin user when you run it.

Monday, April 28, 2008

Kuler from Adobe Labs

In need of some new colors for my blog, I started searching for a color schema tool and then I came across Kuler from Adobe Labs. As of this writing there are more than 46 000 color schemas available, organized by tags, names, popularity and rating. All of them are created by the Kuler users.

Saturday, April 26, 2008

Create a global progress bar for your ASP.NET AJAX applications

In ASP.NET AJAX you can use the UpdateProgress control to display a progress bar for asynchronous page updates. This control needs to be attached to a single UpdatePanel. If you need a consistent progress bar throughout your application, you will thus need to add one UpdateProgress control for every UpdatePanel control. Since this is not an ideal solution, then instead of using the UpdateProgress control, we can create our own progress bar by attaching a method to the beginRequest and endRequest event of the PageRequestManager class, which toggles the visibility of a div-container with an animated image. Have a look at the example below.

1. Start by adding a div-container with the following image to your master-page or web form:

<div><img alt="Progress bar" src="http://www.kindblad.com/wp-content/uploads/2008/04/progressbar.gif" /></div>

2. Add this to your stylesheet file:

#ProgressBar
{
 background: #FFFFFF;
 width: 300px;
 height: 100px;
 border: 1px solid #928F8F;
 position: absolute;
 display: none;
 z-index: 99999998;
}
#ProgressBar img
{
 position: relative;
 left: 43px;
 top: 38px;
}

3. Now we need a method to show and hide the progress bar. Add the following javascript code, make sure you add it below the ScriptManager control:

<script type="text/javascript">
// Toggles the visiblity of the progress bar.
function toggleProgressBar()
{
 var progressBar = $get('ProgressBar');

 if (progressBar.style.display == 'none' || progressBar.style.display == '')
 {
  // Show.
  // Center the progressbar.
  var bounds = getWindowBounds();
  progressBar.style.top = (bounds.y / 2) - 50 + 'px';
  progressBar.style.left = (bounds.x / 2) - 150 + 'px';
  progressBar.style.display = 'block';
 }
 else 
 {
  // Hide.
  progressBar.style.display = 'none';
 }
}
// Returns the height and width of the current window.
function getWindowBounds()
{
 var bounds = {x: 0, y: 0}
 if (self.innerHeight)
 {
  // All except Internet Explorer.
  bounds.x = self.innerWidth;
  bounds.y = self.innerHeight;
 }
 else if (document.documentElement && document.documentElement.clientHeight)
 {
  // Internet Explorer strict mode.
  bounds.x = document.documentElement.clientWidth;
  bounds.y = document.documentElement.clientHeight;
 }
 else if (document.body)
 {
  // Internet Explorer.
  bounds.x = document.body.clientWidth;
  bounds.y = document.body.clientHeight;
 }
 return bounds;
}

// Attach the ToggleProgressBar method.
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(toggleProgressBar);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(toggleProgressBar);
</script>

That's it.

Monday, April 14, 2008

GUID vs. int (Uniqueidentifier vs. identity

I got interested in GUID's when I saw it was used in the ASP.NET membership database schema. At the first glance, 0D40FC92-4F1D-42D1-9A9B-860526C21FF0 didn't seem very nice, but eventually I realized how flexible and effective the GUID datatype is. So let's have a look at why you should use it instead of identities (int)
Let's start by identifying the problems with identity columns (int):
- By default, inserting values into identity columns are not allowed.
- If you try to copy data from one database to another, the identity value is most probably a duplicate as it's already present in the target database.
- No way to know the identity value beforehand until the row is actually inserted into the table.
Using GUID's solves all this:
- In 99,99% of the cases a GUID is unique, due to this you won't see the same value in the target database.
- Since a GUID can be generated in the application layer, like in .NET, it can be generated at any time, even before it's inserted into the database.
So what are the disadvantages of GUIDs'?
- Less readable than int and doesn't look nice in URL's. As a solution to the latter you can use url-rewriting.
- Requires more storage as they are 16 bytes in size instead of 4 bytes for int. But for my own experience I haven't noticed any performance difference when switching to GUID, they perform really well.
To generate a new GUID using MS-SQL Server you use the newid() method, and in .NET you use the GUID.NewGUID().
Since there is no similiar method to scope_identity() or @@identity when using GUID's, then the best way is to generate the value in a stored procedure or in your application code, instead of having newid() as the default value for your GUID-column.

Saturday, April 12, 2008

How to store files in a MS-SQL Server database using ASP.NET

In this post we will take a look at how to store data in a MS-SQL Server database using ASP.NET. We will start by creating the database table in which we will store the actual file data, and then create a new Web Form with a file upload control and an upload button which will save the uploaded file to the database. After that we need to create a generic HTTP Handler which will be responsible for flushing out the file to the client. The reason to why we will use a HTTP Handler for this is that we don't need all the functionality that the System.Web.UI.Page provides, so having both performance and simplicity in mind a HTTP Handler is a better choice.

1. Start by creating a table named File in your database, add the following fields to it:

2. Create a new Web Form, give it the name UploadFile.aspx and add the following code:


C#:
<%@ Page Language="C#" AutoEventWireup="false" CodeFile="UploadFile.aspx.cs" Inherits="UploadFile" %>
<!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>Upload file</title>
</head>
<body>
    <form id="form1" runat="server">
 <asp:FileUpload runat="server" ID="ctrFile" /> <asp:Button ID="btnUploadFile" runat="server" Text="Upload" />
 <asp:HyperLink runat="server" ID="ctrResult" Target="_blank" />
    </form>
</body>
</html>

VB.NET:
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="FileUpload.aspx.vb" Inherits="FileUpload" %>
<!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>Upload file</title>
</head>
<body>
<form id="form1" runat="server">
 <asp:FileUpload runat="server" ID="ctrFile" /> <asp:Button ID="btnUploadFile" runat="server" Text="Upload" />
 <asp:HyperLink runat="server" ID="ctrResult" Target="_blank" />
</form>
</body>
</html>

UploadFile.aspx.cs:


C#:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;

/// 
/// Handles uploading- and storing a file in a database.
/// 
public partial class UploadFile : System.Web.UI.Page
{
 protected override void OnInit(EventArgs e)
 {
  base.OnInit(e);

  btnUploadFile.Click += new EventHandler(btnUploadFile_Click);
 }
 void btnUploadFile_Click(object sender, EventArgs e)
 {
  // exit if file-upload has no file
  if (!ctrFile.HasFile) return;
  
  // generate new fileId
  Guid fileId = Guid.NewGuid();
  // create insert query
  using (SqlCommand command = new SqlCommand())
  {
   command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
   command.CommandText = @"insert into [File](FileId, FileName, FileType, FileSize, FileContent) 
      values(@FileId, @FileName, @FileType, @FileSize, @FileContent)";
   command.Parameters.Add("@FileId", SqlDbType.UniqueIdentifier).Value = fileId;
   command.Parameters.Add("@FileName", SqlDbType.NVarChar, 100).Value = Path.GetFileName(ctrFile.PostedFile.FileName);
   command.Parameters.Add("@FileType", SqlDbType.NVarChar, 100).Value = ctrFile.PostedFile.ContentType;
   command.Parameters.Add("@FileSize", SqlDbType.Int).Value = ctrFile.PostedFile.ContentLength;
   // filecontent, convert from stream to byte array
   byte[] fileContent = new byte[ctrFile.PostedFile.ContentLength];
   ctrFile.PostedFile.InputStream.Read(fileContent, 0, ctrFile.PostedFile.ContentLength);
   command.Parameters.Add("@FileContent", SqlDbType.VarBinary, -1).Value = fileContent;
   command.Connection.Open();
   command.ExecuteNonQuery();
  }
  // show result
  ctrResult.NavigateUrl = "FileStream.ashx?FileId=" + fileId.ToString();
  ctrResult.Text = "Click here to view the uploaded file";
 }
}

VB.NET:

Imports System Imports System.Configuration Imports System.Data Imports System.Data.SqlClient Imports System.IO ''' ''' Handles uploading- and storing a file in a database. ''' Partial Class UploadFile Inherits System.Web.UI.Page Protected Sub btnUploadFile_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUploadFile.Click ' exit if file-upload has no file If Not ctrFile.HasFile Then Exit Sub ' generate new fileId Dim fileId As Guid = Guid.NewGuid() ' create insert query Dim command As New SqlCommand() Try command.Connection = New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString) command.CommandText = "insert into [File](FileId, FileName, FileType, FileSize, FileContent)" _ & "values(@FileId, @FileName, @FileType, @FileSize, @FileContent)" command.Parameters.Add("@FileId", SqlDbType.UniqueIdentifier).Value = fileId command.Parameters.Add("@FileName", SqlDbType.NVarChar, 100).Value = Path.GetFileName(ctrFile.PostedFile.FileName) command.Parameters.Add("@FileType", SqlDbType.NVarChar, 100).Value = ctrFile.PostedFile.ContentType command.Parameters.Add("@FileSize", SqlDbType.Int).Value = ctrFile.PostedFile.ContentLength ' filecontent, convert from stream to byte array Dim fileContent(ctrFile.PostedFile.ContentLength) As Byte ctrFile.PostedFile.InputStream.Read(fileContent, 0, ctrFile.PostedFile.ContentLength) command.Parameters.Add("@FileContent", SqlDbType.VarBinary, -1).Value = fileContent command.Connection.Open() command.ExecuteNonQuery() Finally command.Dispose() End Try ' show result ctrResult.NavigateUrl = "FileStream.ashx?FileId=" + fileId.ToString() ctrResult.Text = "Click here to view the uploaded file" End Sub End Class

3. Create a new Generic Handler (available under Add New Item > Generic Handler), give it the name FileStream.ashx and add the following code:


C#:
<%@ WebHandler Language="C#" Class="FileStream" %>
using System;
using System.Web;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

/// 
/// Reponsible for flushing out the file from the database to the user.
/// 
public class FileStream : IHttpHandler
{
    public void ProcessRequest (HttpContext context)
    {
 // get the file id
 Guid fileId = new Guid(context.Request.QueryString["FileId"]);

 using (SqlCommand command = new SqlCommand())
 {
  // get the file from database
  command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
  command.CommandText = "select * from [File] where FileId = @FileId";
  command.Parameters.Add("@FileId", SqlDbType.UniqueIdentifier).Value = fileId;
  command.Connection.Open();
  SqlDataReader reader = command.ExecuteReader();
  if (reader.Read())
  {
   // flush out the binary data to the user
   context.Response.Clear();
   context.Response.ContentType = (string) reader["FileType"];
   context.Response.AddHeader("Content-Disposition", String.Format("inline;filename={0};", reader["FileName"].ToString()));
   context.Response.AddHeader("Content-Length", reader["FileSize"].ToString());
   context.Response.BinaryWrite((byte[]) reader["FileContent"]);
   context.Response.End();
  }
 }
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

VB.NET:

<%@ WebHandler Language="VB" Class="FileStream" %> Imports System Imports System.Web Imports System.Configuration Imports System.Data Imports System.Data.SqlClient ''' ''' Reponsible for flushing out the file from the database to the user. ''' Public Class FileStream : Implements IHttpHandler Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest ' get the file id Dim fileId As New Guid(context.Request.QueryString("FileId")) Dim command As New SqlCommand() Try ' get the file from database command.Connection = New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString) command.CommandText = "select * from [File] where FileId = @FileId" command.Parameters.Add("@FileId", SqlDbType.UniqueIdentifier).Value = fileId command.Connection.Open() Dim reader As SqlDataReader = command.ExecuteReader() If reader.Read() Then ' flush out the binary data to the user context.Response.Clear() context.Response.ContentType = reader("FileType").ToString() context.Response.AddHeader("Content-Disposition", String.Format("inline;filename={0};", reader("FileName").ToString())) context.Response.AddHeader("Content-Length", reader("FileSize").ToString()) context.Response.BinaryWrite(DirectCast(reader("FileContent"), Byte())) context.Response.End() End If Finally command.Dispose() End Try End Sub Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class

4. Run your code, upload a file using UploadFile.aspx, and then click on the hyperlink "Click here to view the uploaded file" to view the uploaded file.

Tuesday, April 8, 2008

Select random rows from a MS-SQL Server table

Imagine you have a Product table, where you need to get a list of say 5 random products. This is how you can do it:
select top 5 *
from Product
order by newid();
So what actually happens is that newid() returns a new GUID/unique identifier for every row in the result set, it then sorts based on the GUID value and then eventually selects the 5 top most rows.

Sunday, March 16, 2008

Solving the Windows Vista disk-read/write issue

After installing Windows Vista for the first time a few months back, I had a problem with it intensively reading and writing to my hard drives. Not only did it make me worried about the lifetime of my disks, but the sound from it was crazy.

After doing some research I found the following settings to solve the problem and increase the performance:

Disable automatic restore points:

  • Click the Start-menu and right click “Computer”, choose “Properties”.
  • Click on “System Protection” in the left pane
  • Uncheck all disks in the “Automatic restore points” pane.
  • Click OK.

Disable "file-indexing for better search":

  • Open Windows Explorer.
  • Navigate to each disk and right click, choose “Properties”.
  • Uncheck “Index this drive for faster searching”.
  • Click OK.

Disable the “Superfetch” service":

  • Click the Start-menu and right click “Computer”, choose “Manage”.
  • Expand “Services and Applications”
  • Click on “Services”.
  • Scroll down to the service “Superfetch”, right click and choose “Properties”.
  • Set “Startup type” to “Disabled”, then click OK.
  • Make sure the status of the service is empty or “Stopped”, otherwise right click it and choose “Stop”.

Sunday, February 17, 2008

How to avoid naming collisions in C#

In order to avoid naming collisions in C# you can use a namespace- or class alias.

When making a new instance of the ArrayList class you would usually write:


using System.Collections;

...

ArrayList data = new ArrayList();

However, if you already have another namespace imported with an ArrayList class you would get a naming conflict. To solve this you can add a namespace alias:


using Lists = System.Collections;

...

Lists.ArrayList data = new Lists.ArrayList();

You could also have a class alias like this:


using List = System.Collections.ArrayList;

...

List data = new List();

Monday, February 4, 2008

Storing files on the disk vs. database


Until recently I have been a fan of storing files, uploaded through my web applications, on the disk. However lately I find myself moving more towards storing the files in the database as it's more flexible and easier to maintain. Below are some pros and cons.

Storing files on the disk:
Pros:

  • Performance - faster to retrieve files from the disk than a database.
  • Anyone having access to the disk can read and modify files, no need for an additional interface.

Cons:

  • Harder to implement security on single files.
  • Time consuming to do backups when there are thousands of files.


Storing files in a database:
Pros:

  • Web/database-farm support - easy to keep two or more databases up to date through replication.
  • Handling security is a cake - when getting the file use join/exists to query the user/role table to check for read access, if no read access return nothing.
  • More convenient to have all the data located in a single database file.

Cons:

  • Performance - one or more queries against the database are needed in order to get the file, 20 images on a webpage means 20+ queries. Network traffic can also become a bottleneck if the database is running on a seperate server.
  • Cost - on shared webhosts, database space is usually more expensive than diskspace.

Conclusion:If you need security checks, replication and don't want thousands of files on your disks, store the files in a database, otherwise store it on the disk.

Saturday, January 12, 2008

Ctrl+S in Visual Studio closes the web.config file

For some reason Visual Studio 2008 started closing my web.config file whenever I pressed Ctrl+S to save. First I thought it might be a new VS2008 "feature" but no, it turns out to be a bug in the ADO.NET Entity Framework Designer. Solution: uninstall ADO.NET Entity Framework Tools Preview or wait for a fix.

A T-SQL script to search all the columns in a database for a given string

This T-SQL script lets you search through all the columns (nchar, nvarchar, ntext) in a MS-SQL Server database for a given string. Simply change the DbName to your database name and set the @SearchValue to the string you want to search for. The script will return a resultset for each hit, with tablename, column where it found the search-string and all the other columns in that row.

Here's the code:


-- Change the name below to the database you want to search in.
use dbname;

set nocount on;

declare @TableName nvarchar(200)
declare @SchemaName nvarchar(200)
declare @ColumnName nvarchar(200)
declare @Sql nvarchar(4000)
declare @SearchValue nvarchar(200)
declare @Count int

-- Change the value below to the value to search for.
set @SearchValue = '%searchstring%'

-- Get a list of schema, table, column.
DECLARE Items

CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
select s.Name as SchemaName, t.name as TableName, c.name as ColumnName
from sys.tables t
inner join sys.schemas s on t.schema_id = s.schema_id
inner join sys.columns c on t.object_id = c.object_id
where c.user_type_id in (167, 175, 239, 99, 35, 231)
OPEN Items
FETCH NEXT FROM Items
INTO @SchemaName, @TableName, @ColumnName

WHILE (@@FETCH_STATUS = 0)
BEGIN
 -- Execute a count(*) select in order to only return results with 1 or more hits.
 set @Sql = 'select @Count = count(*) from [' + @SchemaName + '].[' +  @TableName + '] where [' + @ColumnName + '] like ''' + @SearchValue + ''';'

 exec sp_executesql @sql, N'@Count int output', @Count output

 if @Count > 0
  begin
   -- Return result with tablename, hit column, * columns.
   set @Sql = 'select ''' + @TableName + ''' as TableName, ' + @ColumnName + ', *'
   set @Sql = @Sql + ' from [' + @SchemaName + '].[' + @TableName + ']'
   set @Sql = @Sql + ' where [' + @ColumnName + '] like ''' + @SearchValue + ''';'
   execute sp_executesql @sql
  end

  FETCH NEXT FROM Items
  INTO @SchemaName, @TableName, @ColumnName
 END
END

CLOSE Items
DEALLOCATE Items