Tuesday, 7 October 2008

Using Master Pages in ASP.NET 2.0

Master Pages are one of the key features of ASP.NET 2.0 that enables developer to easily manage standard look and feel through out whole web site. Below article discuss few key features of it and usage of it.

Content Place Holder Controls ASPX Control


Master Pages distinct those selves from normal Web forms by having following features.

* Master page is identified by @Master directive

<%@ Master Language="VB" CodeFile="mainlayout.master.vb" Inherits="mainlaout" %>

* Have to have <header> and <body> tags

* Can contain ContentPlaceHolder ASPX control

Content Place Holder control allows to define areas where each individual page (which uses this master page) decide content to be included. In other words if master page is a template ares defined by these controls are variable to be replace by using pages.

E.g.

 <table>
  <tr>
   <td>
    <asp:contentplaceholder id="sideContent" runat="server"> </asp:contentplaceholder>
   </td>
   <td>
    <asp:contentplaceholder id="mainContent" runat="server"></asp:contentplaceholder>
   </td>
  </tr>
 </table>

Master page can have any other normal controls also.


Content ASP Control

Content controls are use to plug content into "Content Place Holder" areas of master pages on normal pages where master page is used. On these pages, only editable areas are where you have put Content controls. Rest of the page is decided by the master page (this can be easily see in Visual Studio 2005 designer).


<asp:content id="HomeMain" contentplaceholderid="mainContent" runat="Server">
</asp:content><h1> This is a example header </h1>
.... (any other control))



You can place any standard HTML or ASP control inside Content controls and they will be rendered on that particular client page with rest of the master page controls.


PreInit Method

When browser request a particular page (which uses a master page) master page controls are injected to the standard page and placed correctly in hierarchy of controls. This process happens after page "PreInit" event occur and before page "Init" event occur.

There fore you can programatically manipulate content in master page in side the PreInit event handler method.

You can even change the master page of the processing page.

E.g.

Me.MasterPageFile = "~/myotherlayout.master"


URL Rebasing

Since master page and serving page can be in different directories and master page inject controls into serving page, there could be occasions where we find broken links/paths.

For example consider following scenario.

Master page location: /root/mysite/mainlayout.master
Serving page location: /root/mysite/pages/myhome.aspx
Image location: /root/mysite/images/myheader.png

We have defined a image in master page as follows

<img src="http://www.blogger.com/images/myheader.png" alt="1" />


When serving page (myhome.aspx) renders by ASPX engine, first master page contents are injected into the serving page. There fore above image tag also will be injected into the serving page. When above image tag injected to serving page, relative path defined in the src attribute direct browser to wrong place (i.e. /root/mysite/pages/images/myheader.png).

In order to solve this we can make image tag server control. All server control paths are rebased while inject processing is happening.

E.g.

<img src="http://www.blogger.com/images/myheader.png" runat="server" alt="2"/>



Setting Headers and Titles

