Twitter Feed Popout byInfofru

Get Countries Name in .Net

In this post, I will explain you how can we get the countries name filled in any collection using .net without using any database.

Introduction:

In this post, I will explain you how can we get the countries name filled in any collection using .net without using any database.

It is a regular task, which we all as developers did some past day but the difference is we used database table or xml file to hold the country names. But .net framework provide us with all the countries information in Globalization namespace.

So, here is the code for that

Dictionary<string,string> objDic = new Dictionary<string,string>();

foreach (CultureInfo ObjCultureInfo in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
    RegionInfo objRegionInfo = new RegionInfo(ObjCultureInfo.Name);
    if (!objDic.ContainsKey(objRegionInfo.EnglishName))
    {
        objDic.Add(objRegionInfo.EnglishName, objRegionInfo.TwoLetterISORegionName.ToLower());
    }
}

var obj = objDic.OrderBy(p => p.Key );
foreach (KeyValuePair<string,string> val in obj)
{
    ddlCountries.Items.Add(new ListItem(val.Key, val.Value));
}

 

Explanation:

Notice that, we have used typed dictionary object to store the name and the values of the countries.

Then, we use CultureInfo.GetCultures to get the cultural information of the countries.

Later on, we use RegionInfo to get the regional information of that  culture.

Since, there can be multiple cultures of the same country that is why there is a condition which check either the country is already added in dictionary. If not, then simply add the country name and country two letter name. (Note : We are treating the two letter country name as the value)

After the loop, I used some LinQ stuff to sort county names, and then iterate through the returned object to add the values in drop down list.

That’s it. Now you are not only limited to show the English name of the country but you can also show the native name. For example, the name of my country in English is “Islamic Republic of Pakistan” but the native name is پاکستان.

Also, you can get the following country information using RegionInfo

 

sc_clbn_1

Some developers are habitual of using country id along with the country name. if they still want to use some id to save the country information they can use the GeoId property of the RegionInfo.

CodeGain.com .net Community Portal

A guy named RRaveen  has setup a .net community portal named CodeGain and located on http://www.codegain.com.

Yet the portal is still in process but the content which he has posted is really useful and in fact it really help me in some places.

The best part about this portal is, it is not .net or asp.net specific. You will find articles  on desktop applications, Java, Oracle etc.

Previously, RRaveen had also written some articles on HighOnCoding.com and is active .net community so he is on a great task.

CodeGain

Show Loading Message in Asp.net AJAX

In this post, I will explain you how can we show Loading message in asp.net ajax without using Update Progress. Now some one may asked, why do I want to skip Update Progress ?

Well, there can be several reasons for this, fist of all you have to work on every single page, and on every update panel to get the update progress working.

There are basically three methods of meeting this requirement.

  1. Using Master Pages : A very smart way, but not all of us are using them .. right ?
  2. Extending Page Class  : A little harder but to me it is very elegant way.
  3. Extending Script Manager : Similar to the page class one, but implementation is comparatively simple.

The Basics:

Before I start with exploring the different approaches let me first create a ground by showing what things will be involve in creating a loading message.

I want the background to be grayed and displayed a simple loading text at the top, for that we need a style sheet, which will apply to the loading message div.  Create a stylesheet and call it style.css

.ModalProgressContainer
{
    z-index: 10005;
    position: fixed;
    cursor: wait; 
    top:0%; 
    background-color: #ffffff; 
    filter: alpha(opacity=50);
    opacity: 0.5;
    -moz-opacity: .5; 
    height: 100%;
    width: 100%;
    text-align: center; 
    
    } 
.ModalProgressContent
{
    padding: 10px; 
    border: solid 0px #000040; 
    font-weight: bold; 
    background-color:#ffffff;
    margin-top:300px;
} 

Now lets read and understand the following script.

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);

// ----------------------------- //
// the below script will be saved in JS File, create a JS file and call it ajaxload.js and save the following script

function InitializeRequest(sender, args) {

    if (document.getElementById('ProgressDiv') != null)
       $get('ProgressDiv').style.display = 'block';
    else
        createContorl();
}

function EndRequest(sender, args) {

    if (document.getElementById('ProgressDiv') != null)
        $get('ProgressDiv').style.display = 'none';
    else
        createContorl();
}

function createContorl() {
    var parentDiv = document.createElement("div");
    parentDiv.setAttribute("class", "ModalProgressContainer");
    parentDiv.setAttribute("Id", "ProgressDiv");
 

    var innerContent = document.createElement("div");
    innerContent.setAttribute("class", "ModalProgressContent");
    var img = document.createElement("img");

    img.setAttribute("src", "/Images/Images/Loading.gif");

    var textDiv = document.createElement("div");
    textDiv.innerHTML = 'Loading....';

    innerContent.appendChild(img);
    innerContent.appendChild(textDiv);

    parentDiv.appendChild(innerContent);

    document.body.appendChild(parentDiv);

}

