Feeds:
Posts
Comments

Hi All,

I recently received a review about MyCaptcha control in CodePlex that proposed a couple of improvements in the source code.  This review indicates that :

  1. Thread.Sleep is not a good way to ensure that unique characters are selected for teh Captcha text.
  2. Sending the Captcha text to rendering component (.ashx file) is insecure.

Based on the above objections, I modified the source code and re-uploaded it to Codeplex. The modifications are as follows:

First, I removed Thread.Sleep thing from MyCaptcha.ascx.cs and replaced it with a do {..} while (…) loop to ensure that no letter is duplicate:

char newChar = (char)0;
do
{
newChar = Char.ToUpper(Valichars[new Random(DateTime.Now.Millisecond).Next(Valichars.Count() - 1)]);
}
while (Captcha.Contains(newChar));
Captcha += newChar;

To improve security when passing the Captcha text to rendering component (GetImgText.ashx) to ways come to my mind:

  • To include text generation logic into .ashx file
  • To encrypt captcha text before passing it to .ashx file.

As I mentioned before, generating a random text should not be depended on the way we display it. Therefore I don’t like mingling up the two codes. So I added some code to use a Symmetric algorithm to encrypt/decrypt Captcha text.

Thus, I added a new static class called SecurityHelper which includes two encryption and decryption methods . Symmetric algorithms  require a 16-letter key. Therefore I added a private property to give back the key. This key is optional and you can change it to whatever you would like:

private static byte[] SymmetricKey
{
get
{
return  Encoding.UTF8.GetBytes(“1B2c3D4e5F6g7H81″);
}
}

This post is too short to include the body of EncryptString and DecryptString methods. You can download the source code and see to it.

Back to MyCaptcha.ascx.cs , we need to use SecurityHelper.EncryptString to encrypt Captcha text before passing it to GetImgText.ashx generic handler:

ImgCaptcha.ImageUrl = “GetImgText.ashx?CaptchaText=” + SecurityHelper.EncryptString(Captcha);

We also need to change GetImgText.ashx.cs to make it decrypt QueryString value:

var CaptchaText = SecurityHelper.DecryptString(
Convert.FromBase64String(context.Request.QueryString["CaptchaText"]));

This will make sure that nobody can sniff the captcha text. If you get the Captcha image properties in your browser, it will look like this:

http://localhost:51093/MyCaptcha/GetImgText.ashx?CaptchaText=V1rX8fZjL%2f8ghm1ZkCCsRoTryWDde8tJ7sejoIjoJKA%3d

I also tried to make the text more hard-to-read and a bit prettier so I changed the GetImgText.ashx file to draw an image background for Captcha. Background images come from /images/captcha folder so you need to create such a folder in your web site or modify the source code to point to an appropriate location. I have also added three sample background images, like a Valentine Day one:

vday

try other background images and decide which one do you like the most.

Please visit CodePlex page of this project and download the source code.

When you design a modular ASP.NET application, soon or later you will need to think about adding extensibility features to your project so that it will be possible to add new modules at runtime.  There are a few architectures and designs that let you develop an extensible application, like ASP.NET MVP. However, many of them add a lot of complexity almost to everything and one should learn many concepts to use them.  Therefore, it’s a good idea to use other simple but innovative methods like the one I will explain bellow.

The method I am going to mention lets you develop an ASP.NET application and add some more modules to it later at runtime. In a nutshell, it has the following benefits:

  1. Allows adding new pages to an existing web application at runtime and does not need any recompilation.
  2. Allows adding new web parts to an existing content management system (Portal) at run-time.
  3. Several developers can develop different parts of an application.
  4. It is very easy to understand, develop and use.
  5. Does not exploit any 3rd party library so nothing is needed except Visual Studio.

And it has the following drawbacks:

  1. One should know the exact structure of an existing ASP.NET application, like folder hierarchies.
  2. May not cover all possible scenarios (Actually I have not taught about many scenarios).

How to implement it?

The design I am going to explain is possible only if you develop an ASP.NET Web Project rather than an ASP.NET web site.  As far as I remember, visual studio 2005 does not let you create a web project. If I am right, you need to use Visual Studio 2008. However, there are two main parts that we need to develop:

  • A web application project that includes main modules, main pages, and loads plugged modules, checks licensing, perform security tasks etc.
  • Plugged modules, which will add more pages, web parts and functionalities.

