Sorted By: Tag (deployment)

Remove Trailing Slash From the URLs of Your ASP.NET Web Site With IIS 7 URL Rewrite Module

One of the aspect of SEO (Search Engine Optimization) is canonicalization. In this blog post, we will see how easy to work with IIS Rewrite Module in order to remove evil trailing slash from our URLs
2011-09-11 07:08
Tugberk Ugurlu


redirect-me-baby

One of the aspect of SEO (Search Engine Optimization) is canonicalization. Canonicalization is the process of picking the best URL when there are several choices according to Matt Cutts, the head of Google’s Webspam team.

Here is how Matt Cutts explains what canonical URL is :

“Sorry that it’s a strange word; that’s what we call it around Google. Canonicalization is the process of picking the best URL when there are several choices, and it usually refers to home pages. For example, most people would consider these the same URLs:

  • www.example.com
  • example.com/
  • www.example.com/index.html
  • example.com/home.asp

But technically all of these URLs are different. A web server could return completely different content for all the URLs above.”

If you have multiple ways of reaching your web page (as above), then you need to sit down because it is time to make some decisions my friends.

Trailing Slash is Evil

Let’s assume that we have created a web application, an ASP.NET MVC app because we are so cool. We have our pretty URLs as well.

Let’s go to a page on our web site :

http://localhost:55050/Home/About

image

And another page :

http://localhost:55050/Home/About/

image

We have got the same page content. As we have mentioned before, these two will be treated as two different web page and it will confuse the search engine a bit (even if they are so smart today).

The solution is pretty simple : when a page is requested with trailing slash, then make a 301 (permanent) redirect to the non-trailing-slash version.

IIS URL Rewrite Module

There are several ways of doing that with ASP.NET architecture :

  • You could write your own HttpModule to handle this.
  • You could do a poor man’s redirection on your controller (on your page load if the application is a web forms application).
  • You could use IIS URL Rewrite Module to easily handle this.
  • And so on…

In this quick blog post, I will show how we can implement this feature for our whole web site with IIS Rewrite Module.

URL Rewrite Module is an awesome extension to IIS. Installing it to your web server is also pretty easy if you haven’t got it yet. Just run the Web Platform Installer on your server, and make a search for “url rewrite”. Then the filtered result will appear and you will see if it is installed or not :

image

After you have it, you will see the management section inside your IIS Manager under IIS section :

image

Cut the crap and show me the code

Now, we are all set up and ready to implement this feature. As it is usual nearly for all Microsoft products, there are thousands (ok, not thousand but still) of way to approach this feature but the easiest way of implementing it is to write the logic inside your web.config file.

As you already know, there is a node called system.webServer under the root configuration node. IIS Rewrite Module reserves a node under system.webServer section and allow us to configure the settings there pretty easily. What we will do is to only write the following code under system.webServer node :

<rewrite>
  <rules>
  
    <!--To always remove trailing slash from the URL-->
    <rule name="Remove trailing slash" stopProcessing="true">
      <match url="(.*)/$" />
      <conditions>
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Redirect" redirectType="Permanent" url="{R:1}" />
    </rule>
    
  </rules>
</rewrite>

What this code does is to tell the module to remove the trailing slash from the url if there is one and make 301 permanent redirect to the new URL.

Don’t allow the code to freak you out. It might look complicated but there are good recourses out there to make you feel better. Here is one of them :

Using the URL Rewrite Module by Ruslan Yakushev

When you run your site after this implementation and navigate to /Home/About/, watch what is going to happen :

image

image

Isn’t that awesome? A little effort and perfectly clean way of implementing the 1 of a thousand parts of canonicalization.

Some Gotchas

  • In your development environment, if you run your web site under Visual Studio Development Sever, you won’t be able to see this feature working. You need to configure your application to run under at least IIS Express to see this feature working.
  • When you deploy your web site and see this feature not working on your server, it is highly possible that you misconfigured something on your server. One of the misconfiguration you might have done could be setting the overrideModeDefault attribute to Deny for rules under <sectionGroup name="rewrite"> inside your applicationHost.config file.
  • If you are on a shared hosting environment and you see this feature not working, then ask your provider if they have given you the permission of configuring this part.

File By File Deployment Process with MSDeploy Inside Visual Studio

Have you ever used 'MSDeploy' inside Visual Studio 2010 and wished a nice process bar while publishing a web application? There is even a better way!
2011-03-05 08:32
Tugberk Ugurlu


image

