Twitter Feed Popout byInfofru

Prevent .js caching in asp.net

This is like a very common issue, specially for those who are working on public site which is live and they have to release the builds every week or month and if the new build contain JS files then your change will not reflect on the client browser until someone there presses ctrl + F5.So, after googling this issue. I came to know it is possible to prevent the browser from accessing the cache copy by writing the script tag as below
   1: <script type="text/javascript" src="../Includes/main.js?random=556"></script>
 It is good, when I have a single or some number of pages to change. Unfortunately, That is not the case I have hundreds of pages and that will be hassle to make those changes again and again for every build. So, I try to make this thing happen using Response Filter.

Create Response Filter:

So, to write the Response Filter we need to create a class and which is extended from Stream (System.IO.Stream) and I named it BuildTokenFilter.
   1: Imports Microsoft.VisualBasic
   2: Imports System.IO
   3: Imports System.Text.RegularExpressions
   4: Imports System.Configuration
   5: 
   6: 
   7: Public Class BuildTokenFilter
   8:     Inherits Stream
   9:     Private _responseStream As Stream
  10:     Public Sub New(ByVal responseStream As Stream)
  11:         _responseStream = responseStream
  12:     End Sub
  13:     Public Overrides ReadOnly Property CanRead() As Boolean
  14:         Get
  15:             Return _responseStream.CanRead
  16:         End Get
  17:     End Property
  18:     Public Overrides ReadOnly Property CanSeek() As Boolean
  19:         Get
  20:             Return _responseStream.CanSeek
  21:         End Get
  22:     End Property
  23: 
  24:     Public Overrides ReadOnly Property CanWrite() As Boolean
  25:         Get
  26:             Return _responseStream.CanWrite
  27:         End Get
  28:     End Property
  29: 
  30:     Public Overrides Sub Flush()
  31:         _responseStream.Flush()
  32:     End Sub
  33: 
  34:     Public Overrides ReadOnly Property Length() As Long
  35:         Get
  36:             Return _responseStream.Length
  37:         End Get
  38:     End Property
  39: 
  40:     Public Overrides Property Position() As Long
  41:         Get
  42:             Return _responseStream.Position
  43:         End Get
  44:         Set(ByVal value As Long)
  45:             _responseStream.Position = value
  46:         End Set
  47:     End Property
  48: 
  49:     Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
  50:         Return _responseStream.Read(buffer, offset, count)
  51:     End Function
  52:     Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
  53:         _responseStream.Seek(offset, origin)
  54:     End Function
  55: 
  56:     Public Overrides Sub SetLength(ByVal value As Long)
  57:         _responseStream.SetLength(value)
  58:     End Sub
  59:     Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
  60:         Dim strRegex As String = "src=(?<Link>.*js)"
  61:         Dim BuildTokenString As String = "?token=" & IIf(ConfigurationManager.AppSettings("BuildToken") = Nothing, "1.0", ConfigurationManager.AppSettings("BuildToken"))
  62:         Dim objRegex As New Regex(strRegex)
  63:         Dim html As String = System.Text.Encoding.UTF8.GetString(buffer)
  64:         Dim extCharCount As Integer = 0
  65: 
  66:         Dim objCol As MatchCollection = objRegex.Matches(html)
  67:         For Each m As Match In objCol
  68:             extCharCount += BuildTokenString.Length
  69:             Dim newJSValue As String = m.Value & BuildTokenString
  70:             html = html.Replace(m.Value, newJSValue)
  71:         Next
  72:         buffer = System.Text.Encoding.UTF8.GetBytes(html)
  73:         _responseStream.Write(buffer, offset, count + extCharCount)
  74:     End Sub
  75: End Class
"Write" is the function which is doing the whole stuff. It is really simple to understand. Let me go linewise.
60. Create a string variable and assign and regular expression which will search all the js files tags in html61. Create a string which will append to the JS file. Checking the App key in web.config So that the token can be extended in future.62. Create a Regex Object63. Get the html from Buffer64. Create an integer variable which will keep track of the characters that are added to the html variable. 66. Save the matches in a collection67. Get each mach object from Match Collection68. Add the character count which will added to the html variable69. Create a variable and assign value of match and concatenated with build token70. Replace the old value with the new with build token in html variable72. Encode the html variable back to the buffer73. Write the buffer to the stream by adding count with build token character count.
Now lets create a HttpModule which will responsible of attaching this response filter with every request.

