Creating a Captcha control – Part:2


In this post I will explain how to generate a hard-to-read image out of our Captcha text. The new Captcha with image will look like this:

Final Captcha image

In MyCaptcha control, each letter is different from other ones in three properties:

1- Font

2- Size

3- Distance from the next letter (character spacing)

Therefore, I wrote a class named Letter that each instance of it holds a character along with all its properties like it’s font name and size. The class has a constructor that accepts a character argument and assigns random properties to it:

public class Letter

{

string[] ValidFonts = {“Segoe Script”, “Century”, “Eccentric Std”,“Freestyle Script”,“Viner Hand ITC”};

public Letter(char c)

{

Random rnd = new Random();

font = new Font(ValidFonts[rnd.Next(ValidFonts.Count()-1)], rnd.Next(20)+20, GraphicsUnit.Pixel);

letter = c;

}

public Font font

{

get;

private set;

}

public Size LetterSize

{

get

{

var Bmp = new Bitmap(1, 1);

var Grph = Graphics.FromImage(Bmp);

return Grph.MeasureString(letter.ToString(), font).ToSize();

}

}

public char letter

{

get;

private set;

}

public int space

{

get;

set;

}

}

As you see in the above source code, I pick a random font name from ValidFonts array. The font names in ValidFonts array are Windows Vista fonts. You must keep in mind that you use font names that exist on your Web Server. I also recommend you to use fantasy fonts (like gothic) to make the produced image more hard-to-read.

I also have added a property of type Size to get the width and height of the letter when it is rendered with its own font. To get the character size I use Graphics.MeasureString method.

The ‘space’ property is set when the Captcha text is being rendered. To render the captcha image, I use a generic handler (.ashx) file. Using a generic handler we can render any output type and send it to the output stream. An .ashx file can be treated like an .aspx file but has noticeably fewer overhead. For example we can pass query strings to it and generate the output based on it.

I will send the captcha text as a query string called CaptchaText to GetImgText.ashx generic handler. In the .ashx code, I will make an instance of Letter class for each character.

var CaptchaText = context.Request.QueryString[“CaptchaText”];

if (CaptchaText != null)