Notice,in the first three lines. We are getting the instance of PageRequestManager and then defining InitilizeRequest and EndRequest functions to display or hide the loading div. Where as, in createControl function we are simply writing DHTML, to be more specific there is no HTML of the loading div in our markup. So, we are writing that from JavaScript.

Also, note the that I have break down this script into two part by using comments. First is the declaration and second is definition of the functions.

note: The definition will take place on a seperate JS file where as the declaration need to be made in the page, under body markup.  Now we are all set to explore different approaches.

 

Using Master Pages :

A very simple approach, all you need to do is open your master page and paste the following lines in the head section.

<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="ajaxload.js"></script>

 

And in body, after form tag create a script section and paste the following JavaScript.

var prm = Sys.WebForms.PageRequestManager.getInstance();

prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);

 

Notice it is the same declaration section which we have discussed above and that’s it you are done. All the content form of your web application should now display loading div on each partial postback.

 

Extending Page Class  :

For this, create a class file and call it ajaxPage and inherit it from System.Web.UI.Page and write the following code.

public class ajaxPage : Page
{
    protected override void OnLoad(EventArgs e)
    {
        //Include CSS File
        Page.Header.Controls.Add(new LiteralControl("<link href='style.css' rel='stylesheet' type='text/css' />"));


        //Include JS file on the page
        ClientScript.RegisterClientScriptInclude("ajaxload", ResolveUrl("~/ajaxload.js"));

        //Writing declaration script 
        String script = "var prm = Sys.WebForms.PageRequestManager.getInstance();";
        script += "prm.add_initializeRequest(InitializeRequest);";
        script += "prm.add_endRequest(EndRequest);";

        ClientScript.RegisterStartupScript(typeof(string), "body", script, true);

        base.OnLoad(e);
    }

}

 

Well, we have simply extend the System.Web.UI.Page into our own class and override OnLoad function to include the JS file and write the declaration markup.

Now, on the page code behind where you want to implement Loading message change the inherit namespace from System.Web.UI.Page to ajaxPage (make sure you namespace).

 

Extending Script Manager :

Now instead of extending page class we will extend Script Manager control and for that create a new class file and call it ScrtipManagerExt and write the following code.

public class ScriptManagerExt : ScriptManager
{
    protected override void OnLoad(EventArgs e)
    {

        //Include CSS File
        Page.Header.Controls.Add(new LiteralControl("<link href='style.css' rel='stylesheet' type='text/css' />"));

        RegisterClientScriptInclude(this, typeof(Page), "ajaload", ResolveClientUrl("~/ajaxload.js"));

        String script = "var prm = Sys.WebForms.PageRequestManager.getInstance();";
        script += "prm.add_initializeRequest(InitializeRequest);";
        script += "prm.add_endRequest(EndRequest);";

        RegisterStartupScript(this, typeof(Page), "ajaxtest", script, true);
        base.OnLoad(e);
    }
}

Almost the same thing we did in extend page approach, only the implementation will be change. Instead of using the old Script Manager we will use our new one. the include directive and markup will look like as below.

<%@ Register Assembly="Assembly" Namespace="namespace" TagPrefix="cc1" %>
<cc1:ScriptManagerExt ID="ScriptManagerExt1" runat="server">
</cc1:ScriptManagerExt>

 

That’s it we are done. I tried to make it simpler and show you every possible way I know of doing this task. Again, any approach selection will be on you and your project type. You can also download  the VS 2008 project file.

Migrate from WordPress to BlogEngine.net

In this post, I will explain how to migrate a blog running on Word Press (Self Hosted) to BlogEngine. But before I start let me say, that Word Press simply rocks. The reason why I plan to switch my blog is customization. Since I am a dotnet geek, I really have no great idea of what I can make out of Word Press using PHP and when it comes to Blogging in .net, I guess I made a very right decision to use BlogEngine. It is open source and included all the necessary blogging utilities.

The main thing which I want to migrate is as follows

  • Post
  • Categories
  • Tags
  • Comments

The moment I start, I was thinking to get some export / import tool. Then I came to know about BlogML. A format that is created to interchange content between different bloging engines. Natively, Word Press don’t support BlogML but Robert McLaws did great job on wiring this tool. Unfortunately, that tool didn’t work for me, for some reason it is keep giving me error.

Finally, I tried it in my own way. Since that blog was self hosted, I have access to mysql database engine through phpMyAdmin. Hence, I decided to export SQL of my related tables and data in MSSQL (TSQL) format.

 

  1. After the login into phpMyAdmin, go to the table list by selecting the databases comes at left.
  2. From the tab at the top select export.
  3. In the export group, select SQL and tables in my case it is wp_comments, wp_posts, wp_term_relationships, wp_term_taxonomy, and wp_term
  4. Now from the SQL Compatibility Mode, Select MSSQL. Save the file and your are complete.