Create HttpModule:

Now to write HttpModule, I will create a class which will Implements IHttpModule (interface) and I name it "BuildToken"/
   1: Imports Microsoft.VisualBasic
   2: Imports System.Web
   3: Public Class BuildToken
   4:     Implements IHttpModule
   5:     Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
   6: 
   7:     End Sub
   8:     Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
   9:         AddHandler context.BeginRequest, AddressOf Application_BeginRequest
  10:     End Sub
  11:     Private Sub Application_BeginRequest(ByVal source As Object, ByVal e As EventArgs)
  12:         Dim context As HttpApplication = CType(source, HttpApplication)
  13:         If context.Request.RawUrl.Contains(".aspx") = True Then
  14:             context.Response.Filter = New BuildTokenFilter(context.Response.Filter)
  15:         End If
  16:     End Sub
  17: End Class
 In this case the magical function is Application_BeginRequest which can easily be understand but the question might arises why I have put the If condition on line number 13. Well, I don't want my module to attach response filter against all the files. Keep in mind, HttpModule is always called no matter what content type are you requesting. when somebody write http://www.sitename.net/images/border2.jpg it will still process through HttpModule and that is what I don't want.

Configuration Setting:

We are almost done, just a web.config entry is left which we keep for the modification of token string.
   1: <appSettings>
   2:     <add key="BuildToken" value="7.0"/>
   3: </appSettings>
 

Test the filter:

Now to check the the response filter create a page that is called default.aspx and paste the following markup
   1: <html xmlns="http://www.w3.org/1999/xhtml" >
   2: <head runat="server">
   3:     <title>Untitled Page</title>
   4:     <script type="text/javascript" src="../Script/samain.js"></script>
   1: 
   2:     <script type="text/javascript" src="../ControlsScripts/preloadshare.js">
   1: </script>
   2:     <script type="text/javascript" src="../Script/mainview.js">
</script>
   5: </head>
   6: <body>
   7:     <form id="form1" runat="server">
   8:     <div>
   9:     <p>
  10:     Right click and view source you will find JS files with query string</p>
  11:     </div>
  12:     </form>
  13: </body>
  14: </html>
Now Run the application and view source the page you will notice some thing like give below.sc_responsefiltercacheEach time, when you made some changes in JS file just change Build Token entry in the web.config file and your visitors will get the updated copy of JS. You can also download the project files.

How to change default button of a form

Often, we have condition when we have multiple forms on a page which have multiple submit buttons as well. Whenever, you press enter on any text box it will call the command button which is at top most sequence of command buttons.

So, to overcome this problem here is the little code. Take your each set of fields and button in a panel and specify the default Button Property. In the example below I have a form which have two buttons one is command button and another is an image button and I am setting the second button of the sequence to get called each time enter key press on the panel. (rather then the top most)

   1: <asp:Panel ID="pnl1" runat="server" DefaultButton="ImageButton1">
   2:         <asp:TextBox ID="TextBox1" runat="server">
   3:         </asp:TextBox>
   4:         <asp:Button ID="Button1" runat="server" Text="Submit" />
   5:         <asp:ImageButton ID="ImageButton1" runat="server" />
   6:     </asp:Panel>

Validate username using custom validation (AJAX)

In this post, I will explain you how to have an ajax call on custom validator control and check for the username in the database. This task will include two pages one is the form page (default.aspx in our case) in which we have the custom validator and the other one is the page which we call through AJAX to give us the result (validateUser.aspx). You can also have a web service instead of that page but in my scenario , I am using ASPX page.

So, the form will look like as following.

 

   1: <form id="form1" runat="server">
   2: <div>
   3: <asp:Panel ID="pnl1" runat="server" DefaultButton="Button1">
   4:     <asp:TextBox ID="TextBox1" runat="server">
   5:     </asp:TextBox>
   6:     <asp:Button ID="Button1" runat="server" Text="Submit" />
   7:     <asp:HiddenField ID="hfOutput" runat="server" />
   8: </asp:Panel>
   9:     <asp:customvalidator ID="Customvalidator1" runat="server" errormessage="Enter Valid User" ControlToValidate="TextBox1" ClientValidationFunction="ValidMe"></asp:customvalidator>    
  10: </div>
  11: </form>