Main application and modules must match. It means that they must have same structure (i.e. folders), use same master pages and follow same rules.

The main reason that I used a Web Application Project, rather than a Web Site, was the benefits of a Web Application Project for developing a plug-in based web site. After building a web application project, there will be one assembly and several .aspx, .ascx, .ashx … files. After the web application is published, there is possibility to add more pages and files to it. Therefore, if at a later time we add several .aspx pages along with their .dll files, the web application will be able to work with those pages with no problem.

When developing the main application, you should consider a well formed directory structure, language specific contents, master pages etc. For example, your application should have a master page with a general name, like Site.Master. It also needs to maintain each module’s pages in a separate folder so that new modules can follow the same rule and avoid naming conflicts etc.

To develop the main application, follow the steps bellow:

  1. Create an empty solution in VS 2008.
  2. Add a new ASP.NET Web Project (not a web site) to the solution.
  3. Add any required folders like App_Themes and implement any required authentication, authorization and personalization mechanisms. Your web application must be complete and working.
  4. Add a master page to the web application project and name it Site.Master or another general name.
  5. Add a new Class Library Project and call it Framework (i.e. mycompany.myproject.Framework), common or whatever name that indicates this class library will be shared between the main application and dynamic modules.
  6. Add a new interface to the mentioned class library and call it IModuleInfo. This interface will be implemented with a class inside any pluggable module and will return root menu items that must be added to main application’s menu (or items to be added to a site navigation). It also can return a list of WebParts that introduces web parts that exist inside the module.

public interface IModuleInfo

{

List<MenuItem> GetRootMenuItems(string[] UserRoles);

}

UserRoles parameter is not mandatory. It shows that you can pass parameters to the method that returns a module’s main menu items. In this example, it indicates which Roles the current user has so that menu items will be filtered properly.

  1. Add a new ASP.NET Web Application project to the solution and name it SampleModule.
  2. Add a folder called SampleModule and if necessary, add more sub-folders.
  3. Add a web.config file to SampleModule folder and define which users/roles can access which folder.
  4. Add a master page named Site.Master. In fact , it must have same name with your master page in the main application.
  5. Add a public class with any name (I call it ModulePresenter) that implements IModuleInfo (this interface was added to Common or Framework library).

ModulePresnter class will return a list me menu items to main application. Main application will add those menu items as root items to its main menu afterwards. I will not bring a detailed code for the part that a module creates these items; it is dependent on your project.

public class ModulePresenter : IModuleInfo

{

#region IModuleInfo Members

public List<System.Web.UI.WebControls.MenuItem> GetRootMenuItems(string[] UserRoles)

{

List<MenuItem> items = new List<MenuItem>();

//:

//:

return items;

}

#endregion

}

  1. Compile this application and go back to the main application.
  2. Add an XML file and call it PluggedModules.xml. This file maintains the qualified type name of each module that must be loaded. A qualified type name includes assembly, namespace and class name

<?xml version=”1.0″ encoding=”utf-8″ ?>

<modules>

<module name=”SampleModule” type=” SampleModule.ModulePresenter, SampleModule.dll”></module>

</modules>

  1. Write a code to query PluggbedModules.xml, get menu items and attach them to main menu:

public static void LoadModules(Menu menuControl , string[] userRoles, string xmlName)

{

XDocument document = XDocument.Load(HttpContext.Current.Server.MapPath(string.Format(“~/{0}” , xmlName)));

var allModules = document.Elements(“modules”);

foreach(XElement module in allModules.Elements())

{

string type = module.Attribute(“type”).Value;

IModuleInfo moduleInfo = Activator.CreateInstance(Type.GetType(type)) as IModuleInfo;

List<MenuItem> allItems = moduleInfo.GetRootMenuItems(userRoles);

foreach(MenuItem item in allItems)

{

menuControl.Items.Add(item);

}

}

}

