Thursday, September 16, 2010

Create Custom Route Constraints

When you create an MVC route, you can add constraints to a route. For example, the following route maps browser requests to a controller named Blog and an action named Archive:

1. routes.MapRoute(
2. "BlogArchive",
3. "Archive/{entryDate}",
4. new { controller = "Blog", action = "Archive" }
5. );

routes.MapRoute(
"BlogArchive",
"Archive/{entryDate}",
new { controller = "Blog", action = "Archive" }
);

This route, named BlogArchive, maps three parameters. The controller parameter is assigned the value Blog and the action parameter is assigned the value Archive. Finally, the entryDate parameter gets its value from the entryDate parameter in the URL.

Unfortunately, this route matches too many requests. It matches:

· /Archive/12-25-1966

· /Archive/12

· /Archive/apple

You don’t want entryDate to get values like 12 or apple. These values cannot be converted into a date.

You can fix this problem with the BlogArchive route by adding a constraint to the entryDate parameter like this:
view plaincopy to clipboardprint?

1. routes.MapRoute(
2. "BlogArchive",
3. "Archive/{entryDate}",
4. new { controller = "Blog", action = "Archive" },
5. new { entryDate = @"\d{2}-\d{2}-\d{4}" }
6. );

routes.MapRoute(
"BlogArchive",
"Archive/{entryDate}",
new { controller = "Blog", action = "Archive" },
new { entryDate = @"\d{2}-\d{2}-\d{4}" }
);

This new version of the BlogArchive route includes a constraint on the entryDate parameter. The constraint requires that the entryDate parameter matches a date pattern that looks like 12-25-1966. A URL like /Archive/apple won’t satisfy this constraint and the route won’t be matched.
Two Types of Route Constraints

The URL Routing framework recognizes two different types of constraints. When you supply a constraint, you can either supply a string or you can supply a class that implements the IRouteConstraint interface.

If you supply a string for a constraint then the string is interpreted as a regular expression. For example, the entryDate constraint that we discussed in the previous section is an example of a regular expression constraint.

The other option is to create a custom constraint by creating an instance of a class that implements the IRouteConstraint interface. The URL Routing framework includes one custom constraint: the HttpMethod constraint.
Using the HttpMethod Constraint

You can take advantage of the HttpMethod constraint to prevent a controller action from being invoked unless the action is invoked with a particular HTTP method. For example, you might want a controller action named Insert() to be invoked only when performing an HTTP POST operation and not when performing an HTTP GET operation.

Here’s how you can use the HttpMethod constraint:

1. routes.MapRoute(
2. "Product",
3. "Product/Insert",
4. new { controller = "Product", action = "Insert"},
5. new { httpMethod = new HttpMethodConstraint("POST") }
6. );

routes.MapRoute(
"Product",
"Product/Insert",
new { controller = "Product", action = "Insert"},
new { httpMethod = new HttpMethodConstraint("POST") }
);

The last argument passed to the MapRoute() method represents a new HttpMethod constraint named httpMethod. If you post an HTML form to the /Product/Insert URL, then the Product.Insert() controller action will be invoked. However, if you simply request /Product/Insert with an HTTP GET, then this route won’t be matched.

By the way, the name of the constraint is not important. Only the value is important. For example, the following code works just as well as the previous code:

1. routes.MapRoute(
2. "Product",
3. "Product/Insert",
4. new { controller = "Product", action = "Insert"},
5. new { Grendal = new HttpMethodConstraint("POST") }
6. );

routes.MapRoute(
"Product",
"Product/Insert",
new { controller = "Product", action = "Insert"},
new { Grendal = new HttpMethodConstraint("POST") }
);

In this code, the HttpMethodConstraint is named Grendal. You can name the constraint anything you want and the constraint will still work.
Creating an Authenticated Constraint

You create custom constraints by implementing the IRouteConstraint interface. This interface has one method that you must implement: the Match() method.

For example, the code in Listing 1 represents a custom constraint that prevents unauthenticated access to a URL:

Listing 1 – AuthenticatedConstraint.cs

1. using System.Web;
2. using System.Web.Routing;
3. public class AuthenticatedConstraint : IRouteConstraint
4. {
5. public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
6. {
7. return httpContext.Request.IsAuthenticated;
8. }
9. }

using System.Web;
using System.Web.Routing;
public class AuthenticatedConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.IsAuthenticated;
}
}