Default.aspx (Form)

Notice, the hiddent field called hfOutput which we will use to store the output of the AJAX call.

Where as the page which we call through AJAX will look like as follows

   1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="validateUser.aspx.cs" Inherits="LearnWebApp.validateUser" %>

validateUser.aspx

In short, we have deleted every thing from this page except page directive. Now if we call this page we will see the simple output without having any HTML tag. we did it because we want to get rid from all the html tags so that we can have a neat and clean output at the time we call this page from Javascript (AJAX). What we want this page to return us is either "True" or "False". If you look at the code behind file of this page you will have a good idea of what we actually upto. Here is the code for that.

   1: protected void Page_Load(object sender, EventArgs e)
   2:         {
   3:             // We can also use a database call here ... right now we are compairing string.
   4:             if (Request.QueryString["username"] == "username")
   5:             {
   6:                 Response.Write("true");
   7:             }
   8:             else 
   9:             {
  10:                 Response.Write("false");
  11:             }
  12:         }

validateUser.aspx.cs

As it is there on comments, here we are only comparing string. You can have a database call and return the result accordingly.

To call the validateUser.aspx from validMe function which we have defined in ClientValidationFunction property of custom validator, we need to write the following javascript on default.aspx

   1: <script type="text/javascript">
   2:         var ajaxCalled = false;
   3:         
   4:         function ValidMe(source, args) {
   5:            callPage(args.Value)
   6:            while (document.getElementById("hfOutput").value != ""){
   7:                 if (document.getElementById("hfOutput").value == "true") {
   8:                     args.IsValid = true;
   9:                 }
  10:                 else {
  11:                     args.IsValid = false;
  12:                 }
  13:                 document.getElementById("hfOutput").value = "";
  14:                 return;
  15:             }
  16:         }
  17:  
  18:         function callPage(strName) {
  19:             var rnd = Math.random() * 1000000;
  20:  
  21:             if (window.XMLHttpRequest) { // Mozilla, Safari, IE7...
  22:                 request = new XMLHttpRequest();
  23:             } else if (window.ActiveXObject) { // IE6 and older
  24:                 request = new ActiveXObject("Microsoft.XMLHTTP");
  25:             }
  26:             var url = 'validateUser.aspx?username=' + strName + '&R=' + rnd;
  27:             request.open("GET", url, true);
  28:             request.onreadystatechange = SetPage;
  29:             request.send(null);
  30:             
  31:         }
  32:  
  33:  
  34:         function SetPage() {
  35:             if (request.readyState == 4) {
  36:                 var objHf = document.getElementById("hfOutput");
  37:                 if (request.status == 200) {
  38:                     if (objHf) {
  39:                         objHf.value = request.responseText;
  40:                     }
  41:                 }
  42:             }
  43:             
  44:         }
  45:     </script>

 

Let me describe what we have done here, I am calling CallPage function from ValidMe which will call from the asp.net validation mechanism. CallPage function is an AJAX call which will call validateUser.aspx and SetPage function will be called once the AJAX call is finish and we have output ready to use.

And on that SetPage function we are setting the Hidden field  called hfOutput to get used by ValidMe function.

That's it ..... :) . You can also download the complete project give below.

Configuration Membership API Asp.net 2.0

Membership API is yet another enhancement from asp.net team. In this post, I will guide you through the configuring of Membership API to the enhanced usage.

So, to get started let me clear one more confusion which most of people have in there mind

They think that Membership API does not use any database behind and asp.net runtime engine perform some miracle at the back end  and all the user information is stored somewhere which is known by runtime engine.

 

That is wrong ..... big WRONG ....

By default, asp.net uses SQL Server as the back end of Membership API. If you have planned to use it, before doing any thing you need to implement the schema of Membership API to your database.

Step 1 (Implement Schema & Configure Database):

To do that, you need to use aspnet_regsql. which can be accessed by the instruction give below.

  • Go to X:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727 (version of dotnet framework can be vary but it should be at least 2.0)
  • Find and execute aspnet_regsql which will appear following screen.

aspnet_regsql_screen1

  • Once you click next, you will be asked to "Configure SQL Server for application services" or "Remove application services information from existing database". You need to select the first one.
  • Select the appropriate database, click next and you are done with the database stuff.

Step 2 (Configure Asp.net Application):