As seen in the above code, we query PluggedModule.xml file , extract introduced files and create an instance of it using Activator.CreateInstance method. Then extract IModuleInfo implementation, call GetRootMenuItems to get module’s menu items and add it to main menu.

After doing all the above steps, copy modules .dll file (generated after you build the project) to main application’s \bin folder and add it’s main folder (SampleModule) to main application’s root folder. It will work fine until all naming matches (for example both use master pages with a same name) and when specifying target URL in menu items, they point to a relative path, i.e. SampleModule/MyPage.aspx.

Please download the sample code from here.

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

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.

Desktop Sharing!

In some applications, there is a need to desktop/application sharing, whiteboard etc. Microsoft Office Communications Server 2007 is a great solution for you in case you need Video Conferencing, Desktop/App. sharing, whiteboard and so on. Of course, only MSCS R2 Web Access which can be installed on a x64 OS is suitable for web-based desktop sharing.

Since MSCS is a sort of expensive server and it will make your customer to pay an arm and a leg to purchase required licenses, you may need a simpler and cheaper solution. For instance, in a web-based Learning Management System (LMS) application, there was a need to enabled desktop sharing for teachers. Only teachers would share their desktop and there was no mutual interaction  between the instructor and learners. As you may guess, the customer could not afford the cost of MSCS licenses.

To answer this need, I used Microsoft Media Services and Microsoft Media Encoder. Using these two services, the instructor was able to capture his/her computer’s screen and broadcast it over the network so that students could see what he/she was doing.

What you need:

1- Windows 2003 Server

2- Windows Media Encoder

3-Windows Media Player

To install Windows Meddia Services, on the computer which should be your streamign server, go to Control Panel -> Add Remover Programs -> Add/Remove Windows Component. Then at the buttom of  Windows Component Wizard dialogbox, check  Windows Media Services checkbox and click OK.

windows_media_srv

After installing Windows Media Services, you need to configure it. There are two things that should be configured:

  1. Authentication
  2. Protocol Control

Go to Administrative Tools ->Windows Media Services snap-in. Then click on the name of server computer and navigate to Properties tab. Find Authentication and open properties of each authentication method (if availible). Specify who can access this service and grant each user or group proper access rights.

authorization

Logically, students should have Read access but Teachers should have Create and Write access along with Read access because a teacher pushes the media content to media server.

At the next step you should enable control protocol and configure it. If your server is configured as a web server and has IIS installed, IIS is likely to occupy port 80. Therefore, you need to specify another open HTTP port thorough which Windows Media Encoder can push media content to server. If port 80 is used, WMS Http control protocol is disabled. right-click on it and choose Enabled item. Afterwards, open properties window and specify a new port number as shown in the picture bellow:

controlprotocol1

At this stage Windows Media Services is configured and ready to use.

On each instructor’s client computer, install Windows Media Encoder. To begin broadcasting, run it and from New Session window, go to Quick Starts tab and choose Broadcast Company meeting (then click next).

New Session Window

Then Windows Media Services Publishing Point window is appeared. In this window, enter server IP or name along with the Port number you specified in WMS Http Control Protocol window. You must also specify a name for your publishing point. For example, VisualC#1 !

Publishing point windowBy clicking on OK button, Windows Media Encoder begins and Properties window is seen. If not, click on “Properties” button on toolbar. In this place, for Video, choose Screeen Capture. You can click on Configure button and tell Windows Media Encoder how to capture your computer screen. Available options are: Entire Screen, Region or Window.

If you wish to broadcast your computer’s audio, enable Audio and select your preferred audio device.

Also, for “At End” option, choose “Stop”!

Properties window

At the next step go to Output tab, and uncheck these two options:

  1. Pull from encoder
  2. Archive file

Output

After doing this, go to Compression tab and from Destination drop-down, choose Windows Media Server option. Then from the Video drop-down control, select “Screen Capture (CBR)”. You can also change the Bit rate. The higher Bit tare meand the higher quality but slower transmition.

Compression

Ok! This process might be a little complicated and hard to memorise. No worries, go to File menue and save your configuration. You can provide your saved configuration file to your teachers and ask them to simply double-click on the file to begin recording (except they should change the name of publishing point)!