Notice that Listing 1 contains a class that implements the IRouteConstraint interface. The Match() method checks whether the current user is authenticated and returns either True or False.

Here’s how you can use the AuthenticatedConstraint when creating a route:

1. routes.MapRoute(
2. "Admin",
3. "Admin/{action}",
4. new { controller = "Admin", action = "Index" },
5. new { authenticated= new AuthenticatedConstraint()}
6. );

routes.MapRoute(
"Admin",
"Admin/{action}",
new { controller = "Admin", action = "Index" },
new { authenticated= new AuthenticatedConstraint()}
);

This constraint prevents requests from anonymous users from being mapped to the Admin route.

It is important to understand that even though this particular route cannot be accessed by an anonymous user, a later route might map an anonymous user to the same controller and controller action. For example, if the Admin route is followed by the following Default route, then a user can access the Admin pages:

1. routes.MapRoute(
2. "Default",
3. "{controller}/{action}/{id}",
4. new { controller = "Home", action = "Index", id = "" }
5. );

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);

For this reason, you should explicitly exclude the Admin pages from the Default route with an explicit constraint.
Creating a NotEqual Constraint

The easiest way to exclude one set of pages from matching a particular route is to take advantage of the custom route constraint in Listing 2.

Listing 2 – NotEqualConstraint.cs

1. using System;
2. using System.Web;
3. using System.Web.Routing;
4.
5. public class NotEqual : IRouteConstraint
6. {
7. private string _match = String.Empty;
8.
9. public NotEqual(string match)
10. {
11. _match = match;
12. }
13.
14. public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
15. {
16. return String.Compare(values[parameterName].ToString(), _match, true) != 0;
17. }
18. }

using System;
using System.Web;
using System.Web.Routing;

public class NotEqual : IRouteConstraint
{
private string _match = String.Empty;

public NotEqual(string match)
{
_match = match;
}

public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return String.Compare(values[parameterName].ToString(), _match, true) != 0;
}
}

Here’s how you can use the NotEqual constraint to exclude the /Admin pages from the Default route:

1. routes.MapRoute(
2. "Default",
3. "{controller}/{action}/{id}",
4. new { controller = "Home", action = "Index", id = "" },
5. new { controller = new NotEqual("Admin") }
6. );

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new { controller = new NotEqual("Admin") }
);

This route won’t match any request when the controller parameter gets the value Admin. For example, this route won’t match the URLs /Admin/DeleteAll or /Admin/Index.
Creating a Local Constraint

You also can create a custom constraint that prevents a request from matching a URL unless the request is made from the local machine. This type of constraint can be useful for restricting access to website administrative pages.

Listing 3 contains the code for the LocalConstraint class.

Listing 3 – LocalConstaint.cs

1. using System.Web;
2. using System.Web.Routing;
3.
4. public class LocalConstraint : IRouteConstraint
5. {
6.
7. public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
8. {
9. return httpContext.Request.IsLocal;
10. }
11. }

using System.Web;
using System.Web.Routing;

public class LocalConstraint : IRouteConstraint
{

public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.IsLocal;
}
}

The LocalConstraint simply checks whether the current request is a local request by taking advantage of the Request.IsLocal property. This property returns the value True when the host is either equal to localhost or 127.0.0.1.

Web Deployment: Web.Config Transformation

Usually web applications go through a chain of server deployments before being finally being deployed to production environment. Some of these environments can be Developer box (Debug), QA Server, Staging/Pre-Production, Production (Release). While transitioning between these environments various settings of the web application residing in web.config file change, some of these settings can be items like application settings, connection strings, debug flags, web services end points etc.

VS10’s new web.config transformation model allows you to modify your web.config file in an automated fashion during deployment of your applications to various server environments. To help command line based deployments, Web.Config transformation is implemented as an MSBuild task behind the scene hence you can simply call it even outside of deployment realm.

I will try to go through below steps to explain web.config transformation in detail

  1. Creating a “Staging” Configuration on your developer box
  2. Adding a “Staging” Web.Config Transform file to your project
  3. Writing simple transforms to change developer box connection string settings into “Staging” environment settings
  4. Generating a new transformed web.config file for “Staging” environment from command line
  5. Generating a new transformed web.config file for “Staging” environment from VS UI
  6. Understanding various available web.config Transforms and Locators
  7. Using Web.config transformation toolset for config files in sub-folders within the project

Step 1: Creating a “Staging” Configuration on your developer box