In this step we will configure our existing or new asp.net application to user asp.net membership API.

Please bear in mind that Asp.net Web Application Administration is a very handy and useful tool to check Membership API integration.

Now, to use API you need to specify the connection string of the database which we have configured with aspnet_regsql.

  • Add the following connection string in web.config
   1: <add name="ConnectionString" connectionString="Data Source=SAMHEAVEN;Initial Catalog=Northwind;User Id=sa;Password=usam;"
   2:      providerName="System.Data.SqlClient" />
  • Specify membership and role configuration under system.web of web.config.
   1: <roleManager enabled="true">
   2:    <providers>
   3:      <clear/>
   4:      <add name="AspnetSqlRoleProvider" applicationName="/AppName" connectionStringName="ConnectionString" type="System.Web.Security.SqlRoleProvider"/>
   5:    </providers>
   6:  </roleManager>
   7:  <membership>
   8:    <providers>
   9:      <clear/>
  10:      <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ConnectionString" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/DanyTech" requiresUniqueEmail="true" passwordFormat="Clear" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>
  11:    </providers>
  12:  </membership>

 

  • Finally, you need to set authentication type.
   1: <authentication mode="Forms" />

To be descriptive, we have specified settings for two basic parts of Membership API. which is using Connection String called "connectionString" which we have created in the first step.

AspNetSqlMembershipProvider and  AspnetSqlRoleProvider have an attribute called applicationName which is really important. All the information of the Membership API will stored in the database against the applicationName specified here.

Where as, AspNetSqlMembershipProvider have a list of settings. Click here to get the complete list of Membership Provider settings.

Now the configuration stuff is complete. You can check is every thing running fine by clicking on the Asp.net Configuration Icon give right above the solution explorer.

se_config

Go to the security tab and check you can create some users and roles (at least administrator, user) . If not then make sure you have not skipped any step.

Get list of installed printers using C# WMI

Well, almost about an year back I write an application which search for the available printer on the server and do some operation accordingly. Today while browsing my code library I found that small test application. So I thought it would be good to share this with the community.

Management Objects are really good, I mean when it comes to windows you can do lots of operations using Management Object. You can get the list of services installed on system, hardware and etc. And the point which is worth to mention here is you can do that by using simple query like TSQL.

To access the printer information on the local machine you can use the following code

   1:             ManagementScope objScope = new ManagementScope(ManagementPath.DefaultPath); //For the local Access
   2:             objScope.Connect();
   3:            
   4:             SelectQuery selectQuery = new SelectQuery();
   5:             selectQuery.QueryString = "Select * from win32_Printer";
   6:             ManagementObjectSearcher MOS = new ManagementObjectSearcher(objScope, selectQuery);
   7:             ManagementObjectCollection MOC = MOS.Get();
   8:             foreach (ManagementObject mo in MOC)
   9:             {
  10:                 listBox1.Items.Add(mo["Name"].ToString().ToUpper());
  11:             }

 

The above code will use the current logged on identity as the default credentials. where as following code will get the list of printer installed from a remote location.

   1: ConnectionOptions objConnection = new ConnectionOptions();
   2: objConnection.Username = "aghausman";
   3: objConnection.Password = "nightmare";
   4: objConnection.Authority = "ntlmdomain:DDI"; //Where DDI is the name of my domain
   5: // Make sure the user you specified have enough permission to access the resource. 
   6:  
   7:  
   8: ManagementScope objScope = new ManagementScope(@"\\\\10.0.0.4\oot\\cimv2",objConnection); //For the local Access
   9: objScope.Connect();
  10:  
  11: SelectQuery selectQuery = new SelectQuery();
  12: selectQuery.QueryString = "Select * from win32_Printer";
  13: ManagementObjectSearcher MOS = new ManagementObjectSearcher(objScope, selectQuery);
  14: ManagementObjectCollection MOC = MOS.Get();
  15: foreach (ManagementObject mo in MOC)
  16: {
  17:     listBox1.Items.Add(mo["Name"].ToString().ToUpper());
  18: }

 

and here is the attachment of the solution files created in Visual Studio 2008

Downloading Zip File Using Asp.net