The Publishing Point name must be generated by your application and shown to the instructor to be used in Windows Media Encoder and also should be used in the client’s viewer for connecting to media server.

Clients can visit the streamed video by Windows Media Player. The protocol used for watching streamed videos is MMS, like http! for example , we may use mms://videoserver/myvideo

At the above address, Videoserver is server’s name and MyVideo is the publishing point name.

To create the client’s viewer we need to embed Windows Media Player ActiveX into our .aspx page. Visit this address to see how this is done:

http://www.mioplanet.com/rsc/embed_mediaplayer.htm

After embeding, URL parameter must be set properly. The best way is to write a function (with Internal access modifier) to generate the url and bind it to URL parameter:

<PARAM NAME=”URL” VALUE=”<%=GetMMSURL()%>”>

Each time the instructor begins broadcasting, students can open their viewing page and watch the deskop of their teacher! The teacher can display his/her desktop, open an application and show it (like in a Demo session) or open Microsoft Paint and use it as a white board!

The approach above is a one-way method unless you provide a facility for clients to send text messages to teacher and ask questions. However, for low incomers, this should be a reliving way of desktop viewing :-)

oops.. today I’d decided to post a new article but surprisingly noticed that the blog was suspended! Thanks to Matt, it is alive and kicking now!

Anyway, lets see how we can generate a log visit report for our ASP.NET web site. By the term of Log Visit, I mean the statistics of a website which shows at which time, which page (or file) has been viewed by who!

The good news is that IIS can record the above information for us. It can log all activities done by your web site in the following ways and formats:

W3C Extended log file format

World Wide Web Consortium (W3C) Extended format is customizable and is saved in an ASCII text file. You can select your desired fields among a lot of choices.

IIS log file format

IIS log file format has  fixed columns and is stored as an ASCII text file. This file includes more information than W3C format.

NCSA Common log file format

National Center for Supercomputing Applications (NCSA) Common log file format is a fixed ASCII format that is available for Web sites, but not for FTP sites

ODBC logging

Open Database Connectivity (ODBC) logging format is a record of a fixed set of data properties in a database.

Logging into text files is quicker than logging into a database. It does not have any performance pitfall but when it comes to reporting, you probably should import the text file into a database.

Logging by ODBC will slow down your website to some extent  because it records very much of (sometimes unnecessary) information. For example, in W3C format, only information about pages who have been loaded successfully is stored. While in ODBC method, all referred objects, like .js or image files, are recorded, no metter if the resource have been loaded successfully or not.

By the way, since ODBC will make this post shorter, I will choose ODBC method for my sample program.

To enable logging with ODBC, first you must create a table for storing log information and then create an ODBC data source thorough which IIS can store logs.

To create the log table, which is usually called INETLOG, go to System32\InetSrv folder and find LogTemp.Sql file. This file includes a script that creates the required table into your database. This script has been written for Sql Server, but you can modify it to be executed on other databases like MS Access or even My Sql.

In the next step, create a SYSTEM DNS that points to the above table. You must create a System DNS because IIS will use the DNS with a user different from the one you have logged into your computer (usually NetWork Service account).

To create a new System DSN, go to Control Panel-> Administrative Tools and then double-click Data Sources (ODBC) . Then, go to System DNS tab and click Add. Select SQL Server, enter the name of your server and database and specify a user/password. You would better enter a SQL SERVER login (do not choose Windows Authentication) and specify a password that will not be changed.

After doing so, change the default database of this DSN to the database that logging table resides on. Click OK and close the dialog box.

Now go to Control Panel -> Administrative Tools  and double-click on Internet Information Services Manager.

Open Web Sites, and then find your Virtual Directory or Web Site. Right-click on it, choose properties and under the Home Directory tab, find Enable Logging check box. Enable the check box and In the Active log format list box, select ODBC. Afterwards, click on Configure button to view the ODBC settings. In this dialog box, enter the name of ODBC DSN you created in the previous step, name of the table (inetlog), user name and password of logging data base.

For example:

ODBC: WordPressLogDSN

Table: InetLog

Login: sa

Password: 123

In the above sample I used “SA” SQL SERVER’s default login name. This is a risky job and I do not recommend you do it! You would better use a user name with no administrative permission which only has access to logging table or database.