Since header part of the page is contained in master page, there is no way to manipulate in web form using normal methods (by putting

However there are few ways you can set Title of the web form.

1. Using title attribute in @Page directive
E.g.
<%@ Page Language="VB" MasterPageFile="~/mymainlayout.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Title="Home Page" %>

2. Using Title property of the web form

E.g.
Me.Title = "My Home Page"


Site Wide Masters

There are 3 ways to associate master pages with a web form.

1. Using Master attribute in @Page directive

E.g.

<%@ Page Language="VB" MasterPageFile="~/mymainlayout.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Title="Home Page" %>

2. Setting MasterPageFile property of the web form in "PreInit" method or earlier

E.g. (shown above)

3. Define default master page for all web forms in web configuration file

E.g.

<configuration> <system.web> <pages master="mymainlayout.master">
</pages> </system.web>



That's the very basic about master pages, hoping to write more as I get my self more familiar with master pages.

Friday, 3 October 2008

Creating copy of live MS SQL Database in the same serve

There are occasions where we (developers) need to copy databases in the same server. Consider a situation where you want to get a copy of production database for testing purpose and you can’t move it into a new server (because of resource/budget restrictions).

Unfortunately MS SQL server doesn’t provide direct method to copy databases in same server (you can copy database between servers using Copy Database Wizard).

There fore we need to depend on alternative methods.

Following 3 steps show how you can achieve this with T-SQL statements.


1. Backup original database to disk

BACKUP DATABASE TestDB TO DISK = 'D:\TestDB\Test.dat'

  • “TestDB” is the name of the original database name
  • TO DISK indicate we are storing the backup in backup device (in this case it is hard disk)Backup device will be created in given file ('D:\TestDB\Test.dat')

2. Drop the destination database if it exists

IF EXISTS(SELECT * FROM sysdatabases WHERE name = 'TestDBCopy')

BEGIN

SET @query = 'DROP DATABASE TestDBCopy'

EXEC (@query)

END

  • Destination database is the copy that we are going to create (TestDBCopy)

3. Restore with a new database

RESTORE DATABASE TestDBCopy FROM DISK = 'D:\TestDB\Test.dat'

WITH

MOVE 'TestDB' TO 'D:\TestDB\TestDBCopy.mdf',

MOVE 'TestDB_Log' TO 'D:\TestDB\TestDBCopy.ldf',

FILE = 5

  • “TestDBCopy” is the name of the new database
  • It will be restored from full backup set we created in the step 1 (Test.dat)
  • Since it is in same server and files are already exists we need to move (rename log file and datafiles)

E.g. Move ‘TestDB’ TO 'D:\TestDB\TestDBCopy.mdf'

In here ‘TestDB’ is the logical name of the data file and 'D:\TestDB\TestDBCopy.mdf' section indicate full name of the new data file in OS.

  • FILE = 5 indicate DBMS to pickup 5th file set from the backup device.

That’s it, now you can go back to SQL Server Management Studio and see how your old copy and new copy will work.

Tuesday, 30 September 2008

Increasing IIS7 request filtering limits

As a new security enhancement feature, IIS7 has mechanism to filter out all requests which are larger than specific limit (default is 30Mb).

However there are situation where some web servers require handling very large requests such as Audio/Video file uploads.

In such a scenario administrators are required to change this default setting. This can be achieve following below steps.

  1. Open a command prompt window with administrator privileges
    1. Start->Run-> runas /user:Administrator cmd
  2. Change your current directory to Internet Server directory
    1. cd c:\Windows\systems32\inetsrv
  3. Then run following command

appcmd set config "My Site/MyApp" -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600 -commitpath:apphost

maxAllowedContentLength is the maximum request size to be set. In above example we are setting it to 100Mb.

Friday, 19 September 2008

Developing Group Calendar using WEBDAV


Though Microsoft Outlook provide you very good interface to access and share your information in a particular community. There are circumstances where your want your own style to be apply to data provided by Exchange Server. For example consider a situation where you want to create your own group calendar (without limiting to Outlook group calendar UI) with few more additional information on it and presented in your own UI to suite particular requirement. In such a scenario you can develop a group calendar by accessing your Exchange server information store through WEBDAV requests.


Following example shows how this can be done in a PHP web application.



What is WEBDAV?


WebDAV stands for Web-based Distributed Authoring and Versioning. It is an extension for Hyper Text Transfer Protocol (HTTP) that allows users to collaboratively manage file on remote servers using HTTP requests.


Standard HTTP supports following 8 methods (usually called verbs):

  • GET / POST / HEAD / PUT / DELETE / TRACE / OPTIONS / CONNECT


WebDAV add few more method as extensions. Following are some of them.

  • PROPFIND
  • PROPPATCH
  • MKCOL
  • SEARCH
  • COPY
  • MOVE
  • LOCK
  • UNLOCK


WebDAV also have few extensions such as CalDAV and GroupDAV which serves for specific requirements.


In following example we use WebDAV requests to search through Exchange Server Store to find out calendar information for particular set of Exchange users.


More information can be found on following links:




Enabling WebDAV in the Server


In our example we use IIS to send WebDAV requests. In order to send WebDAV request through IIS server, we need to enable it. Enabling it is really easy. Follow below steps.

  • Install WebDAV
    • WebDAV is pre-installed in Windows 2000 and where IIS 5 is used
    • If you are using IIS 6
      • Go to "Add or Remove Programs" in Control Panel and run the Windows Components Wizard
      • Can find WebDAV under Application Server Internet Information Services World Wide Web Service WebDAV Publishing
  • Enabled it in IIS server
    • Open IIS server control panel snap-in
    • Click on Web Service Extension node
    • Check WebDAV status is "Allowed" in the right hand pane
    • If it is not allowed right click on the WebDAV extension icon and choose "Allow" from available tasks

For more information follow below link

http://www.windowsnetworking.com/articles_tutorials/WebDAV-IIS.html


OpenSSL and configuring it


OpenSSL is an open source implementation of SSL and TSL protocols. It allows secure connections over web, through encrypted data communication. Following example uses OpenSSL to access Exchange Server information store over SSL connection. Normally exchange server information should be only access via SSL connection to prevent any kind of security breaches.

My example below uses PHP as the scripting language, there for we need to enable OpenSSL for PHP processor which is used by IIS server to render PHP pages.

OpenSSL comes as an extension to PHP. Like most of the standard extensions for PHP (in windows) this one is also not enabled by default. There fore we need to enable it before starting to access Exchange server through SSL.

Follow below steps (on windows machine)

  • Make sure OpenSSL DLL is in PHP extension directory
  • Locate the php.ini file for your PHP installation and open it in a text editor
  • Locate the extension part of the that file and make sure to un-comment line against OpenSSL library (simply remove the semicolon mark)
  • Save the php.ini file
  • Re-start the IIS server to take this change effect

If you want to make sure OpenSSL extension is correctly installed, use phpinfo() function (out put of the phpinfo() will show a complete webpage) and check the "Registered Stream Socket Transports" section. In that section "ssl" should be appear as one of the registered stream.

For more information on PHP extension configuration, please visit below links.

Pre-requisite PHP scripts

In order to make our life easy while developing this example, we use following classes which were developed by Troy Wolf. You can find similar examples and more information on these PHP helper classes on his web site (http://www.troywolf.com/articles/php/exchange_webdav_examples.php).

  • class_http.php – enables caching for WebDAV requests
  • class_xml.php – accept raw XML input and returns standard PHP objects which can be easily manipulate

These files can be downloaded from Troy's website (if not please contact me through email).

WEBDav Request


The most important part of this example is constructing WebDAV request to send to Exchange server. Following example code show how to access calendar events for a particular user called "mpasharp".

Note: WebDAV request is a XML request object.



<?xml version="1.0"?>

<a:searchrequest xmlns:a="DAV:" xmlns:s="http://schemas.microsoft.com/exchange/security/">

<a:sql>


SELECT "urn:schemas:calendar:location", "urn:schemas:httpmail:subject",

"urn:schemas:calendar:dtstart", "urn:schemas:calendar:dtend",

"urn:schemas:calendar:busystatus", "urn:schemas:calendar:instancetype", "urn:schemas:mailheader:sensitivity"

FROM Scope('SHALLOW TRAVERSAL OF "https://yourexhangeserver/Exchange/mpsharp/calendar"')

WHERE NOT "urn:schemas:calendar:instancetype" = 1

AND "DAV:contentclass" = 'urn:content-classes:appointment'

AND "urn:schemas:calendar:dtstart" &gt; '2008/09/01 00:00:00'

AND "urn:schemas:calendar:dtend" &lt; '2008/09/07 23:59:00'

ORDER BY "urn:schemas:calendar:dtstart" ASC

</a:sql>

</a:searchrequest>



Querying exchange store is similar to querying normal RDBMS database. Above WebDAV request shows how standard SQL type SELECT method has been used to retrieve information from Exchange server.


We use this SQL query with conjunction of WebDAV SEARCH method. This is denoted in the first element of the request.


<a:searchrequest xmlns:a="DAV:" xmlns:s="http://schemas.microsoft.com/exchange/security/">


In FROM clause you have to specify exchange server URL to calendar your are looking for (highlighted in RED).


"WHERE" clause allows us to place conditions on query. In above example we are interested in calendar appointments which are start date in between 2008 Sep 01 00:00:00 hour and 2008 Sep 07 23.59:00 hour. It also place a restriction on "calendar:instancetype".


Instance type field specifies the type of an appointment in the calendar. There 4 types of exchange server appointment types.

  • Single appointment = 0
  • Master recurring appointment = 1
  • Instance of a recurring appointment = 2
  • Exception to a recurring appointment = 3


According to above example we are not interested in "Master recurring appointments".


Using ORDER BY clause, you can order result set returned by exchange server store. In above example we order result set on appointment start date in ascending order.


More information on querying Exchange store can be found on MSDN website.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/wss_references_webdav.asp



Example of How to use


After constructing the WebDAV request, using this in practical is just a matter of coding it in your preferred language.


Here how we can do it in PHP.


  • First include Troy's helper classes so we need to code less


require_once("class_http.php");

require_once("class_xml.php");


  • Create a function so we can use every user in the group. This function accepts user name as a parameter and build HTML table with all calendar event for that particular user.


function create_user_calendar_table($username) {


}


Below code should place inside this function.


  • We need administrator user to access Exchange server store. This user should have access to all users calendars in the group


$exchange_server = "https://mail.myexample.com";

$exchange_username = "applicationmailuser";

$exchange_password = "password";


  • We use Troy's http class object to send the XML-formatted WebDAV request to the Exchange Server and to receive the response from the Exchange Server. The response is also XML-formatted.


$h = new http();


  • Set some standard header in WebDAV request


$h->headers["Depth"] = "0";

$h->headers["Translate"] = "f";


For more information on these headers, please visit the Troy's website.


  • Finally set the WebDAV request


$h->xmlrequest = '<?xml version="1.0"?>';

$h->xmlrequest .= <<<END

<a:searchrequest xmlns:a="DAV:" xmlns:s="http://schemas.microsoft.com/exchange/security/">

<a:sql>

SELECT "urn:schemas:calendar:location", "urn:schemas:httpmail:subject",

"urn:schemas:calendar:dtstart", "urn:schemas:calendar:dtend",

"urn:schemas:calendar:busystatus", "urn:schemas:calendar:instancetype", "urn:schemas:mailheader:sensitivity"

FROM Scope('SHALLOW TRAVERSAL OF "$exchange_server/Exchange/$username/calendar"')

WHERE NOT "urn:schemas:calendar:instancetype" = 1

AND "DAV:contentclass" = 'urn:content-classes:appointment'

AND "urn:schemas:calendar:dtstart" &gt; '2008/09/01 00:00:00'

AND "urn:schemas:calendar:dtend" &lt; '2008/09/07 23:59:00'

ORDER BY "urn:schemas:calendar:dtstart" ASC

</a:sql>

</a:searchrequest>

END;



  • Following statement does it all. Fetch method in Troy's http class calls SEARCH method in WebDAV extension.


if (!$h->fetch($exchange_server."/Exchange/$username/calendar", 0, null, $exchange_username, $exchange_password, "SEARCH")) {

echo "<h2>There is a problem with the http request!</h2>";

echo $h->log;

exit();

}


  • Then user Troy's XML class to construct object from XML response returned


$x = new xml();

$x->fetch($h->body)



  • Now create the table rows with information you got


foreach($x->data->A_MULTISTATUS[0]->A_RESPONSE as $idx=>$item) {


echo '<tr>'

.'<td>'.$item->A_PROPSTAT[0]->A_PROP[0]->E_SUBJECT[0]->_text.'</td>'

.'<td>'.$item->A_PROPSTAT[0]->A_PROP[0]->D_DTSTART[0]->_text.'</td>'

.'<td>'.$item->A_PROPSTAT[0]->A_PROP[0]->D_DTEND[0]->_text.'</td>'

.'<td><a href="'.$item->A_HREF[0]->_text.'">Click to open via OWA</a></td>'

.'<td><a href="Outlook:calendar/~'.$item->A_PROPSTAT[0]->A_PROP[0]->E_SUBJECT[0]->_text.'">Click to open via Outlook</a></td>'

."</tr>\n";


}



  • If you want to see how Troy's class have structured XML response into a class structure, use following code fragment


echo "<pre>\n";

print_r($x->data);

echo "</pre>\n";



That's it. You can call this function for every user in your group and construct a neat group calendar.




Thursday, 11 September 2008

Different between gmmktime and mktime PHP functions

PHP contains very useful date and time related functions. However when using these in practice, you should understand them carefully. Because wrong use of these functions, can cause very hard to find bugs in your applications.

One of the common mistake PHP developers does is, ill usage of gmmktime() and mktime() functions, without knowing their proper meaning.

First let’s look at what gmmktime and mktime does.

Both these functions returns Unix time stamp. Unix time stamp is number of seconds elapse since epoch (1970 January 01 00:00:00 hours in GMT time zone)

These functions have following signature:

int mktime ([ int $hour [, int $minute [, int $second [, int $month [, int $day [, int $year [, int $is_dst ]]]]]]] )
int gmmktime ([ int $hour [, int $minute [, int $second [, int $month [, int $day [, int $year [, int $is_dst ]]]]]]] )
As you can see above, these two have identical signatures and all arguments are optional.

So different lies in internal functionality

mktime function assumes, parameters stated to it self are in servers time zone and (internally) use server's time zone information to calculate time stamp.

gmmktime function assumes, parameters stated to it self are in GMT (standard) time zone and ignore servers time zone information when calculating time stamp.

One of the important concepts that you should remember here is, time stamp is time zone independent.

Let’s take an example to clear this out.

Consider the date (and time) 1970 January 02:00:00 (2 AM in the morning), and our sample server (who is running the PHP scripts) resides in GMT +1 time zone.

Following lines are executed on the sample server:


            print_r(mktime(2,0,0,1,1,1970));
            print(“<br/>”);
            print_r(gmmktime(2,0,0,1,1,1970);

Below is the out put we will receive:

3600
7200

This is bit confusing at first glance (specially when you are not totally familiar with meaning of what these functions do). Lot of people expect to return something less by gmmktime() function than mktime() function, simply because GMT is behind the GMT + 1 time zone.

However, above results are correct. What actually happened while executing can be explained as below.

When mktime() function execute, it assume time values pass to it self are in server’s time zone. There fore in order to figure out time stamp, it first calculates the given time in GMT time zone (because all time stamps are time zone independent, by calculating them in GMT). So when given time converted to GMT, mktime() function receive new date and time as 1970 January 01 01:00:00 hours. In simplest words, when time is 2AM in GMT + 1 time zone, we all know it is 1AM in GMT. Time stamp of the 1970 January 01 01:00:00 is 3600 (One hour passed epoch). There fore mktime() returns 3600 as time stamp.

In contrast to that, when gmmktime() function execute, it assume time values pass to it self are in GMT time zone. There fore, it doesn’t require converting them to GMT time zone again before calculating the time stamp. So gmmktime() calculate time stamp for 1970 January 01 02:00:00, which is equal to 7200 (2 hours passed epoch).

Hope you understand the different now.