Here is the quick code of downloading the zip file from asp.net (vb.net)

   1: Dim _strBeingViewedName As String = "MyZip"
   2: Response.ContentType = "application/x-zip-compressed"
   3: Response.AppendHeader("Content-Disposition", "attachment; filename=" + _strBeingViewedName + ".zip")
   4: Response.TransmitFile("..\\zipPath\\" & _strBeingViewedName + ".zip") 'Full Path of the zip file
   5: Response.End()

Protecting images with Response Filter

In this article we will see how we can change the email addresses written on a website to images on the fly. The general opinion about this task is to revamp the form where we are asking user to input the email address and then generate an image which will display later instead of email address.Fortunately, Asp.net provides us with a feature called Response filter which allow us to alter the response generated by web server. By using Response filter we don’t need to alter the foundation of our application. We just need to plug that response filter in and our work is done.So to create a filter we need to create a class called “EmailFilter.CS” which will inherit from Stream.
public class EmailFilter : Stream{private string _path;private Stream _response;public EmailFilter(Stream response, string path){_response = response;_path = path;}
public override int Read(byte[] buffer, int offset, int count){return _response.Read(buffer, offset, count);}
public override void Write(byte[] buffer, int offset, int count){}} 
This can easily be read that we have two local variables which are getting set by our parameterized constructor and we have overrides two functions out of which the write function is really important. We are going to play with that function throughout the tutorial.Note:It is also important to mention here that we have removed some code for clarity but to use the stream class you need to override the some other functions and properties which you can find in code attached.
Now the next step is to write the code in Write method.
 