Deployment of your web application is not hard anymore. It is so much easier than before with 'MSDeploy'. MSDeploy was introduced to us with Visual Studio 2010. It takes all the application and publish it how we want.

I am not going to explain what MsDeploy is and how it works. This is bot the topic here. I assumed that you are reading this post because you have had a least one or two experience with MSDeploy inside Visual Studio 2010.

When we are publishing an application with one click publish button, you probably noticed a little green world icon with coming and going tiny things on the left bottom side. That think is showing the process of your publishing but not so much informative. I thought that would be cool to view the remaining time of the process but Visual Studio has a lot better feature which I didn’t know until last night! Indeed, we have a chance to view the process file by file from output window of visual studio 2010 while publishing your application. That is pretty darn cool. But how we can configure this feature so that we could be able to view that.

imageWe need to go over to Tools > Options. Then expend the Projects and Solution section from the list on the window. You will find Build and Run section under that which will give you a window which will look like as it is here on the left. You notice that there is an option called 'MsBuild project build output verbosity'. There are five options there and it is set to Minimal by default. I changed it to Normal which is enough for our purpose here.

Save your settings and then expend the output window. You can start your publishing process now and you will see which file is now being deployed by MSDeploy as you can also see on the above screenshot. Yes, awesome… Smile Now, think about twice before using an FTP client again Smile

Local IIS 7.0 - CS0016: Could not write to output file / Microsoft.Net > Framework > v4.0.30319 > Temporary ASP.NET Files

Solution to an annoying error message! You are getting 'Could not write to output file 'c:\Windows\Microsoft.NET\Framework\....' message? You are at the right place.
2011-03-05 08:18
Tugberk Ugurlu


This week I went nuts over my local IIS. I have never swore to a machine that much in my whole life. I am sure of that! The problem is not that big and probably not worth to be written on a blog post I am going to write it anyway because the solution was hard to find on the internet. Maybe this post will help you to fix the problem as I did and you will stop swearing to you machine as I did Smile

Let’s get to the point. I am no IIS guy! Seriously!  The so called Cassini (the tiny web server which pops up when you run a web application on Visual Studio) was so enough for me for over 2 years. But no more enough. I figured that IIS can not be ignored by me anymore. How can I get that point? That’s not the issue here. The issue is that I tried to run an ASP.NET MVC 3.0 application under my local IIS 7.0 and got a very annoying error. Which is;

Compiler Error Message: CS0016: Could not write to output file 'c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\62d43c41\27d749ca\App_Code.7lodcznm.dll' – 'Access denied.'

imageTemporary ASP.NET Files folder (c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files) was the the one with the problem here. First, I thought that the problem is related to security permissions on the folder and I was right.

I right clicked on the Temporary ASP.NET Files folder and go to the security tab. I noticed that there is user called IIS_IUSRS and that guy has the full control permission. But apparently that was not enough.

The Temporary ASP.NET Files  and C:\Windows\temp folders should have IIS_WPG and NETWORK SERVICE users with the full control permission. I have no idea why C:\Windows\temp folder needs that but I have no effort left to try to find that. Instead, I am writing a blog post about the problem. Maybe latter I will get to that and figure it out, too Smile

Once you applied those setting, restart your IIS and try to run your application again. The error should be gone by now.

I suffered a lot by trying to find the right method for the problem and I hope you didn’t have to go through hell over this.

Hope this helps Smile

Running ASP.NET MVC Under IIS 6.0 and IIS 7.0 Classic Mode : Solution to Routing Problem

In this blog post, we will see how to run ASP.NET MVC application under IIS 6.0 and IIS 7.0 classic mode with some configurations on IIS and Global.asax file...
2011-02-26 07:31
Tugberk Ugurlu


Highway sign

I wrote a blog post on Deployment of ASP.Net MVC 3 RC 2 Application on a Shared Hosting Environment Without Begging The Hosting Company couple of months ago. The solution was working for most case scenarios if the server is configured properly for ASP.NET Routing. Other working case I have seen was the applications which are running under IIS 7.0 integrated mode. Under IIS 7.0 integrated mode, no special configuration necessary to use ASP.NET Routing.

As we know, one of the most beautiful parts of ASP.NET MVC framework is Routing. We have nice, clean, extensionless URLs thanks to routing and this is becoming an issue under IIS 6.0 and IIS 7.0 classic mode.