{

List<Letter> letter = new List<Letter>();

int TotalWidth = 0;

int MaxHeight = 0;

foreach (char c in CaptchaText)

{

var ltr = new Letter(c);

int space = (new Random()).Next(5) + 1;

ltr.space = space;

letter.Add(ltr);

TotalWidth += ltr.LetterSize.Width+space;

if (MaxHeight < ltr.LetterSize.Height)

MaxHeight = ltr.LetterSize.Height;

System.Threading.Thread.Sleep(1);

}

As the above piece of code shows, all Letter instances are stored in letter generic list. The width of each letter plus its distance with the next letter is summarized in TotalWidth local variable. We also get the height of the biggest letter so that we get sure all letters fit in the captcha image.

I also have two constants for vertical and horizontal margins:

const int HMargin = 5;

const int VMargin = 3;

Thus, our image will have a size of VMargin+MaxHeight and HMargin+TotalWidth:

Bitmap bmp = new Bitmap(TotalWidth + HMargin, MaxHeight + VMargin);

var Grph = Graphics.FromImage(bmp);

At next step, I will draw each letter with it’s own font size and position it according to it’s space property:

int xPos = HMargin;

foreach (var ltr in letter)

{

Grph.DrawString(ltr.letter.ToString(), ltr.font, new SolidBrush(Color.Navy), xPos, VMargin );

xPos += ltr.LetterSize.Width + ltr.space;

}

Now the image is cooked and ready! We should send it to the output stream:

bmp.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

Up to now the Captcha text is sketched well but I’d like to smudge it a little more in order to make it more hard-to-read. To do is I will draw a number of circles on random positions of the image. One nice idea is to define an IShape interface with a method named Sketch(). Then define different classes that implements IShape and draws different shapes on the image.

By the way, the code that smudges the image is this:

Color[] Colors = { Color.Gray , Color.Red, Color.Blue, Color.Olive };

for (int i = 0; i < 200; i++)

{

var rnd = new Random();

var grp = Graphics.FromImage(bmp);

grp.DrawEllipse(new Pen(Colors[rnd.Next(3)]), rnd.Next(bmp.Width – 1), rnd.Next(bmp.Height – 1), 5, 5);

System.Threading.Thread.Sleep(1);

}

You can download the source code of this control from HERE. The password of archived file is: aspguy.wordpress.com

There is also a project for this control at CodePlex. You can upload any changes you might make on the source code.

Have fun with Captchaing!

Aref Karmi

9 Apr 2009

Advertisements

Creating a Captcha control – Part:1


In this post and a post after I will explain how to develop a Captcha control and use it in an ASP.NET web site.

As described in Wikipedia,  A CAPTCHA or Captcha (IPA: /ˈkæptʃə/) is a type of challenge-response test used in computing to ensure that the response is not generated by a computer. In a crude term, a captcha control shows some hard-to-read letters on the screen and asks the user to enter the text in a box. Then checks to see whether the entered text is correct or not.

There are a lot of Captcha controls for ASP.NET that you can download and use in your project but, none is as interesting as the one that you write yourself and know exactly how it works!

I will explain the techniques of writing a simple but powerful Captcha control in two posts because it is made of two parts:

  1. The captcha control that displays a text and asks users to enter text in a box then validates it.
  2. The class that renders the Captcha text as a hard-to-read image.

Because the 2nd part can be reused for different purposes, for example in your own Captcha control, I will describe it in a different part.

OK let’s get started. The Captcha control that we are going to write has the following specs:

  1. Is developed as an .ascx control so it is reusable in every ASP.NET website.
  2. Saves nothing on your hard-disk so if you open a same page in two different windows (or tabs) there will be no conflict between two Captcha controls.
  3. Is very easy to use and needs no complicated concept like understanding and using http handlers.

The only drawback that I can count about this control is that it stores the generated text in ViewState thus, you must always encrypt it.

To create this control first I new a website. Then, I add a .ascx (web user control) to it called MyCaptcha. It looks like this:

Captcha xhtml script

In the above code,  lbltext displays the captcha text. txtCpatcha is a text box in which the user must enter the code. There is also a button named btnTryNewWords that re-generates the code if user has difficulties in reading it.

The control looks like this in design mode:

c2

The control has a property named LetterCount that specifies the number of letters in the code:

public

int LetterCount { get; set; }

It also has a private property that holds the generated key in ViewState.

private

string GeneratedText{

get{

return ViewState[this.ClientID + “text”] != null ?ViewState[

this.ClientID + “text”].ToString() : null;}

set

{

// Encrypt the value before storing it in viewstate.

ViewState[this.ClientID + “text”] = value;

As commented in the above code, you are highly recommended to encrypt the key before you put it in ViewState.

To generate the captcha text I wrote a public method called TryNew() that picks random letters from a list of characters and combine them to each other:

public void TryNew()
{
char[] Valichars = {‘1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′,’0′,’a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’i’,
‘j’,’k’,’l’,’m’,’n’,’o’,’p’,’q’,’r’,’s’,’t’,’u’,’v’,’w’,’x’,’y’,’z’ };
string Captcha = “”;
int LetterCount = MaxLetterCount >5 ? MaxLetterCount : 5;
for (int i = 0; i < LetterCount; i++)
{
int index = new  Random(DateTime.Now.Millisecond).Next(Valichars.Count()-1);
Captcha += Valichars[index].ToString().ToUpper();
Thread.Sleep(1);
}
GeneratedText = Captcha;
lbltext.Text = Captcha;
}

Because the captcha control won’t be case-sensitive, there is no capital letter in ValidChars array.

You also may have noticed the Thread.Sleep(1) statement in the above code! Why should we stop the running thread for one millisecond?!

The answer is that Random class uses DateTime.Now.Millisecond as it’s default seed. If the computer is too fast and the loop that selects and combines the letters is too short (for example 5 loops only) , the loop begins and ends in a millisecond or even a shorter period of time. Therefore, you will get equal letters only. To see and feel what I mean (!) remove Thread.Sleep(1) line and you will get a text like AAAAAA or 333333.

Anyway, there is also another public property called IsValid that indicates if the entered text is equal to captcha text:

public

bool IsValid{

get

{

bool result = GeneratedText.ToUpper() == TxtCpatcha.Text.Trim().ToUpper();

if (!result)TryNew();

return result;

}

}

That’s it. Now to test the control , drag MyCaptcha.ascx and drop it on Default.aspx page.  Your .aspx page will be like this:

<

uc1:MyCaptcha ID=”MyCaptcha1″ runat=”server” />

<br />

<asp:Label ID=”lblCheckResult” runat=”server” Text=”?”></asp:Label>

<br />

<asp:Button ID=”btnCheck” runat=”server” onclick=”btnCheck_Click”

Text=”Check it!” />

in btnCehck_Click event handler, write the following piece of code:

if

(MyCaptcha1.IsValid)lblCheckResult.Text =

“It is ok” ;

else

lblCheckResult.Text =

“oops!, invalid text was entered.” ;

After running the website, you will have a captcha control like the image bellow:

c3

In the next post I will show you how to scramble the text in a way that only a human with a high eye-sight can read it 🙂

I also might add some extra codes so that it can work along with other Validation controls on the page.

Reading and writing images from/to database


Hi,
This post will show you how to save/load images to/from a database. This approach lets you do it without having to save the image on to disk. On a real hosting computer, you probably will not have write permissions. Therefore, it is sometimes vital to do image saving/loading on the fly.

In this post we will work on a database named Personnel, in which there is a table called Personnel:

create table Personnel
(
id int identity(1,1) not null primary key,
Fillname varchar(100) not null,
Picture image null
)

We are going to store out personnel’s name and picture into this table. On the application side, create a .aspx page with the following four controls:
1-a TextBox
2-a RequiredFieldValidator
3-a FileUpload control
4-a Button
5-a DataList control

Your page will look like this:

As the above image indicates, we will save each person’s full name and picture to database and the personnel information will be viewd in a DetailList control.

Behind the AddRecord button, we read the image into a Byte[] object. Then transmit the bytes to database. I strongly recommend you to use a stored procedure (if you are working with ADO.NET) because you won’t face any problems with converting bytes to string.

In Asp.NET there is a class claeed HttpPostedFile. This class lets us get full information about the file that is about to upload.  The code bellow show how we read the file:

if (FileUpload1.HasFile)
{
HttpPostedFile myFile = FileUpload1.PostedFile;
int Length = myFile.ContentLength;
string ContentType = myFile.ContentType.ToUpper();

if (Length == 0)
throw new Exception(“File size must be greater than zero!”);
if (ContentType.CompareTo(“IMAGE/PJPEG”) != 0 && ContentType.CompareTo(“IMAGE/JPEG”) != 0)
throw new Exception(“Only JPEG files are welcome!”);

Byte[] myFileBytes = new byte[Length];
myFile.InputStream.Read(myFileBytes, 0, Length);

In the above code I just allow JPEG files to be uploaded. Actually, I wanted to show you how to control the image type and infact, you can upload any file type.

As the last line of this code shows, HttpPostedFile class contains an inner stream from which we can read the image bytes. After reading the image file, we simply save it into db. I have created a stored procedure for doing this and I call this procedure from my C# code:

ALTER PROCEDURE dbo.SavePersonnel
@FullName Varchar(100),
@Picture Image

AS
Insert into Personnel (FullName,Picture) Values (@FullName,@Picture )
Return

C#:

string cnStr = ConfigurationManager.ConnectionStrings[“ConnectionString”].ToString();
using (SqlConnection connection = new SqlConnection(cnStr))
{
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = “dbo.SavePersonnel”;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue(“FullName”, txtFullName.Text.Trim());
cmd.Parameters.AddWithValue(“Picture”, myFileBytes);
connection.Open();
cmd.ExecuteNonQuery();
}

Well, now how to read the image and show it using a System.Web.UI.WebControls.Image control. Unfortunately, despite System.Drawing.Image class, ASP.NET Image class does not provide a public stream. Therefore we can not create the image content withouth an image url.

Thanks to ASP.NET Generic Handlers, we can overcome this problem easily. We may develop a .aspx or .ashx (generic handler) file and use it to read the file from database and write the image bytes into the response output stream. A generic handler (.ashx) file is much more light weight than a .aspx file. Therefore, I will develop a .ashx file. We will pass the ID of each person to this .ashx file. The generic handler then finds the person at DB, reads the image and writes it to the current HttpContext instance :

Here is the full source code of the .ashx file:

<%@ WebHandler Language=”C#” Class=”GetPersonnelImage” %>

using System;
using System.Web;
using System.Data.SqlClient;

public class GetPersonnelImage : IHttpHandler {

public void ProcessRequest (HttpContext context) {
context.Response.ContentType = “image/jpeg”;
if (context.Request.QueryString[“id”] == null || context.Request.QueryString[“id”] == “”)
return;
else
{
string cnStr = System.Configuration.ConfigurationManager.ConnectionStrings[“ConnectionString”].ToString();
using (SqlConnection connection = new SqlConnection(cnStr))
{
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = “Select Picture from dbo.Personnel Where Id=” + context.Request.QueryString[“id”];
connection.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
byte[] image = reader.GetValue(0) as byte[];
System.IO.MemoryStream ms = new System.IO.MemoryStream(image);
ms.WriteTo(context.Response.OutputStream);
ms.Flush();
context.Response.OutputStream.Flush();
}
}
}
}

public bool IsReusable {
get {
return true;
}
}
}

As is clear, we read the person’s record with a SqlDataReader and then get the image bytes using it’s GetValue method.

To let a Image control show the image we have to set it’s ImageUrl’s property in ths way:

Image img = new Image();

img.ImageUrl = “~/GetPersonnelImage.ashx?id=10″;

Inside a GridView or DataList, we can create a Template field with an Image control and bind the Image control’s ImageUrl property to the mentioned generic handler. For example:

<asp:Image ID=”Image1″ runat=”server” ImageUrl='<%#Eval(“id”,”GetPersonnelImage.ashx?id={0}”)%>’

You can download a full sample program from here. To run the project, you must have Sql Server 2005 Express edition on your machine. If you don’t have SQL Server 2005 Express, change the connection string existing in Web.config file to your own database.

Querying WHOIS datbases int ASP.NET


A while back I was involved in developing a web site for a Domain and Hosting reseller. In that project I needed to create a “Find A Domain”  section in which the customer could check to see if a domain name exists.

I made a exhaustive research and figured out that each Who is server maintains a list of certain domain types. For example,  Whois.net can whois only .COM, .NET and .ORG domains.

Many posts over the internet, including blogs.msdn.com,  also says that to query a who is database one should connect to the whois server through a TCP/IP conenction (usually via port 43).

All the above issues make Whois action fairly difficult to perform. Luckily, today I came across a very nice web site which provides a Whois SOAP web service.  To see the details of the service check this link:

http://www.webservicex.net/whois.asmx?op=GetWhoIS

This web service searches all the who is databases to look up the domain name you provide. Therefore, you will not need to search several who is databases.

To Whois a domain name, you should pass a ‘hostname’ parameter to the service:

http://www.webservicex.net/whois.asmx?Hostname=Microsoft.com

You can use this web service simply via a GET or a POST method as well as making a reference to it via Visual Studio and call its GetWhoIS metho. As I mentioned in the previous post (about REST web services), I prefer to get the who is answer using XElement.Load method. For example we may write the following method for whoising:

public static string WhoIs(string hostname)
{
XElement WhoisResult = XElement.Load(

http://www.webservicex.net/whois.asmx/GetWhoIS?HostName=microsoft.com&#8221;);
return WhoisResult.ToString();
}

Each Who is server returns a different response. Therefore, to develop a method which indicates wheather a domain name exits or not, we should look for a common string value in the WhoIS response. For example the ‘NAME SERVER’ seems to be a common string. There fore, a domain lookup function can be written this way:

public static bool IsDomainTaken(string hostname)
{
return WhoIs(hostname).ToUpper().Contains(“NAME SERVER”);
}

As I told you, this web service seems to query several WhoIS server, thus the GetWhoIS method is a little bit time consuming.

P.S. Try to Whois Microsoft.com, the result is pretty funny:

Whois Server Version 2.0

Domain names in the .com and .net domains can now be registered

with many different competing registrars. Go to http://www.internic.net

for detailed information.

MICROSOFT.COM.ZZZZZZ.MORE.DETAILS.AT.WWW.BEYONDWHOIS.COM

MICROSOFT.COM.ZZZZZ.GET.LAID.AT.WWW.SWINGINGCOMMUNITY.COM

MICROSOFT.COM.ZZZZZ.DOWNLOAD.MOVIE.ONLINE.ZML2.COM

MICROSOFT.COM.ZZZOMBIED.AND.HACKED.BY.WWW.WEB-HACK.COM

MICROSOFT.COM.ZZZ.IS.0WNED.AND.HAX0RED.BY.SUB7.NET

MICROSOFT.COM.WILL.LIVE.FOREVER.BECOUSE.UNIXSUCKS.COM

MICROSOFT.COM.WILL.BE.SLAPPED.IN.THE.FACE.BY.MY.BLUE.VEINED.SPANNER.NET

MICROSOFT.COM.WILL.BE.BEATEN.WITH.MY.SPANNER.NET

MICROSOFT.COM.WAREZ.AT.TOPLIST.GULLI.COM

MICROSOFT.COM.TOTALLY.SUCKS.S3U.NET

MICROSOFT.COM.SOFTWARE.IS.NOT.USED.AT.REG.RU

MICROSOFT.COM.SHOULD.GIVE.UP.BECAUSE.LINUXISGOD.COM

MICROSOFT.COM.RAWKZ.MUH.WERLD.MENTALFLOSS.CA

MICROSOFT.COM.OHMYGODITBURNS.COM

MICROSOFT.COM.MORE.INFO.AT.WWW.BEYONDWHOIS.COM

MICROSOFT.COM.LOVES.ME.KOSMAL.NET

MICROSOFT.COM.LIVES.AT.SHAUNEWING.COM

MICROSOFT.COM.IS.NOT.YEPPA.ORG

MICROSOFT.COM.IS.NOT.HOSTED.BY.ACTIVEDOMAINDNS.NET

MICROSOFT.COM.IS.IN.BED.WITH.CURTYV.COM

MICROSOFT.COM.IS.HOSTED.ON.PROFITHOSTING.NET

MICROSOFT.COM.IS.GOD.BECOUSE.UNIXSUCKS.COM

MICROSOFT.COM.IS.A.STEAMING.HEAP.OF.FUCKING-BULLSHIT.NET

MICROSOFT.COM.IS.A.MESS.TIMPORTER.CO.UK

MICROSOFT.COM.HAS.ITS.OWN.CRACKLAB.COM

MICROSOFT.COM.HAS.A.PRESENT.COMING.FROM.HUGHESMISSILES.COM

MICROSOFT.COM.FILLS.ME.WITH.BELLIGERENCE.NET

MICROSOFT.COM.CAN.GO.FUCK.ITSELF.AT.SECZY.COM



Bye for now.

Working with AWS S3 through C#


A while ago I needed to use AWS S3 (the Amazon’s cloud-based file storage) to store some files and then download them or get their listings through C#. As ironic as it sounds I noticed that there was no .NET implementation nor a documentation for S3 so I decided to create a file repository in C# which lets .NET developers access S3 programmatically.

Here is a rundown as to how you would work with AWS S3 through C#:

In order to use any APIs of Amazon Web Services (AWS) you will have to add the nugget package that is provided by Amazon. Simply bring up the Nuget Package Manager window and search for the keyword AWS. The first item in the search result is most likely AWS SDK for .NET which must be installed before you can access S3.

 

 

Once the SDK is installed we will have to find the properties of our S3 bucket and place it somewhere in web.config (or app.config) file. Normally these three properties of the S3 bucket is required in order to access it securely:

 

  1. Secret key
  2. Access key
  3. Region end point

These details will be provided to you by your cloud administrator. Here is a list of region end points that you can place in your configuration file (e.g. us-west-1)

 

Region name

Region

Endpoint

Location constraint

Protocol

US Standard *

us-east-1

You can use one of the following two endpoints:

  • s3.amazonaws.com (Northern Virginia or Pacific Northwest)
  • s3-external-1.amazonaws.com (Northern Virginia only)

(none required)

HTTP and HTTPS

US West (Oregon) region

us-west-2

s3-us-west-2.amazonaws.com

us-west-2

HTTP and HTTPS

US West (N. California) region

us-west-1

s3-us-west-1.amazonaws.com

us-west-1

HTTP and HTTPS

EU (Ireland) region

eu-west-1

s3-eu-west-1.amazonaws.com

EU or eu-west-1

HTTP and HTTPS

EU (Frankfurt) region

eu-central-1

s3.eu-central-1.amazonaws.com

eu-central-1

HTTP and HTTPS

Asia Pacific (Singapore) region

ap-southeast-1

s3-ap-southeast-1.amazonaws.com

ap-southeast-1

HTTP and HTTPS

Asia Pacific (Sydney) region

ap-southeast-2

s3-ap-southeast-2.amazonaws.com

ap-southeast-2

HTTP and HTTPS

Asia Pacific (Tokyo) region

ap-northeast-1

s3-ap-northeast-1.amazonaws.com

ap-northeast-1

HTTP and HTTPS

South America (Sao Paulo) region

sa-east-1

s3-sa-east-1.amazonaws.com

sa-east-1

HTTP and HTTPS

 

In order to avoid adding the secret key, access key and region endpoint to the <appSettings> part of your configuration file and to make this tool more organised I have created a configuration class for it. This configuration class will let you access the <configurationSection> element that is related to S3. To configure your app.config (or web.config) files you will have to add these <sectionGroup> and <section> elements to your configuration file:

 

<configSections>

<sectionGroup
name=AspGuy>

<section
name=S3Repository
type=Aref.S3.Lib.Strategies.S3FileRepositoryConfig, Aref.S3.LiballowLocation=true
allowDefinition=Everywhere />

</sectionGroup>

</configSections>

The
S3FileRepositoryConfig
class is inherited from
ConfigurationSection
class and has properties that map to some configuration elements of your .config file. A sample configuration for S3 is like this:

 

<AspGuy>

<S3Repository


S3.ReadFrom.AccessKey=xxxxxxxxxx


S3.ReadFrom.SecretKey=yyyyyyyyyyyyyyyyy


S3.ReadFrom.Root.BucketName=-bucket-name-


S3.ReadFrom.RegionName=ap-southeast-2


S3.ReadFrom.RootDir=“”>

</S3Repository>

</AspGuy>

Note that <AspGuy> comes from the name property of <sectionGroup name=”AspGuy”> element. Also <S3Repository> tag comes from the name of <section> element. Each property of S3FileRepositoryConfig
is mapped to an attribute of <S3Repository> element.

Apart from SecretKey, AccessKey andBucketName you can specify a root directory name as well. This setting is there so you can begin accessing the S3 bucket from a specific folder rather than from its root, and obviously this setting is optional. For example imagine there is a bucket with the given folder structure:

  • Dir1
  • Dir1/Dir1_1
  • Dir1/Dir1_2

If you set the RootDir property to “” then when you call the GetSubDir methods of the S3 file repository if will return “Dir1” because Dir1 is the only top-level folder in the bucket. If you set the RootDir property to “Dir1” and then call the GetSubDirs method you will get two entries which are “Dir1_1” and “Dir1_2”.

Here is the code of the configuration class mentioned above:

using System.Configuration;

 

namespace Aref.S3.Lib.Strategies

{


public
class
S3FileRepositoryConfig : ConfigurationSection

{


private
const
string S3ReadFromAccessKey = “S3.ReadFrom.AccessKey”;


private
const
string S3ReadFromSecretKey = “S3.ReadFrom.SecretKey”;


private
const
string S3ReadFromRootBucketName = “S3.ReadFrom.Root.BucketName”;


private
const
string S3ReadFromRegionName = “S3.ReadFrom.RegionName”;


private
const
string S3ReadFromRootDir = “S3.ReadFrom.RootDir”;

 

[ConfigurationProperty(S3ReadFromAccessKey, IsRequired = true)]


public
string AccessKey

{


get { return (string) this[S3ReadFromAccessKey]; }


set { this[S3ReadFromAccessKey] = value; }

}

 

[ConfigurationProperty(S3ReadFromSecretKey, IsRequired = true)]


public
string SecretKey

{


get { return (string) this[S3ReadFromSecretKey]; }


set { this[S3ReadFromSecretKey] = value; }

}

 

[ConfigurationProperty(S3ReadFromRootBucketName, IsRequired = true)]


public
string RootBucketName

{


get { return (string) this[S3ReadFromRootBucketName]; }


set { this[S3ReadFromRootBucketName] = value; }

}

 

[ConfigurationProperty(S3ReadFromRegionName, IsRequired = true)]


public
string RegionName

{


get { return (string) this[S3ReadFromRegionName]; }


set { this[S3ReadFromRegionName] = value; }

}

 

[ConfigurationProperty(S3ReadFromRootDir, IsRequired = true)]


public
string RootDir

{


get { return (string) this[S3ReadFromRootDir]; }


set { this[S3ReadFromRootDir] = value; }

}

}

}

 

For the repository class I have created an interface because of removing the dependency of clients (e.g. a web service that may need to use with various file storages) on S3. This will let you add your implementation of file system, FTP and other file storage types and use then through dependency injection. Here is the code of this interface:

namespace Aref.S3.Lib.Interfaces

{


public
interface
IFileRepository

{


void Download(string fileName, string targetPath);


void ChangeDir(string relativePath);


IEnumerable<string> GetFileNames(string pattern);


IEnumerable<string> GetSubdirNames(string startRelativeFolder = “”);


void AddFile(string localFilePath);


bool FileExists(string relativeFileName);


void DeleteFile(string relativeFileName);

}

}

 

In this interface:

  • Download: Downloads a file hosted on S3 to disk.
  • ChangeDir: Changes the current directory/folder to the given directory. If the new directory (relativePath parameter) starts with / then the path will be representing an absolute path (starting from the RootDir) otherwise it will be a relative path and will start from the current directory/folder.
  • GetFileNames: Retrieves the file names of the current folder
  • GetSubDirNames: Retrieves the name of folders in the current folder
  • AddFile: Uploads a file to S3
  • FileExists: Checks to see if a file is already on S3
  • DeleteFile: Deletes the file from S3

The implementation of these method are quiet simple using AWS SDK for .NET. The only tricky part is that S3 does not support folders. In fact in S3 everything is a key-value pair and the structure of entries is totally flat. What we do however is to use the forward slash character to represent folders and then we use this character as a delimiter to emulate a folder structure.

Here is the source code of S3 File Repository. You can clone the repository of this code which is on GitHub to play with the code. Feel free to send a pull request if you want to improve the code. The GitHub repository is located at https://github.com/aussiearef/S3FileRepository

 

 

 

 

 

 

Querying a database using Linq and Reflection


Hi,

With Insert, Update and Delete methods but without a Select method, LinqDataSource control looks just like a chair with only three legs! Such a powerful and flexible control is used to get connected to a DataBound control like GridView, while it could excel in many scenarios if it had a Select method! For example, it was great if we could write such a code:

LinqDataSource1.TableName=’students’;

LinqDatasource1.Where = ‘Grade<5’;

var x= LinqDataSource1.Select();

Anyway, in order to develop a special component, that I am gonna describe it in a separate post later, I needed to query a Table using Linq to Sql and the table’s string name. In ADO.NET territory, we may create a dynamic string query and execute it over the database:

const string TableName = ‘students’;

string Query = String.Format(‘Select * from {0} ‘, TableName);

But, how to query the Student table with Linq? Better to say, how does LinqDataSource probably work? The question is fairly easy, but before explaining it, I invite you to be informed that Linq has come to let us query in a strongly typed fashion! Thus, only in rare situations you might need to query a database in an untyped manner.

Anyway, first we have to get to know which Assembly is already running. In a Console or Windows application we may simply find this by calling Assembly.GetExecutingAssembly() method. But, in a Web application, things are different. In an ASP.NET application classes are compiled into App_config.dll assembly. ASP.NET uses shadow copy mechanism to let an ASP.NET application get updated while it is executing. In fact, ASP.NET copies every .DLL file in the bin directory to ” Temporary ASP.NET Files “ folder and name them with strange , long and unreadable (!) names. For example App_Code.Dll file might be named “App_Code.7vkubplh.dll” ! Therefore, we have to search all loaded assemblies for the required type.

As a result, we need the following code to get all assemblies loaded inside the current Application Domain:

List<Assembly> asmList =  AppDomain.CurrentDomain.GetAssemblies().ToList();

Since DataContext class provides required methods, we actually don’t need to find concrete DataContext classes. But if for any reason you need to find them, the best way is to find for classes that have been decorated with DatabaseAttribute attribute:

var AllDataContext = from C in asmList

from P in C.GetTypes()

from J in P.GetCustomAttributes(true)

where J.GetType().Name == “DatabaseAttribute”

select P;

Well, In order to query a table, you have to Add a DataContext to your application and drag your desired table on to  it. Luckily, since each Linq To Sql entity is a class, we can not have two different tables with the same name. Therefore,  the only job to do is to query a type with your table name:

Type table = (from C in asmList

from P in C.GetTypes()

where P.Name == “user”

select P).Single();

This code looks up all loaded assemblies and checks to see which one is named “user”. “user” is actually the table name. Since we are sure only one “user” class exists, we have used Single extension method.

Well, now that we have found the class, we should create an instance of DataContext class and call it’s non-generic GetTable method:

DataContext dc = new DataContext(” a connection string comes here”);

List<object> Records = dc.GetTable(table).Cast<object>().ToList();

The above code converts the resulting table to List<object> but it is not necessary indeed.

Well, the records are ready. You can assign “Records” variable to a GridView to see the results :

GridView1.DataSource = Records;

GridView1.DataBind();

If you would like to get the field values individually, you should obtain all public property names, loop over them and call GetValue on each one:

Table tbl = new Table();

// Loop over records

foreach (var s in dc.GetTable(table))

{

TableRow row = new TableRow();

// Retrieve all instance (non-static) and public properties.

PropertyInfo[] pList = s.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

// Loop over properties

foreach (PropertyInfo p in pList)

{

TableCell cell = new TableCell();

object temp = p.GetValue(s, null);

cell.Text = temp != null ? p.GetValue(s, null).ToString() : “-“;

row.Cells.Add(cell);

}

tbl.Rows.Add(row);

}

this.Controls.Add(tbl);

Well, in the above code I have converted all the values to String but be reminded that this method won’t work for Boolean fields.

Hope this article be a bit of help 🙂

Aspguy

Speed up Linq to Sql with compiled queries


There is no doubt that tehre are some drawbacks to Linq to Sql. One of them is that the Sql statement is built dynamically so it is needed to be parsed and compiled each time you run it. Fortunately .Net 3.5 has a solution for this problem. System.Data.Linq namespace includes a class named CompiledQuery which is responsible for caching the compiled version of a Linq to Sql query. This class has a static method called Compile which takes a Func<T,S,R> delegate. In this signature, T is the type of a DataContext (i.e. HRMDataContext) , S is the type of a predicate to filter the query and R is the type of returned result. Needless to say that it must be IQueryable<T>.

In this article we will see how to pre-compile a query, its limitations and how it really improves the speed of a Linq query.

To pre-compile a query we must define a public static field of type Func<T,S,R> . What we assign to this field is the result of CompiledQuery.Compile method:

public static Func<testDataContext , SearchCriteria, IQueryable<Person>> FilteredResult …

In the above line, testDataContex is the type of a DataContext inside the project, SearchCriteria is type of a class or struct that is designed for passing search criteria to .Compile method. For example, suppose that in testDataContext, we have a Table named Person. We have also defined a class (or struct) named SearchCriteria as bellow:

public class SearchCriteria
{
public int id { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
}

Now to get these definitions to work with a precompiled query we can write such a statement:

public static Func<testDataContext , SearchCriteria, IQueryable<Person>> FilteredResult =
System.Data.Linq.CompiledQuery.Compile(
(testDataContext dc , SearchCriteria criteria ) =>
from p in dc.Persons
where (p.id == criteria.id || criteria.id == -1)
&& (p.FirstName == criteria.FirstName || criteria.FirstName == string.Empty)
&& (p.LastName == criteria.LastName || criteria.LastName == string.Empty)
select p
);

That’s it. At this point, FilteredResult contains a pre-compiled query and can be used this way:

testDataContext dc = new testDataContext();
SearchCriteria criteria = new SearchCriteria();
criteria.id = -1;
criteria.FirstName = “Bill”;
criteria.LastName = “Gates”;
List<Person> p = FilteredResult(dc, criteria).ToList();

The above code creates instances of testDataContext (dc) and SearchCriteria (criteria) and passes them to FilteredResult as arguments. The result of FilteredResult is IQueryable<Person> we have called .ToList() extension method to get a List<Person> series.

One upsetting point about pre-compiled queries is that you can not use a stored-procedure to make a compiled query. In the above Linq to Sql code, if you write “from C in usp_GetPerson() …” you will get an error indicating that stored procedures are not allowed to be used.

Now let’s see how much precompilation can be helpful. I have written a small Console application that runs two version (one is compiled and one is not) of a query over a database for 1000 times. The time needed to run each query is as follows:

Compiled query takes 0 minutes, 1 seconds and 62 milliseconds.

Regular query takes 0 minutes, 13 seconds and 328 milliseconds.

As it is clear, the compiled query is greatly faster than a regular query. Notice that in a Linq model, nothing will really happen unless we iterate over the result of the query. Therefore, I have written a foreach statement to iterate over the result of queries. I also have written a small query at the beginning of the program to make Linq manager open a connection to Sql Server. If we do not do this, the compiled query will surprisingly takes longer!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace CompiledQuery
{
class Program
{
public static Func<testDataContext , SearchCriteria, IQueryable<Person>> FilteredResult =
System.Data.Linq.CompiledQuery.Compile(
(testDataContext dc , SearchCriteria criteria ) =>
from p in dc.Persons
where (p.id == criteria.id || criteria.id == -1)
&& (p.FirstName == criteria.FirstName || criteria.FirstName == string.Empty)
&& (p.LastName == criteria.LastName || criteria.LastName == string.Empty)
select p
);

static void Main(string[] args)
{
testDataContext dc = new testDataContext();
SearchCriteria criteria = new SearchCriteria();
IQueryable<Person> Q = null;

// The following code makes Linq manager to open a connection to Sql Server
var init = from p in dc.Persons select p;
foreach (Person person in init) ;

criteria.id = -1;
criteria.FirstName = “Bill”;
criteria.LastName = “Gates”;
DateTime BeginTime = DateTime.Now;

for (int i = 0; i < 1000; i++)
{
Q = FilteredResult(dc, criteria);
foreach (Person person in Q) ;
}

DateTime EndTime = DateTime.Now;
TimeSpan Diff1 = EndTime – BeginTime;

BeginTime = DateTime.Now;

for (int i = 0; i < 1000; i++)
{
Q = from p in dc.Persons
where (p.id == criteria.id || criteria.id == -1)
&& (p.FirstName == criteria.FirstName || criteria.FirstName == string.Empty)
&& (p.LastName == criteria.LastName || criteria.LastName == string.Empty)
select p;
foreach (Person person in Q) ;
}

EndTime = DateTime.Now;
TimeSpan Diff2 = EndTime – BeginTime;

Console.WriteLine(“Compiled query takes : {0}:{1}:{2}”, Diff1.Minutes, Diff1.Seconds, Diff1.Milliseconds);
Console.WriteLine(“Regular query takes {0}:{1}:{2}”, Diff2.Minutes, Diff2.Seconds, Diff2.Milliseconds);

Console.ReadKey();
}
}
}

You can download the source of of a full sample project from here.