public override void Write(byte[] buffer, int offset, int count){string html = System.Text.Encoding.UTF8.GetString(buffer);string emailPattern = @"\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
Regex objRegex = new Regex(emailPattern);MatchCollection objCol = objRegex.Matches(html);
foreach (Match m in objCol){string email = m.Value;Font objFont = new Font("Arial", 12, FontStyle.Bold);int width = (int) getTextWidth(email, objFont);Bitmap objBitmap = new Bitmap(width, 20);Graphics objGraphics = Graphics.FromImage(objBitmap);objGraphics.FillRectangle(Brushes.White, new Rectangle(0, 0, width, 20)); //getting white bgobjGraphics.DrawString(email, objFont, Brushes.Black, new Point(0, 0));string relpath = "images/" + Guid.NewGuid().ToString() + ".jpg";string saveFileName = _path + relpath;objBitmap.Save(saveFileName,System.Drawing.Imaging.ImageFormat.Jpeg);objGraphics.Dispose();objBitmap.Dispose();string imgMarkup = "<img src='" + relpath + "'/>";html = html.Replace(email, imgMarkup);}buffer = System.Text.Encoding.UTF8.GetBytes(html);_response.Write(buffer, offset, count);}protected float getTextWidth(string strText, Font f){float width = 0;Bitmap objBitmap = new Bitmap(1, 1);Graphics objGraphics = Graphics.FromImage(objBitmap);try{width = objGraphics.MeasureString(strText, f).Width;return width;}catch (Exception){return 0;}finally{objBitmap.Dispose();objGraphics.Dispose();}} 
The first four lines are easy to understand we are just storing the HTML generated by web server to a variable and we have created a regular expression object to check for the email addresses in out html.
In foreach loop we are generating the images of every email address using System.Drawing and saving the images in a temp location and finally disposing the objects.Now the main stuff is here, we are creating a string variable which will hold html image tag with source and then replace the email address with the image tag.
Whereas, getTextWidth is a simple function which measure the width of our text and return it so that we can have dynamic width for different size of texts.Let's use this response filter in our aspx page. To do that we need to write the following code in Page_Load 
protected void Page_Load(object sender, EventArgs e){Response.Filter = new EmailFilter(Response.Filter, Server.MapPath("/").ToString());}
It is worth to mention here the parameter. Our Response filter is just a class file and we donot have the Server path in classes but we still want to store the images using relative path so to do that we just pass the root path as parameter which we will use in Response Filter to save the image. To understand the situation correctly we need to write the following code in the form tag of our aspx.
<div>aghausman@gmail.com </br>aghausman@ciberstrategies.com</br>me@aghausman.net</br></div>
That is nothing but three simple email addresses. Now when you run the page you will see the following output. Notice that we have write three email addresses but it is showing only two. To see what went wrotn we have let's have a look at the source given below:[singlepic=27,500,200,web20,]
Notice that there is no html after the br of second image. It means there is some thing wrong with the response.write. Now to understand what happen we need to go back and read the last line of our Write function which is as follows
_response.Write(buffer, offset, count);
here we are simply passing what we have get from Write parameter but the matter of fact is that it is now changed. Remember, we have change our email address with the image tag so to compare let's see our first email address and frst generated image. 
Email Address : aghausman@gmail.comImage Text : <img src='images/da04a458-7ff4-41cb-b982-5724c1eadb84.jpg'/>
Notice that image tag is using more then double characters. so we need to change the last parameter count according to the new condition. for that let's see the Write method code again.
  
 
public override void Write(byte[] buffer, int offset, int count){string html = System.Text.Encoding.UTF8.GetString(buffer);string emailPattern = @"\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
Regex objRegex = new Regex(emailPattern);MatchCollection objCol = objRegex.Matches(html);
int totCount = 0;foreach (Match m in objCol){string email = m.Value;Font objFont = new Font("Arial", 12, FontStyle.Bold);int width = (int) getTextWidth(email, objFont);Bitmap objBitmap = new Bitmap(width, 20);Graphics objGraphics = Graphics.FromImage(objBitmap);objGraphics.FillRectangle(Brushes.White, new Rectangle(0, 0, width, 20)); //getting white bgobjGraphics.DrawString(email, objFont, Brushes.Black, new Point(0, 0));string relpath = "images/" + Guid.NewGuid().ToString() + ".jpg";string saveFileName = _path + relpath;objBitmap.Save(saveFileName,System.Drawing.Imaging.ImageFormat.Jpeg);objGraphics.Dispose();objBitmap.Dispose();string imgMarkup = "<img src='" + relpath + "'/>";totCount += imgMarkup.Length;html = html.Replace(email, imgMarkup);}buffer = System.Text.Encoding.UTF8.GetBytes(html);_response.Write(buffer, offset, count + totCount);} 
We have only create an int variable before loop and on every loop we are adding the length of image tag to the variable and finally on response.write we are adding the count with the length of image tags we have generated. that's it.Now if we run the page we will see the following output:  
[singlepic=26,500,200,web20,]That's all, we have now replace the emal addresses written on our website to images. Just in case you don't want to write the page_load stuff on every page as it is very difficult then you can also use httpModule. For the see the following code
public class EmailToImages : IHttpModule{public void Dispose(){
}public void Init(HttpApplication application){HttpContext context = HttpContext.Current;
context.Response.Filter = new EmailFilter(context.Response.Filter, context.Server.MapPath("/"));}}<httpModules><add name="EmailToImage" type="LearnWebApp.EmailToImages, LearnWebApp"/></httpModules> 
Now to remove the temperory images you might need a code which delete the images in timely fashion. That's all.
 Orignal Article and source code will be find at : http://www.highoncoding.com/Articles/468_Protecting_Email_Addresses_Using_Response_Filters.aspx

Fill Asp Menu by Folder

In this post, we will see how can we fill the Asp Menu by specifying folder instead of some other data source. Following is the folder structure which this code is supportedRoot-> Folder 1 -> Files-> Folder 2 -> Files-> Folder 3 -> FilesI mean, if there is another folder in Folder 1 or Folder 2 or Folder 3. The code will not detect because it is not recursive.So Let's get down to the code
protected void Page_Load(object sender, EventArgs e){DirectoryInfo di = new DirectoryInfo(@"C:\\agha"); //Path of folder you want get file/folder fromDirectoryInfo[] objDi = di.GetDirectories();foreach (DirectoryInfo d in objDi){MenuItem objMenuItem = new MenuItem(d.Name);FileInfo[] objfi = d.GetFiles("*.*");foreach (FileInfo f in objfi){objMenuItem.ChildItems.Add(new MenuItem(f.Name));}Menu1.Items.Add(objMenuItem);}}

Get Primary key on Row Command (GridView)

 Some days back I got a query from one of my fellow, regarding a very normal situation I mean that’s the day to day task that we as a developers are doing. Here is the scenarioScenario: Consider you have a data grid view which show a list of products from northwind database and you want a link button which will edit the same grid view entry but in a separate page and on separate form with the help of the primary key which you may want to send to another page using query string or else.So the task is to get the primary key of the row on which the link button is pressed.Solution:Well, we can achieve this task from variety of methods. Let me just give you a quick list of how we can do this.
1. Have Hidden Field in Link button column2. Pass PK in command argument3. Using Data key names.
Ok, for basics I have created two pages one if default.aspx which holds the grid and the other is editform.aspx which will get the primary key sent by Default.aspxOn editForm.aspx add the following code on page load. 
 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load   If Not Request.QueryString("Id") Is Nothing Then 'check if there is nothing in query string       Response.Write("Product Id Is : " + Request.QueryString("Id").ToString()) 'print the id   End IfEnd Sub 
Now for the for the different approaches let's read belowApproach 1 (Hidden field)Write the following grid view on default.aspx 
 <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"  DataSourceID="SqlDataSource1"><Columns><asp:BoundField DataField="ProductName" HeaderText="ProductName" /><asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" /><asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" /><asp:TemplateField><ItemTemplate><asp:HiddenField ID="hfKey" runat="server" Value='<%#Eval("ProductID") %>' /><asp:LinkButton ID="Edit" CommandName="edt" runat="server">Edit</asp:LinkButton></ItemTemplate></asp:TemplateField></Columns></asp:GridView>  
 
 
  
Notice that, we have taken a hidden field just in the same column we have the link button and have it default value of out primary key field. Now on RowCommandEvent of the grid view write the following code 
 Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand    If e.CommandName.ToLower() = "edt"  Then       Dim lb As LinkButton = CType(e.CommandSource, LinkButton) 'getting clicked link button       Dim strKey As String = CType(lb.Parent.FindControl("hfKey"), HiddenField).Value 'getting PK Value       Response.Redirect("EditForm.aspx?id=" + strKey) 'redirecting    End IfEnd Sub  
I guess code does not need any explanation, so let's move on to the next approach.Approach 2We have a minor change the in Template Field of the Gridview we write in Default.aspx. replace that with the following code.  
<asp:TemplateField><ItemTemplate><asp:LinkButton ID="Edit" CommandName="edt" CommandArgument='<%#Eval("ProductId") %>' runat="server">Edit</asp:LinkButton></ItemTemplate></asp:TemplateField>
So, we have remove the hidden field we have added in the last approacha and simply add the command argument to the link button, now to catch the command argument and send it to edit form write the following code onRowCommand Event   
Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As  System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand    If e.CommandName.ToLower() = "edt" Then       Dim strKey As String = e.CommandArgument  'Getting Pk Value from argument       Response.Redirect("EditForm.aspx?id=" + strKey) 'redirecting    End IfEnd Sub  
Approach 3:Ok, for this you need to add DataKeyNames Property to main GridViewMarkup. In other word, it is an attribute of grid view which can accept multiple values using "," but in our case we are using one. So when we add this attribute our grid markup will look like as follows
 
 
 
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID ="SqlDataSource1"><Columns><asp:BoundField DataField="ProductName" HeaderText="ProductName" /><asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" /><asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" /><asp:TemplateField><ItemTemplate><asp:LinkButton ID="Edit" CommandName="edt" runat="server">Edit</asp:LinkButton></ItemTemplate></asp:TemplateField></Columns></asp:GridView>
 
 Notice that we have remove command argument from link button, now add the following code on the RowCommand Function.
Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand    if e.CommandName.ToLower() = "edt" Then       Dim lb As LinkButton = CType(e.CommandSource, LinkButton)       Dim gvRow As GridViewRow = lb.BindingContainer 'Getting current row to get index       Dim strKey As String = GridView1.DataKeys(gvRow.RowIndex)(0).ToString()       Response.Redirect("EditForm.aspx?id=" + strKey) 'redirecting    End IfEnd Sub
In the above code we are getting the current row from which the link button is clicked because we need the index of the row to get the data key name value.So, now you have plenty of choices to select which approach you like to go with :) .Screen Cast : http://tinyurl.com/5fuj8e

Create dynamic controls with validation

Creating a dynamic control and render to a page is a simple task but what happen when you need to apply validation to that dynamic control.Here is the little snippet of that
TextBox objtext = new TextBox();Page.Form.Controls.Add(objtext);RequiredFieldValidator objReq = new RequiredFieldValidator();objtext.ID = "MyTextBox";objReq.ControlToValidate = objtext.ID;objReq.ErrorMessage = "Please tell us some thing";Page.Form.Controls.Add(objReq);