When we typing the path of a web site page inside the address bar of our web browser, we are making a request against server. If our web application is running under any version of IIS, the request hits ASP.NET framework on certain conditions. Especially, Older versions of IIS only map certain requests to the ASP.NET framework. If the extension of the web request is aspx, ashx, axd or any other extensions which is specific for ASP.NET framework are being mapped to ASP.NET framework. So, in a MVC application the requests are not being mapped to ASP.NET framework. 

 image
(You will be getting this 404 exception when you hit the extensionless URL of your application)

No, do not throw away your precious, new born ASP.NET MVC application which you have created working along with Nuget PMC (which is perfect), EFCodeFirst and any other cool newbie stuff.  There are optional solutions for this problem and they are not like hard things to implement.

Although, if you have a Windows Server 2003 and thinking about going up to IIS 7.0 integrated or classic mode, stop right there my friend ! Because, IIS 7.0 is not compatible with Windows Server 2003. So you are stuck with IIS 6.0 for now and keep reading for the solution Smile

The solutions are optional as indicated. They depend on what kind of powers you have over your server. Here is the list of solution you might be interested;

Option 1 : I am the guy with the full control power over my server and I want to keep extensionless URLs

If you have full access over your server, you could create so called Wildcard Script Map so that you can use the default ASP.NET MVC route table with IIS 7.0 (in classic mode) or IIS 6.0. This Wildcard Script Map will map all requests to the web server to the ASP.NET framework.

I have no experience with this option, though. I had a problem like this within this week, I have solved it with the following option and didn’t want to use this one even if I have full control over my server. I am not a server pro, so I won’t be making any comments on how this will effect the requests flow made against your server. I just thought that “man, every single request which made against my server will be mapped to ASP.NET framework. This could effect the speed of the delivery process.” and that how I skipped this option.

And, bad news guys Sarcastic smile Microsoft, also, indicated the following line of sentence one of their web site;

“Be aware that this option causes IIS to intercept every request made against the web server. This includes requests for images, classic ASP pages, and HTML pages. Therefore, enabling a wildcard script map to ASP.NET does have performance implications.”

To implement this feature, you need to follow some steps and here is the text I grabbed from http://asp.net/ ;

 

image_thumb[5]

Here's how you enable a wildcard script map for IIS 7.0 (classic mode):

  1. Select your application in the Connections window
  2. Make sure that the Features view is selected
  3. Double-click the Handler Mappings button
  4. Click the Add Wildcard Script Map link
  5. Enter the path to the aspnet_isapi.dll file (You can copy this path from the PageHandlerFactory script map)
  6. Enter the name MVC Click the OK button

 

 

 

image_thumb[4]

Follow these steps to create a wildcard script map with IIS 6.0:

  1. Right-click a website and select Properties
  2. Select the Home Directory tab
  3. Click the Configuration button
  4. Select the Mappings tab
  5. Click the Insert button
  6. Paste the path to the aspnet_isapi.dll into the Executable field (you can copy this path from the script map for .aspx files)
  7. Uncheck the checkbox labeled Verify that file exists
  8. Click the OK button

 

Option 2 : I am the guy who has the full control power over my server, cares about performance and not care about URLs

This option is the one of the other option I do not like very much but maybe you will Smile So here is the deal;

We will simply add Extensions to the Route Table so that older versions of IIS can pass requests to the ASP.NET framework. This option requires changes inside Global.asax file of you application and some addition work on IIS for modifying the Default route so that it includes a file extension that is mapped to the ASP.NET framework.

Let’s see the RegisterRoutes method inside your Global.asax file;

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

As you see here on line 7, we are aiming to get URLs without extension. Let’s see what it needs to be look like after we change it in order to implement this option;

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

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


        }

Here, we are assigning .mvc extension for every URL for controller name.

I want to warn you about your links inside your views. If you created them by hard coding, now you are officially screwed my friend. Because, you either have to change all of them by hand or need to implement option 1 in order to keep them unbreakable. If you used ActionLink or RouteLink kind of way, then your are good to go. Changes will be handled by MVC Framework for you.

Therefore, to get ASP.NET Routing to work, we must modify the Default route so that it includes a file extension that is mapped to the ASP.NET framework.

This is done using a script named registermvc.wsf. It was included with the ASP.NET MVC 1 release in C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 1.0\Scripts, but as of ASP.NET 2 this script has been moved to the ASP.NET Futures, available at http://aspnet.codeplex.com/releases/view/39978.

Executing this script registers a new .mvc extension with IIS. After you register the .mvc extension, you can modify your routes in the Global.asax file so that the routes use the .mvc extension.