Debug and Release build configurations are available by default within Visual Studio but if you would like to add more build configurations (for various server environments like “Dev”, “QA”, “Staging”, “Production” etc then you can do so by going to the Project menu Build --> Configuration Manager… Learn more about creating build configurations.

Step 2: Adding a “Staging” Web.Config Transform file to your project

One of the goals while designing web.config transformation was to make sure that the original runtime web.config file does not need to be modified to ensure that there would be no performance impacts and also to make sure that the design time syntax is not mixed with runtime syntax. To support this goal the concept of Configuration specific web.config files was introduced.

These web.config files follow a naming convention of web.configuration.config. For example the web.config files for various Visual Studio + Custom configurations will look as below:

web.config transform

Any new Web Application Project (WAP) created in VS10 will by default have Web.Debug.config and Web.Release.config files added to the project. If you add new configurations (e.g. “Staging”) or if you upgrade pre-VS10 projects to VS10 then you will have to issue a command to VS to generate the Configuration specific Transform files as needed.

To add configuration specific transform file (e.g. Web.Staging.Config) you can right click the original web.config file and click the context menu command “Add Config Transforms” as shown below:

Add Config Transforms

On clicking the “Add Config Transform” command VS10 will detect the configurations that do not have a transform associated with them and will automatically create the missing transform files. It will not overwrite an existing transform file. If you do not want a particular configuration transform file then you can feel free to delete it off.

Note: In case of VB Web Application Projects the web.configuration.config transform files will not be visible till you enable the hidden file views as shown below:

VB.net web.config Transform

The transform files are design time files only and will not be deployed or packaged by VS10. If you are going to xCopy deploy your web application it is advised that you should explicitly leave out these files from deployment just like you do with project (.csproj/.vbproj) or user (.user) files…

Note: These transform files should not be harmful even if deployed as runtime does not use them in any fashion and additionally ASP.NET makes sure that .config files are not browsable in any way.

Step 3: Writing simple transforms to change developer box connection string settings into “Staging” environment settings

Web.Config Transformation Engine is a simple XML Transformation Engine which takes a source file (your project’s original web.config file) and a transform file (e.g. web.staging.config) and produces an output file (web.config ready for staging environment).

The Transform file (e.g. web.staging.config ) needs to have XML Document Transform namespace registered at the root node as shown below:

xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
configuration>

Note: The transform web.config file needs to be a well formed XML.

Inside the XML-Document-Transform namespace two new attributes are defined. These attributes are important to understand as they drive the XML Transformation Engine.

Transform – This attribute inside the Web.Staging.config informs the Transformation engine the way to modify web.config file for specific configuration (i.e. staging). Some examples of what Transforms can do are:

  • Replacing a node
  • Inserting a node
  • Delete a node
  • Removing Attributes
  • Setting Attributes

Locator – This attribute inside the web.staging.config helps the Transformation engine to exactly pin-point the web.config node that the transform from web.staging.config should be applied to. Some examples of what Locators can do are:

  • Match on value of a node’s attribute
  • Exact XPath of where to find a node
  • A condition match to find a node

Based on the above basic understanding let us try to transform connection string from original web.config file to match Staging environment’s connection string

Let us examine the original web.config file and identify the items to replace... Let’s assume that the original Web Config file’s connection string section looks as below:

xml version="1.0" encoding="UTF-8"?>
<configuration>
<connectionStrings>
<add name="personalDB"
connectionString="Server=DevBox; Database=personal; User Id=admin; password=P@ssw0rd" providerName="System.Data.SqlClient" />
<add name="professionalDB"
connectionString="Server=DevBox; Database=professional; User Id=admin; password=P@ssw0rd" providerName="System.Data.SqlClient" />
connectionStrings>
....
....
configuration>


NOTE: It is not advisable to keep connection string unencrypted in the web.config file, my example is just for demonstration purposes.

Let us assume that we would like to make following changes to web.config file when moving to staging environment

  • For “personalDB” we would like to change the connectionString to reflect Server=StagingBox, UserId=admin, passoword=StagingPersonalPassword”
  • For “professionalDB” we would like to change the connectionString to reflect Server=StagingBox, UserId=professional, passoword=StagingProfessionalPassword”

To make the above change happen we will have to open web.Staging.Config file and write the below piece of code

xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="personalDB"
connectionString="Server=StagingBox; Database=personal; User Id=admin; password=StagingPersonalPassword"
providerName="System.Data.SqlClient" xdt:Transform="Replace" xdt:Locator="Match(name)" />
<add name="professionalDB"
connectionString="Server=StagingBox; Database=professional; User Id=professional; password=StagingProfessionalPassword"
providerName="System.Data.SqlClient" xdt:Transform="Replace" xdt:Locator="Match(name)"/>
connectionStrings>
configuration>

The above syntax in web.staging.config has Transform and Locator attributes from the xdt namespace. If we analyze the connection string node syntax we can notice that the Transform used here is “Replace” which is instructing the Transformation Engine to Replace the entire node

Further if we notice the Locator used here is “Match” which is informing Transformation engine that among all the “configuration/connectionStrings/add” nodes that are found, pick up the node whose name attribute matches with the name attribute of node in web.Staging.config.

Also if you notice web.Staging.config does not contain anything else but the connectionStrings section (i.e. it does not have and various other sections that web.config file usually has, this is because of the fact that the Transformation Engine does not require a complete web.config file in web.staging.config. It does the merging for you thus saving you duplication of all the rest of the sections in web.config file.

Simplest Approach: If you do not mind replicating the entire web.config file in web.staging.config then you can certainly do so by copying the entire web.config content into web.staging.config and change the relevant nodes inside web.staging.config. In such a situation you will just have to put xdt:Transform="Replace" attribute on the topmost node (i.e. configuration) of web.staging.config. You will not need xdt:Locator attribute at all as you are replacing your entire web.config file with web.staging.config without Matching anything.

So far we have seen one Transform (i.e. Replace) and one Locator (i.e. Match), we will see various other Transforms and Locators further in the post but first let us understand how we can produce the Transformed web.config file for the Staging environment after using original web.config and web.staging.config

Wednesday, July 21, 2010

Rememberable trip to Srinagar

We(me and my seven colleagues) plan to went Srinagar(The heaven on Earth) on this new year. We plan to go by hiring a car on rent, but unfortunately we got a very good driver. Actually driver drunk much that he was unable to drive properly. We began our journey from Amritsar by taking blessing from Harmandir Sahib.


Because of driver our trip is more interesting, remember able. We covered 30 km in 2 hours(from amritsar to batala). Then we kiceked the driver away at batala railway station. We enjoyed with other peolpe at station..


Then we went to Jammu by train. Early morning we reached there and eat some stuff to full the tummies. Then we again hired a four wheeler for Srinagar... The way of Srinagar is very tough. We reached there by 8 pm. we all were very tired. we take hot bath at the restaurent. Some of us are great drunkers. We enjoyed the night with drink. Then we ready for the next day. We planned to go to GulMarg next day.


Gulmarg is actually a very romantic place. We missed girls a lot. The kashmirans are very sexy, good looking with only face seeing under the black burka.


I think i cant share the feeling of there in words. But before showing pictures i thing i want to say that the people of there were harami......

we also enjoyed mountaineering there. One of us is a fat guy. he did not able able to do so. because uski f_ _ gyi thi. We enjoyed there very much and came back in evening to Srinagar. We then went to Lal Chowk, a famous place, attraction point of terrorists. Then went to rooms earlier because the shops used to close at 9.30 pm.. Then we enjoyed with lots of wine. One of us knew about lal kitaab. He ade fun of all of us.

Next day we Planned to roam in Srinagar local places. But unfortunately we only enjoyed the beauty of DAL Lake. we had mixed emotions because rain of snow was started, we enjoyed earlier but driver come to know us that we had to go from there, if snow fell in masses then we will stuck there for days. we tried our best to paas the Srinagar border, army refused us to cross. So we stuck there. now we can neither roam nor go back. We paased day at border then again came back to Hotel. Same thing happened next day. We wished to go back now instead to enjoy there. our palns to go to Sonmarg, PatniTop now spoiled. we spent the whole day near border and Lal Chowk. we felt that if rain continues, we had to stay there for a week or more. So we decided to look for some Gurdwara for stay. We hopefully searched it and at last found it near Airport. We stayed there for night. We planned to cross the border before 4 am in the morning. But failed because army people stayed there whole day, night 24 hour service provided by them to help people. But this time we were lucky, snow did not fall for whole night and sky was clear in the morning. Army give us the chance to cross the border. finally we were out of the Srinagar. Nobody wanted to go somewhere else in srinagar because there were snow all around of us. That time we come to know why srinagar called the Heaven of Earth. The scenes were amazing.








Last thing i want to say