From now on, any visit to a page will be recorded!

NOTICE: The logging table will be filled with tons of records, therefore, I strongly recommend you to store InetLog table on a seperate FileGroup. Also, You would better to schedule a script that removes unnecessary records from inetlog table.

Writing The Code

In the rest of the post I am going to write a sample page that displays how many times each .aspx or .html page has been visited. I will show the stats in numeric and bar chart format.

As I mentioned, data about any referred resources will be stored in InetLog table. Thus, we should be able to determine if a record belongs to a Page or not. Only pages whose ServiceStatus is equal to 200 have been loaded or access with no error. So, I need a Sql function that determines if a resource is a page (i.e. .aspx) and if it has been accessed successfully.

I will call the function IsPage. The code is very simple so I just bring the script body here:

create function IsPage(   @PageName varchar(200) )
returns int
begin
Declare @len int
set @len = len(@PageName)

if Substring(@PageName, @Len, 1) = ‘/’
set @PageName = Substring(@PageName,1,@Len-1)

Declare @Extension  Varchar(4)
Set @Extension = Upper(Substring(@PageName,@Len – 3 , 4))

if @Extension = ‘ASPX’ or @Extension = ‘HTML’
return 1
return  0
end

I will use this function to create my stats and also to remove records of non-page resources like .js files (if I don’t need them).

At the next step I will write a stored procedure that determines how many times each page has been visited. To let the script run on older versions of Sql Server, I have written it as simple as possible:

create procedure rep_LogVisit
@BeginDate smalldatetime,
@EndDate smalldatetime
as
select Count(1) as FileCount, target as PageName
from inetlog
where ServiceStatus = 200 and dbo.isPage(target) =1
and LogTime>=@BeginDate and LogTime<=@EndDate
group by dbo.GetFileName(target)
go

As the above code indicates, rep_LogVisit counts the records who’s ServiceStatus equals to 200 (successful) , the resource is a page and the log has been recorded between a given date.

In order to display the result, I use a GridView control, having two columns. One for the page name, and one for the visit count:

<asp:GridView ID=”GridView1″ runat=”server” AutoGenerateColumns=”False”

CellPadding=”4″ ForeColor=”#333333″

GridLines=”None”>

<Columns>

<asp:BoundField DataField=”target” HeaderText=”Page Name” />

<asp:TemplateField HeaderText=”Visit Count”>

<ItemTemplate>

<asp:Panel runat=”server” ID=”divBar” style=”background-color:Red” Width=’<%#GetLength((int)Eval(“TotalCount”)) %>’>

<asp:Label runat=”server” ID=”lblCount” text=’<%#Eval(“TotalCount”) %>’ ForeColor=”White”></asp:Label>

</asp:Panel>

</ItemTemplate>

</asp:TemplateField>

</Columns>

</asp:GridView>

Well, I will call  rep_LogVisit stored procedure, bind the grid to it’s result. I also have to write a function called GetLength in order to calculate the lenth of each bar:

int MaxCount = 0;

protected void Page_Load(object sender, EventArgs e)

{

if (!IsPostBack)

{

SqlConnection conn = new SqlConnection(“Your Connection String Here”);

SqlCommand cmd = conn.CreateCommand();

cmd.CommandType = CommandType.StoredProcedure;

cmd.CommandText = “rep_LogVIsit”;

// Add date parameters here. skipped to simplify the code.

DataTable table = new DataTable();

SqlDataAdapter adapter = new SqlDataAdapter(cmd);

adapter.Fill(table);

// Get the bigger visit count

MaxCount = (int)(from C in table.AsEnumerable()

select C).Max(c=>c["TotalCount"]);

GridView1.DataSource = table;

GridView1.DataBind();

}

}

// Calculate the length of each bar

internal int GetLength(int TotalCount)

{

if (MaxCount == 0)

return 0;

else

return Convert.ToInt32(Math.Round(((double)TotalCount / MaxCount)*300));

}

At run-time, you will see something like the image bellow:

untitled1

I haven’t written here for a while because I was involved in a job not related directly to ASP.NET development. In fact, I was consulting a small company to build up a software product line based on a standard software development process (i.e. MSF) and industry best practices. This might look a little bit weird but believe me it happens a lot that a small company asks a software developer to do such a job and save money!!