After this implementation, your URLs will look like this;

/Home.mvc/Index/

/Product.mvc/Details/3

/Product.mvc/

Option 3 : I am the guy who has no control power over my server, not care about URLs (If you care, it does not matter. You have no choice)

This option is the easiest way of make your application up and running within minutes depending on your application structure. Only you need to do here is; making some changes inside your Global.asax file, recompiling your application and publishing it into your server. That’s all. Let’s see how our new RegisterRoutes method inside Global.asax file needs to be look like;

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

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


        }

Look at line 7. Isn’t it familiar? It is one of the ASP.NET framework extensions. You could add .aspx or whatever you want from ASP.NET framework extensions. It is already registered into the Default route so the requests will be mapped to the ASP.NET framework.

I hope that this is the solution you are looking for your problem.

Deployment of ASP.Net MVC 3 RC 2 Application on a Shared Hosting Environment Without Begging The Hosting Company

After the release of ASP.Net MVC RC 2, we are now waiting for the RTM release but some of us wanna use RC 2 already... But how to deploy it on a shared hosting acount is the mind-exploding problem...
2010-12-18 12:41
Tugberk Ugurlu


UPDATE on 2011, 02.26

I have wrote another blog post on ASP.NET MVC Deployment problems you might have related to your server. If you are still having problems (especially, if you are getting 404 exceptions for extensionless URLs), you might want to have a look at on "Running ASP.NET MVC Under IIS 6.0 and IIS 7.0 Classic Mode : Solution to Routing Problem"

asp-net-mvc-3.gifOn the 10th of December in 2010, Microsoft ASP.Net MVC team has released the MVC 3 RC 2 and it has some good stuff inside which RC 1 didn't have. It is not so much different but there are some breaking changes, especially ViewBag thing.

You could find more information about ASP.Net MVC RC 3 goodies on ScootGu's blog post or Phil Haacked blog post.

The MVC 3 RC 2 has come from go-live-license so you can use this in production if you wish. But the main problem rises here if you are in a shared hosting environment. As you know, shared hosting providers are not willing to install the new releases unless it is for sure that there is no detected bug in the package.

I thought that would be a big problem for me [because I am still in shared hosting environment :)] but deploying the necessary assemblies as manually is the solution. Scott Hanselman has a great post on how to deploy an MVC 3 application into a shared hosting environment. The article covers all the necessary steps. One problem is that if you do exactly as it is there, you will sure have a problem if you are deploying the RC 2 of the MVC 3.

The yellow screen of death will give you the following error;

Could not load file or assembly 'System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

The error will be thrown by the system because it needs System.Web.WebPages.Deployment.dll as well. The solution of this little problem is simple;

Navigate to C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies (this could be C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies on Windows 7) inside the windows explorer and you will see some files inside the folder;

asp.net-mvc-3-rc-2-bin-deployment-shared-hosting-environment-full.PNG

You need those 6 dll files. In addition to that you will also need System.Web.Mvc.dll (version 3.0.11209.0). You will be able to find that dll file by navigating to C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 3\Assemblies (that should be C:\Program Files (86x)\Microsoft ASP.NET\ASP.NET MVC 3\Assemblies in Windows 7 [I'm not sure though])

asp.net-mvc-3-rc-2-bin-deployment-shared-hosting-environment-mvc-folder.PNG

Finally you should all have the following dlls in hand;

  • Microsoft.Web.Infrastructure
  • System.Web.Razor
  • System.Web.WebPages
  • System.Web.WebPages.Razor
  • System.Web.Helpers
  • System.Web.WebPages.Deployment (If you are deploying MVC RC 2, this assembly is necessary to deploy)
  • System.Web.Mvc

I made a copy of those dlls and put them together inside a folder so that I could reach them easily whenever I need them;

essential-MVC-3-0-RC-2-with-razor-dlls.PNG

We have all the necessary files in our hands and so what now !

There are some conventions here that you could choose. The way I follow is that;

  • I used built in Visual Studio Publish tool to publish my application to the production side.
  • After publishing was complated, I simply copied those 7 dll files into the bin folder inside the root directory of my application.

visual-studio-2010-publish-tool-goodies.png
Visual Studio 2010 Publish Tool

That was it ! [Of cource I didn't put the System.Web.WebPages.Dployment.dll into the production side and I got the error firstly :)]

Finally, my bin folder has the necessary assembly files to run the application;

magic-bin-folder-of-asp-net-mvc-3-rc-2-application.png

Tags