Your selection screen should like like below.

sc_wp_to_be

 

Now open the generated SQL in MSSQL and before you run you might need to fix some column names and some data type issues of the table. But believe that is pretty easy. To help you more, please see the table creation script below

CREATE TABLE [dbo].[wp_comments](
    [comment_ID] [bigint] IDENTITY(1,1) NOT NULL,
    [comment_post_ID] [int] NOT NULL,
    [comment_author] [varchar](200) NOT NULL,
    [comment_author_email] [varchar](100) NOT NULL,
    [comment_author_url] [varchar](200) NOT NULL,
    [comment_author_IP] [varchar](100) NOT NULL,
    [comment_date] [datetime] NOT NULL,
    [comment_date_gmt] [datetime] NOT NULL,
    [comment_content] [text] NOT NULL,
    [comment_karma] [int] NOT NULL,
    [comment_approved] [varchar](20) NOT NULL,
    [comment_agent] [varchar](255) NOT NULL,
    [comment_type] [varchar](20) NOT NULL,
    [comment_parent] [bigint] NOT NULL,
    [user_id] [bigint] NOT NULL,
    [comment_subscribe] [varchar](1) NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [comment_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

CREATE TABLE [dbo].[wp_posts](
    [ID] [bigint] NOT NULL,
    [post_author] [bigint] NOT NULL,
    [post_date] [datetime] NOT NULL,
    [post_date_gmt] [datetime] NOT NULL,
    [post_content] [text] NOT NULL,
    [post_title] [text] NOT NULL,
    [post_category] [int] NOT NULL,
    [post_excerpt] [text] NOT NULL,
    [post_status] [varchar](20) NOT NULL,
    [comment_status] [varchar](20) NOT NULL,
    [ping_status] [varchar](20) NOT NULL,
    [post_password] [varchar](20) NOT NULL,
    [post_name] [varchar](200) NOT NULL,
    [to_ping] [text] NOT NULL,
    [pinged] [text] NOT NULL,
    [post_modified] [datetime] NOT NULL,
    [post_modified_gmt] [datetime] NOT NULL,
    [post_content_filtered] [text] NOT NULL,
    [post_parent] [bigint] NOT NULL,
    [guid] [varchar](255) NOT NULL,
    [menu_order] [int] NOT NULL,
    [post_type] [varchar](20) NOT NULL,
    [post_mime_type] [varchar](100) NOT NULL,
    [comment_count] [bigint] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

CREATE TABLE [dbo].[wp_terms](
    [term_id] [bigint] IDENTITY(1,1) NOT NULL,
    [name] [varchar](200) NOT NULL,
    [slug] [varchar](200) NOT NULL,
    [term_group] [bigint] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [term_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

CREATE TABLE [dbo].[wp_term_relationships](
    [object_id] [bigint] NOT NULL,
    [term_taxonomy_id] [bigint] NOT NULL,
    [term_order] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [object_id] ASC,
    [term_taxonomy_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
CREATE TABLE [dbo].[wp_term_taxonomy](
    [term_taxonomy_id] [bigint] IDENTITY(1,1) NOT NULL,
    [term_id] [bigint] NOT NULL,
    [taxonomy] [varchar](32) NOT NULL,
    [description] [text] NOT NULL,
    [parent] [bigint] NOT NULL,
    [count] [bigint] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [term_taxonomy_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

 

Please note  that it is just the schema script. All you data will be included in mysql generated SQL File which we have created before.

Now, we have all the required tables with data imported from Word Press to Blog Engine Db but we will fill Blog engine tables to show imported data. Lets first start with category.

 

Category:

There is no such table in wp_categories in word press instead it uses wp_term and wp_term_taxonomy to store categories where as in Blog engine we have a table called be_categories which hold categories information. So following query will dump the data from wp_terms , wp_taxonomy to be_categories.

INSERT INTO [dbo].[be_Categories]
           ([CategoryID]
           ,[CategoryName]
           ,[Description]
           ,[ParentID]
           ,[Slug])
     SELECT
           NEWID(),
           w1.[name],
           ('Posts in ' + w1.[name]) as Description,
           NULL, -- as I am not going to make any parent child relation now ...
           w1.[slug]
           FROM [BlogEngine].[dbo].[wp_terms] w1
  INNER JOIN  wp_term_taxonomy w2 on w1.term_id = w2.term_id and w2.taxonomy = 'category'
GO

Posts:

Now lets deal with posts, a very easy query because we have the post table in both the blogging engines. In Word Press it is wp_posts where as in Blog Engine it is be_post

INSERT INTO [dbo].[be_Posts]
      ([PostID]
      ,[Title]
      ,[Description]
      ,[PostContent]
      ,[DateCreated]
      ,[DateModified]
      ,[Author]
      ,[IsPublished]
      ,[IsCommentEnabled]
      ,[Raters]
      ,[Rating]
      ,[Slug])

SELECT newid(),
       post_title,
       post_excerpt,
       post_content,
       post_date,
       post_modified,
      'username',
      1,
      1,
      0,
      0,
      post_name
from wp_posts where post_type ='post'

 

Post Category Relation:

Now its time to set, which post have which categories. The table which is repsonsible for saving this information is called wp_term_relationship in Word Press and be_PostCategory in Blog Engine. See the following query.

select  wp.post_title ,wtr.name into #temp1 from wp_term_relationships wr inner join 
wp_term_taxonomy wt on wr.term_taxonomy_id = wt.term_taxonomy_id and wt.taxonomy = 'category' 
inner join wp_terms wtr on wt.term_id = wtr.term_id
inner join wp_posts wp on wr.object_id = wp.ID and post_type = 'post'



INSERT INTO [dbo].[be_PostCategory]
           ([PostID]
           ,[CategoryID])
select (select postId from be_Posts where Title= convert(nvarchar(max),t.post_title)),
(select CategoryID from  be_Categories where CategoryName = t.name) from #temp1 t

drop table #temp1

GO

I guess this query might need some explanation. See, in the top query I am getting the title of posts and name of categories and storing it to temp table.

Now come to the second part, here I insert new reords in be_postcategory based on the category names and post titles we filled before.

 

Tag:

In Blog Engine we have a table called be_PostTag which manage all the tags related stuff but in wordpress again involve all the tables containing wp_term. So, I write the following query which get the data from those tables and store it in Tags.

INSERT INTO [dbo].[be_PostTag]
         ([PostID]
         ,[Tag])
         
         
         
   SELECT
         (select postId from be_Posts where Title= convert(nvarchar(max),wp.post_title)) ,SUBSTRING(w1.[name], 1, 50)
         FROM [BlogEngine].[dbo].[wp_terms] w1
INNER JOIN  wp_term_taxonomy w2 on w1.term_id = w2.term_id and w2.taxonomy = 'post_tag'
inner join  wp_term_relationships wr on wr.term_taxonomy_id = w2.term_taxonomy_id
inner join  wp_posts wp on wr.object_id = wp.ID

 

 

Comment:

This one is comparatively easy. We have table called wp_comments in Word Press and be_postcomment in Blog Engine to manage the comments. Here is the final query.

INSERT INTO be_PostComment]
         ([PostCommentID]
         ,[PostID]
         ,[ParentCommentID]
         ,[CommentDate]
         ,[Author]
         ,[Email]
         ,[Website]
         ,[Comment]
         ,[Country]
         ,[Ip]
         ,[IsApproved])

SELECT 
      newId()
    ,(select postId from be_Posts where Title= convert(nvarchar(max),wpp.post_title)) as PostID
    ,(select postId from be_Posts where Title= convert(nvarchar(max),wpp.post_title)) as PostID
    ,[comment_date_gmt]
    ,[comment_author]
    ,[comment_author_email]
    ,[comment_author_url]
    ,[comment_content]
    ,NULL
    ,[comment_author_IP]
    ,1
    
FROM [wp_comments] wpc
INNER JOIN BlogEngine.dbo.wp_posts wpp on wpc.comment_post_ID = wpp.ID
where wpc.comment_approved = '1' 

 

Note : You might see some /r/n between some post and comments. Don’t get afraid of this, just replace “/r/n”  with “<br/>” on effected using Replace function of TSQL.

 

That’s how you can  import all the data from Word Press to Blog Engine and this is fairly a huge issue why people don’t move their blogs.  I have tried to explain the method by making it more simple, if you still face any issue please feel free to contact me.

Maintain Scroll Position With Asp.net Validation Controls.

In this post I will demonstrate you how to maintain the scroll position of asp.net validation controls on a page

Few days ago, when I was trying to put validation controls on a form which is at the bottom of the page. I noticed that each time Asp.net validation controls executed it reset the scroll position to top and the end user see no messages until page scroll back to the old position. Irritated :)

Problem:

Untitled

 

So, In this post I will demonstrate you how to maintain the scroll position of asp.net validation controls on a page. To start with an example, lets create a form like below

<div>
     <p>

 </p>
 <p>
     &nbsp;</p>
 <p>
     &nbsp;</p>

         <p>
             &nbsp;</p>

         <p>
             &nbsp;</p>
         <p>
             &nbsp;</p>
         <p>
             &nbsp;</p>
         <p>
             &nbsp;</p>
         <p>
             &nbsp;</p>
 <p>
     &nbsp;</p>
 <p>
     &nbsp;</p>
 <p>
     &nbsp;</p>
     <table class="style1">
         <tr>
             <td>
                 Name</td>
             <td>
                 <asp:TextBox ID="txtName" runat="server" autocomplete="off" Width="200"></asp:TextBox>
                 <asp:RegularExpressionValidator ID="revName" runat="server" 
                     ControlToValidate="txtName" Display="None" 
                     ErrorMessage="Please enter a valid name" 
                     ValidationExpression="(^([0-9-a-z-A-Z\\s+?\\.+?\\(+?\\)+?])+$)" 
                     ValidationGroup="grpTop"></asp:RegularExpressionValidator>
                     <asp:RequiredFieldValidator ID="rfvName" runat="server" 
                     ControlToValidate="txtName" Display="None" ErrorMessage="Please enter a name." 
                     SetFocusOnError="true" ValidationGroup="grpTop"></asp:RequiredFieldValidator>
             </td>
         </tr>
         <tr>
             <td>
                 Email Address</td>
             <td>
                 <asp:TextBox ID="txtUsername" runat="server" autocomplete="off" Text="" 
                     Width="200"></asp:TextBox>
                 <asp:RequiredFieldValidator ID="rfvEmailAddress" runat="server" 
                     ControlToValidate="txtUsername" Display="None" 
                     ErrorMessage="Please enter a valid email address." ValidationGroup="grpTop"></asp:RequiredFieldValidator>
                 <asp:RegularExpressionValidator ID="revEmail" runat="server" 
                     ControlToValidate="txtUsername" Display="None" 
                     ErrorMessage="Please key in a valid email address." SetFocusOnError="true" 
                     ValidationExpression="^([a-zA-Z0-9_'+*$%\\^&amp;!\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9:]{2,4})+$" 
                     ValidationGroup="grpTop"></asp:RegularExpressionValidator>
                 <asp:CustomValidator ID="valEmailAlreadyExists" runat="server" Display="None" 
                     ErrorMessage="Email address already exists" ValidationGroup="grpTop"></asp:CustomValidator>
             </td>
         </tr>
         <tr>
             <td>
                 Date Format</td>
             <td>
                 <asp:DropDownList ID="ddlDateFormat" runat="server" Width="200px">
                     <asp:ListItem>Select</asp:ListItem>
                     <asp:ListItem Text="dd/MM/yyyy" Value="dd/MM/yyyy">dd/MM/yyyy</asp:ListItem>
                     <asp:ListItem Text="MM/dd/yyyy" Value="MM/dd/yyyy">MM/dd/yyyy</asp:ListItem>
                     <asp:ListItem Text="dd/MM/yy" Value="dd/MM/yy">dd/MM/yy</asp:ListItem>
                     <asp:ListItem Text="MM/dd/yy" Value="MM/dd/yy">MM/dd/yy</asp:ListItem>
                 </asp:DropDownList>
                 <asp:RequiredFieldValidator ID="rfvDateFormat" runat="server" 
                     ControlToValidate="ddlDateFormat" Display="None" 
                     ErrorMessage="Please select date format." InitialValue="Select" 
                     SetFocusOnError="true" ValidationGroup="grpTop"></asp:RequiredFieldValidator>
             </td>
         </tr>
         <tr>
             <td>
                 &nbsp;</td>
             <td>
                 <asp:CheckBox ID="cbIsAdmin" runat="server" Checked="false" 
                     Text="Administrator?" />
                 &nbsp;<asp:CheckBox ID="cbResetPW" runat="server" Checked="false" 
                     Text="Reset Password" />
             </td>
         </tr>
         <tr>
             <td>
                 &nbsp;</td>
             <td>
                 <asp:Button ID="Button1" runat="server" Text="Submit Group 1"  ValidationGroup="grpTop"
                     onclick="Button1_Click" />
                 <asp:ValidationSummary ID="ValidationSummary1" runat="server" 
                     EnableClientScript="true" HeaderText="Fix the following issues :" 
                     ValidationGroup="grpTop" />
             </td>
         </tr>
         <tr>
             <td>
                 &nbsp;</td>
             <td>
                 &nbsp;</td>
         </tr>
     </table>
</div>

Notice that <p> tag which I have given in the above snippet to keep my form at the bottom of the page so that the scroll position problem can easily be demonstrated.

When you run the above snippet, you will realize that the page scroll position will lost as soon as you want to submit the form. If you try the page directive System.Web.Ui.Page.MaintainScrollPositionOnPostBack. Noting will change because by using this property Asp.net engine will take care of scroll position after post back. But we want it on client script. It means, we need to modify the mechanism on which asp.net validation controls executed.

To start with the understanding, I came across a very good article “Understanding ASP.NET Validation Library” by DeepakRaghavan. Which gives me the understanding of two methods. Page_ClientValidate and WebForm_OnSubmit and ultimately I need to modify them and bear in mind that these function will be written inside form tag not in title.

The idea is to use the bookmark to maintain the scroll bar. So lets modify both the functions respectively.

 

Page_ClientValidate:

   1: var bookMark = "#OtherBookMark";
   2: function Page_ClientValidate(validationGroup)
   3: {
   4:   
   5:   Page_InvalidControlToBeFocused = null;  
   6:   if (typeof(Page_Validators) == "undefined") {  
   7:   return true;  
   8:   }  
   9:   var i;  
  10:   for (i = 0; i < Page_Validators.length; i++) {  
  11:   ValidatorValidate(Page_Validators[i], validationGroup, null);  
  12:   }  
  13:   ValidatorUpdateIsValid();  
  14:   ValidationSummaryOnSubmit(validationGroup);  
  15:   Page_BlockSubmit = !Page_IsValid;  
  16:   
  17:   if (validationGroup == "grpTop")
  18:   {
  19:       bookMark = "#addForm";
  20:   }
  21:   else
  22:   {
  23:       bookMark = "#OtherBookMark";
  24:   }
  25:   return Page_IsValid;  
  26: }

Description:

Line No 1.       A variable that will hold the bookmark name

Line No 2-14   The default function implementation (We have simple nothing to do with it… simply copy / paste)

Line No 15- 22 Since we can have multiple forms on a page, that is why it is better to keep track that which validation group is called and decide the bookmark name accordingly.

 

Now instead of modifying WebForm_OnSubmit, let’s first create a following function

SubmitAction:

 

   1: function SubmitAction() {
   2: if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false)
   3:   {
   4:           var hashIndex = location.href.indexOf("#");
   5:           
   6:           if (hashIndex > -1) 
   7:           {
   8:               var loc = location.href.substring(0,hashIndex);
   9:               location.href = loc + bookMark;
  10:           }
  11:           else
  12:           {
  13:               location.href = location + bookMark;
  14:           }
  15:           
  16:           return false;
  17:   }
  18:   else
  19:   {
  20:       return true;
  21:   }
  22: }

 

Description:

Well, the function is very simple and don’t really need line by line commentary.
We are checking if the validation is fail, set the bookmark. other wise just let it go.

 

WebForm_OnSubmit:

Now we will call the above SubmitAction function inside WebForm_OnSubmit. To inject this function you need to write the following lines on the Page_Load

   1: if (!Page.ClientScript.IsOnSubmitStatementRegistered("keySubmitAction"))
   2: {
   3:     Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), "keySubmitAction", "return SubmitAction();");
   4: }

System.Web.UI.Page.ClientScript.RegisterOnSubmitStatement is actually used to inject your script inside WebForm_OnSubmit. To be more specific, the first lines will be yours :).

and if you notice the Line No : 3 I used return statement which means as soon as WebForm_OnSubmit will execute my function (SubmitAction) will run first and then return the execution out… no more processing on WebForm_OnSubmit.

Now when you look at the view source of your browser you will see some thing similar to the following.

sc_mvc

Ok, now we only need to setup our bookmark.

Just give the id “addForm” to the table or div inside which the validation summary control is placed. that’s it.  However, you can download the VS 2008 Solution from here.

How to show and select month/year in Calendar Extender

In this post I will explain you, How to make calendar extender control to show month / year view by default and instead of selecting dates how can we use calendar extender to select months.

Before I start, let me say that I got extensive support from this forum post http://forums.asp.net/t/1349086.aspx. Thanks to Zhi-Qiang Ni, but the way he follow was a little bit lengthy. However, all credit still goes to him because I gain the exact idea from his post.

Let me start by creating a calendar extender control and attach it to a textbox.

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<cc1:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" OnClientHidden="onCalendarHidden"  OnClientShown="onCalendarShown" BehaviorID="calendar1"
    Enabled="True" TargetControlID="TextBox1">
</cc1:CalendarExtender>


Now, in extender markup, notice onClientHidden and OnClientShown event which I implemented as below.

function onCalendarShown() {
 
     var cal = $find("calendar1");
     //Setting the default mode to month
     cal._switchMode("months", true);
     
     //Iterate every month Item and attach click event to it
     if (cal._monthsBody) {
         for (var i = 0; i < cal._monthsBody.rows.length; i++) {
             var row = cal._monthsBody.rows[i];
             for (var j = 0; j < row.cells.length; j++) {
                 Sys.UI.DomEvent.addHandler(row.cells[j].firstChild, "click", call);
             }
         }
     }
 }
 
 function onCalendarHidden() 
 {
     var cal = $find("calendar1");
     //Iterate every month Item and remove click event from it
       if (cal._monthsBody) {
         for (var i = 0; i < cal._monthsBody.rows.length; i++) {
             var row = cal._monthsBody.rows[i];
             for (var j = 0; j < row.cells.length; j++) {
                 Sys.UI.DomEvent.removeHandler(row.cells[j].firstChild,"click",call);
             }
         }
     }
 
 }

Pretty simple, In onCalendarShown method I just set the default mode to month and then iterate the control to get month item and attach on click event to it. So that, it will not go further to show us dates of that month and select the first day of that month instead.

Where as, In onCalendarHidden I am simply detaching the click event from month items. Now notice the last parameter of Sys.UI.DomEvent.addHandler function, it is the name of the function which will do the rest of the magic as below.

function call(eventElement)
        {
            var target = eventElement.target;
            switch (target.mode) {
            case "month":
                var cal = $find("calendar1");
                cal._visibleDate = target.date;
                cal.set_selectedDate(target.date);
                cal._switchMonth(target.date);
                cal._blur.post(true);
                cal.raiseDateSelectionChanged();
                break;
            }
        }

Here we are simply selecting the month as the selected date of calendar control. and finally the control will look like as below.

cal_extender

You can get the source code from here :
http://cid-cdbfe38dc780f729.skydrive.live.com/self.aspx/.Public/Calendar%20Extender%20Month.zip

PMP Preparation Blog

One of my friend Sarim Shehkhani has created a blog on PMP Preperation. I red that blog and found it very useful for anyone who is planning to get PMP. Here is the URL : http://pmpforidiots.blogspot.com/Sarim Shehkhani is him self a PMP and got 7+ years experience in Project Management and he is the one who introduces Visual Studio Team Foundation System to me. So, I am looking forward to get some more professional project management skils from PMP for Idiots.

Show images on Grid View from File Stream SQL Server 2008

Background :

In my last post about SQL Server 2008 new feature File Stream (Saving and Retrieving File Using FileStream SQL Server 2008), we did an example of saving an image to the file stream and then retrieve it back and make it available for download.The result of that example looks like as below.fs_snapshot1But, one has to press the button to download the image file. One of my blog reader raise a point that he wants to display the same image instead of Get File button which is going to download.

Introduction :

So, in this post I will explain you, how can we rendered the image before actually downloading it and show that in the grid (Maybe as thumbnail, but this post will not discuss any thing about generating thumbnails).Note : If you want to know. How to add files to the file stream please see my post Saving and Retrieving File Using FileStream SQL Server 2008

Getting Started:

We will complete this goal by using HttpHandler. lets first alter our gridview.

   1: <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
   2:         onrowcommand="GridView1_RowCommand">
   3:         <Columns>
   4:             <asp:BoundField DataField="ID" HeaderText="ID" />
   5:             <asp:BoundField DataField="SystemNumber" HeaderText="System Id" />
   6:             <asp:TemplateField>
   7:                 <ItemTemplate>
   8:                     <asp:LinkButton ID="lbGetFile" runat="server" CommandName="GetFile" CommandArgument='<%#Eval("ID") %>' ><img src='<%#Eval("ID") %>.jpg' /></asp:LinkButton>
   9:                 </ItemTemplate>
  10:             </asp:TemplateField>
  11:         </Columns>
  12:
  13:     </asp:GridView>

Notice the link button on line no 8. I have now specify an image tag inside Link button and pass the primarykey of tbl_files as the file name along with random “.jpg”. So that, it can finally looks like as follows8e7af927-cc7e-4515-8409-d94566246de8.jpga3de6abb-382f-484c-822c-7f93e0ede0c7.jpg4ad64bf1-ea6e-4228-bdc0-300a0cd90f5a.jpgThe idea is, I will attach the handler with jpg file type to accommodate the incoming requests.Now, lets create HttpHandler and name it “imageHandler”

public class imageHandler : IHttpHandler
{
    #region IHttpHandler Members
    public bool IsReusable
    {
        get { return false; }
    }
    public void ProcessRequest(HttpContext context)
    {
        //Getting file name from incoming request.
        string url = Path.GetFileName(context.Request.Path);
        Guid FileId;
        try
        {
            //Since we have all our primary keys stored in GUID
            //Try parsing the file name to Guid
            FileId = new Guid(Path.GetFileNameWithoutExtension(url));
        }
        catch (FormatException)
        {
            //If some other JPG file is requested
            FileId = Guid.Empty;
        }
        if (FileId != Guid.Empty) // If the call is for valid Image File Stream
        {
            SqlConnection objSqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            objSqlCon.Open();
            SqlTransaction objSqlTran = objSqlCon.BeginTransaction();
            SqlCommand objSqlCmd = new SqlCommand("FileGet", objSqlCon, objSqlTran);
            objSqlCmd.CommandType = CommandType.StoredProcedure;
            SqlParameter objSqlParam1 = new SqlParameter("@ID", SqlDbType.VarChar);
            objSqlParam1.Value = FileId.ToString();
            objSqlCmd.Parameters.Add(objSqlParam1);
            string path = string.Empty;
            string fileType = string.Empty;
            using (SqlDataReader sdr = objSqlCmd.ExecuteReader())
            {
                while (sdr.Read())
                {
                    path = sdr[0].ToString();
                    fileType = sdr[1].ToString();
                }
            }
            objSqlCmd = new SqlCommand("SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()", objSqlCon, objSqlTran);
            byte[] objContext = (byte[])objSqlCmd.ExecuteScalar();
            SqlFileStream objSqlFileStream = new SqlFileStream(path, objContext, FileAccess.Read);
            byte[] buffer = new byte[(int)objSqlFileStream.Length];
            objSqlFileStream.Read(buffer, 0, buffer.Length);
            objSqlFileStream.Close();
            objSqlTran.Commit();
            context.Response.AddHeader("Content-disposition", "attachment; filename=" + Path.GetFileName(path) + fileType);
            // Here you need to manage the download file stuff according to your need
            context.Response.ContentType = "application/octet-stream";
            context.Response.BinaryWrite(buffer);
        }
        else
        { // If the call is for some other JPG file, nothing to do with file stream.
            context.Response.WriteFile(context.Request.Path);
        }
    }

Well, read the comments I wrote in the code. That will of course help you to understand what actually I have done.And then register the HttpHandler.

<httpHandlers>
    <add verb="*" path="*.jpg" type="LearningApp.imageHandler, LearningApp"/>
</httpHandlers>

Conclusion:

There we go, In this way we can show the images stored on file stream in grid view. You can download both VS 2008 and VS 2010 project files.

Team Foundation Server Installation Story

In my life, whenever I attempt to install Team Foundation Server (TFS). I experienced some new issues, fixes, updates and work around and we are now again moving to TFS for source controlling and project management. So, this time I planned to put my installation experience on a blog.

In my knowledge TFS is the only Microsoft technology, that doesn’t work with Next Next stuff. You need to be sure what you are doing when you are installing things.

In this post I will explain you the process of installing TFS to the new machine.

Pre-Requirement:

1. SQL Server 2005 With Reporting and Analysis services. (Service Pack 2)
2. Install SharePoint Services 2007.
3. Once installed, go to administration tool and run SharePoint Product and Technologies Configuration wizard. Ignore the popup saying that
"The following services may have to be started or reset during configuration:
Internet Information Services
SharePoint Administration Service
SharePoint Timer Service".
Just press ok and let it go.

Once the the Wizard is finish, A browser will open containing the SharePoint site.
If it open up with the error, Go to IIS and see if there is an other site which is using SharePoint. If yes, then either you can change port of your site or you can also change SharePoint default port. For that see the following post.

http://www.theangrycoder.net/sharepoint/how-to-change-default-port-of-sharepoint.html

4. Now go to the Central Administration Site and see the Administration Task. And complete configure outgoing email settings and create new web applications task which will ensure your that SharePoint is successfully installed and able to create web sites with no problem.

I have no idea, what went wrong but my reporting services doesn’t create any database neither it was configures on my machine. So I waste some time to do it myself.

Configure Reporting Services:

  1. Now go to Programs – SQL Server 2005 - Configuration Tools - Reporting Service Configuration.
  2. Click on the Tab on the left called "Report Server Virtual Directory" and then simply press create button on the form. Give appropriate web site on the popup "Default Website" in my case.
  3. Repeat the Step six for "Report Manager Virtual Directory".
  4. Go to Database Setup Tab and if you cannot see any thing in database drop down. Click on new button. A screen will appear. Give correct credentials to create new database. Once your are done with new DB creation. Add user name and password on the main form and click apply.

I have not put the TFS DVD yet, all this was a pre-installation stuff.

Installation:

  1. Now go to the TFS Installation screen and run Windows SharePoint Service Extension, but make sure you have successfully installed SharePoint before this.
  2. At the end of the setup a popup will appear which will ask for the following URL.
  3. SharePoint Site URL (Which will be your default SharePoint Site)
    Reports
    ReportServer

    Last two are the virtual directories which will be find either under your default website in IIS, or under the website running on port 80. So, you have to check it manually and give the path.
  4. Then Run Team Foundation Server Installation but before that make sure you have done following things.

    Create a user that has full rights on SharePoint Administration. In my case, I simply, create an admin user with different user id and password. You need to provide this user authentication information during installation.

    Set SQL Server Agent / SQL Server browser Services to Auto Start.

Yeah, this was the story of my last 1.5 days :). It is my thinking, that TFS always comes up with some unique problem. So you might face some thing that is not listed here. In that case, Create post on your blog and share with us.

Cheers everyone :)

How to change default port of SharePoint

In this post, I will explain you how can we change the default port of SharePoint. 
To do that, take the following steps.

  1. Goto IIS, Right Click on Sharepoint Site and change the port (Lets say to 90)
  2. Goto Sharepoint Central Administration, Click on the operation tab then Alternate acccess mapping under global settings.
  3. Now you can see the list of sharepoint sites. Now edit the one without port, and alter the URL. in My case I change it from
    http://srv-production to http://srv-production:91

And you are done with port stuff.