The job urged me to write something about how to build up a small software product line or how to work on a software project following standard guidelines. It may be hard to believe, but I personally have seen a lot of companies, in various sizes, that do not have any strategy for their configuration management, requirement management and so on. Especially, small businesses suffer from this issue a lot but most of them frequently change their developers because the manager believes that developers do not work well! Some other ones know about the importance of having a well defined software development process but believe that they can’t afford the cost of hiring consultants or purchasing the tools. This post will show you up that software development can be organized perfectly with minimum cost and a little effort.

Begin with Standards

Whether you are going to launch a new project or you are maintaining an old application, you need some standards for coding conventions, database naming, coding principals, testing and so on. If you do not have any standards, the code your developers write will be very hard to understand and hard to maintain by other ones.  Naming standards also can help you develop some automation tools because you can assume that some conditions are always met. For example, you can always be sure that the primary key field of each table is named “ID”.  Standards should be granular, clear and short as much as possible. A very long and dense standard document is very hard to read, memorize and understand. For example, create some standard documents for the following subjects:

  • C# (or other language that you use) naming conventions
  • Database objects naming conventions
  • UI standards
  • C# design and coding standards and guidelines
  • Database design standards and guidelines

It is very important that you supervise that standards are always followed by team members. There are several tools that you can use to see if standards are correctly used. For instance,  StyleCop can integrate with Visual Studio and analyze source code for standards. See  this link for more info: http://code.msdn.microsoft.com/sourceanalysis

It is highly recommended to create coding and other standards with cooperation of all team members. There are also several web resources about coding and design standards that you can refer to. Something that I personally did was to download and study some sample source code from Microsoft website and checked to see what kind of naming conventions have been used in them.

Setup a domain for your office!

It is recommended to have a domain-based internal network for your office.  Without a domain you can not control the software or servers you setup. Big organizations often setup a domain, or a secondary domain, for their software development  section.

Setup an internal mail server

The office I told you about, the one which I worked on the promoting their software development process, used to exchange their internal documents or messages thorough external email accounts (i.e. Gmail) . There is no point in sending internal valuable information included in internal documents out of the company! Therefore, it is much better to set up an internal email server, i.e. Microsoft Exchange Server, and use it for internal communications. If you don’t have money (!) , setup a free pop3 mail server like hMail , or even use Windows 2003 POP3 service for simply send/receive emails.

Use Source Control

Never ever develop source codes in an uncontrolled environment. Even a single developer, should use a sort of soruce control program. For example, if I modify a .cs file and damage the code for some reason, with a source control program, like SubVersion, I can rollback the changes.  For small to medium projects or offices, I recommend to use SubVersion, which is a free source control program that supprots many important features like versioning and branching. If you have several product lines, projects and you have money! , I highly recommend you to install and use Team Foundation Server. TFS has great features for pushing a software development process, including a source control system. The default TFS client is Visual Studio (Team Explored) but there are other 3rd party clients so that if you are not using .NET , you don’t have to forget TFS.

Apply a standard software development process

There are several software development processes that I can not sat which one is better than the others because the value of each one is revealed due to the context of your projects, the size of your company, your budget and etc… The important note is that you should choose a SW development process that complies with CMMI, like RUP and MSF. CMMI is a kind of standard for software development process and has five levels. If you manage to install and supervise a CMMI-matching process completely , you are likely to be a CMMI Level 3 !

I personally prefer MSF (Microsoft Solution Foundation) since despite RUP, which is extremely comprehensive and suites large organizations, MSF has different versions for Agile software development and CMMI improvement that takes you from CMMI Level 3 to Level 5 seamlessly. Also, Team Foundation Server works based on MSF-based processes so that you won’t need to think about a software to make the process running.

MSF is actually a framework that let’s you design and customize your own MSF-based process. Therefore, you can create a process that best matches your needs, create custom process templates and build your project portal based on it.

Regardless of the process instance you chose for your company, you should be aware that you take the following subjects into account:

1.       Configuration Management : How your source codes are maintained, how you grant or deny access to users, how you organize different branches of source code and …. For example if you release first version of a product, you label and call it “1″. Then until you release the 2nd version, you create a branch called “2″ for service packs. New features are added to “1″ but urgent changes and bug fixes are performed on “2″. When you are ready to release the 2nd version you merge “1″ and “2″.

2.       Requirement Management : It means how you get your customer’s and business analysts’ needs, discuss and filter them and send them to development team.

3.       Project Management : How you create tasks, plan your project, control that the project is on time, and how you close it.

4.       Testing : Defines your rest strategy, test scenario and …

5.       Deployment :  Also called Release Management. Tells us how to prepare deployment environment, how to build deployment packages and etc.

6.       Maintenance and Customer Support : This item is usually included in Retirement Management but, I believe Customer Support is a vast and independent subject.

In some cases , you would better develop your own software to control the projects, create and assign tasks, manage requirements and be in touch with customers.

Always put your customized document templates somewhere accessible to team members with sufficient privileges.

Control internet access!

Developers and other team members need to be connected to internet because today’s software development requires searching for answers over the internet. But how you provide internet connectivity to your developers? If I was you, I would never used Internet Connection Sharing! Instead, I highly and strongly recommend to use Internet Security and Acceleration (ISA) server. With an ISA server you can protect your network with a firewall system, provide internet access via a web proxy, restrict or deny access to certain users, monitor the network resources and get reports. For example, you can block access to entertainment websites , like MySpace, or prevent team members to upload certain file types , like .CS and keep your confidential information safe.

If you have money, use Microsoft ISA Server 2006 or Microsoft Forefront . If you do not have money, use an open source ISA-like server.

Conclusion

Launching a development team requires some concidetations, no matter your project or company is too small or too large. In this post I poited to some of them and told you how to do something urgent about them.

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.

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”);
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.

At the time of writing this post, .NET has no specific facility to work with REST services. Though, some services over the web provide information in REST format. For example, http://www.geonames.org (that provides gegraphic information) has a lot of free web services to get geographical information. The other day, I needed to use these services to let the end user choose his/her country and then state from two drop-down lists. So I had to figure out how to consume such services. In this post we will use the following service as an case-study:

http://ws.geonames.org/countryInfo?lang=it&country=DE

If you navigate to this link you will get the following result:

As is seen, the resulting XML is pretty straight forward.  With knowing that REST web services work with GET and POST methods, it is nearly nothing except working with xml!

For example, to query a REST service, like the one I mentioned above, we can use LINQ’s XML functionality.  The XElement class (declared in System.Linq.XML) provides a Load method that can retrieve an XML data from a url with GET  method:

XElement rootXml = XElement.Load(“http://ws.geonames.org/countryInfo?lang=it&country=DE”);

var Countries = from C in rootXml.Elements()
select new { Code = (string)C.Element(“countryCode”),
Name = (string)C.Element(“countryName”) };
foreach (var x in Countries)
Console.WriteLine(“{0}  {1}”, x.Code, x.Name);
Console.ReadKey();

After retrieveing the full xml, you can extract any kind of information you want. no matter how complex is it!

Adding or modifying information using POST method is a bit more complex. First we have to obtain a channel by which we may POST the information. Then we have to create an instance of data entity in XML format. Finally we have to POST data through the channel.

To get access to REST service we use a HttpWebRequest since it lets use the POST method and let us specify the type of information we are posting.

HttpWebRequest channel = (HttpWebRequest)WebRequest.Create(“http://ws.geonames.org/countryInfo”);
channel.Method = “POST”;
channel.ContentType = “text/xml”;

HttpWebRequest class provides a stream to which we can write information :

StreamWriter sw = new StreamWriter(channel.GetRequestStream());

Then we can create a concerete entity to post:

XElement country = new XElement(“country” ,

new XElement(“countryCode”, “AUS”),

new XElement(“countryName” , “Australia”),

….

);

Finally we just need to save this XElement object to the stream we obtained from HttpWebRequest:

country.Save(sw);

This post shows how to deal with REST web services, or any other resource that let us work it in a POST/GET manner. Thanks to Linq to XML working with such services is now too easy.

Older Posts »