Sunday, November 25, 2012

Host site on Windows Azure virtual machine

There are several actions which you need to do in order to host your public site on the Windows Azure virtual machine. First of all you need to create your VM instance in Azure panel. You may find many tutorials how to do that, so I won’t repeat it here.

Once you will do that, add Web server role in the Server manager:

image

If your site is running on ASP.Net 3.5 you have to select it as well as shown on the picture above. Then create site in IIS like you always do and assign host header bindings for you domain name.

Then go to Azure management panel, click on your virtual machine and select Endpoints tab above:

image

Here you need to add endpoint for http traffic. In order to do that click Add endpoint button below:

image

When you will create it use the following values: Protocol = TCP, Public port = 80, Private port = 80. At the end you should see the following endpoints in your panel:

image

After that you need to configure DNS A-record in the DNS editor of your hosting provider. For this you need to know public IP address by which your site will be available. It can be found in Azure panel. Click on your virtual machine and in the Dashboard tab you will find Quick glance panel. On this panel you will see Public virtual IP address:

image

This is exactly what you need to use for the A-record. According to information from MS (e.g. here: Overview of Managing Deployments in Windows Azure) virtual IP won’t be changed during service lifetime:

Throughout the lifetime of a deployment, the VIP assigned will not change, regardless of the operations on the deployment, including updates, reboots, and reimaging the OS. The VIP for a given deployment will persist until that deployment is deleted. When a customer swaps the VIP between a stage and production deployment in a single hosted service, both deployment VIPs are persisted. A VIP is associated with the deployment and not the hosted service. When a deployment is deleted, the VIP associated with that deployment will return to the pool and be re-assigned accordingly, even if the hosted service is not deleted. Windows Azure currently does not support a customer reserving a VIP outside of the lifetime of a deployment.

After these steps will be done, you need to wait until DNS servers will be updated with new IP. After that you will have your site running on the Windows Azure.

Fix “HTTP Error 500.19 - Internal Server Error” when install ASP.Net MVC 3 site on IIS 8

Some time ago I moved MVC 3 site to the Windows Server 8 with IIS 8. Right after installation I got the following error:

HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.

Site worked properly on Windows Server 2008 R2 with IIS 7.5, so web.config was correct. The problem was in missing URL rewrite module for IIS. In the site I used several rewrite rules which are stored in web.config as you probably know. As URL rewrite module was not installed on the server, whole section with rewrite rules was not recognized and IIS shown above error. After installation of URL rewrite module, site became working.

This is not ASP.Net MVC specific problem. It may occur for general ASP.Net sites as well. So hope that this tip will help you if you will get the same problem.

Problem with context site in Sharepoint when call web service from javascript

If you need to call web service (here I will talk about old asmx web services) from javascript in ASP.Net or Sharepoint you may use auto-generated js proxy which is added to html output when you add ServiceReference to the ScriptManager instance for the current page:

   1: var scriptManager = ScriptManager.GetCurrent(this.Page);
   2: if (scriptManager == null)
   3: {
   4:     scriptManager = new ScriptManager();
   5:     this.Controls.Add(scriptManager);
   6: }
   7:  
   8: var referenceProxy = new ServiceReference();
   9: referenceProxy.Path = "/_layouts/test/test.asmx";
  10: referenceProxy.InlineScript = true;
  11:  
  12: scriptManager.Services.Add(referenceProxy);

Your web service’s class should be marked with [ScriptService] attribute, and all web methods which you want to use from javascript should be marked with [ScriptMethod] attribute:

   1: namespace MyNamespace
   2: {
   3:     [ScriptService]
   4:     [WebService(Namespace = "http://example.com/", Name = "Test")]
   5:     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
   6:     [ToolboxItem(false)]
   7:     public class Test : WebService
   8:     {
   9:         [ScriptMethod]
  10:         [WebMethod]
  11:         public string Foo(string str)
  12:         {
  13:             // ...
  14:         }
  15:     }
  16: }

After that you can call web service from javascript like this:

   1: MyNamespace.Test.Foo("Hello, world!");

However in Sharepoint you may encounter with the problem when use this method. Check the line 9 in the code above which adds service reference to script manager.

   1: referenceProxy.Path = "/_layouts/test/test.asmx";

Path contains the url to the service. As you can see it is located in layouts folder, i.e. it can be called in context of any Sharepoint site. Also we specified that generated proxy should be added as inline script to the output html (referenceProxy.InlineScript = true). In this case we need to use relative url in the ServiceReference.Path property as it is said in the documentation:

If the InlineScript property is set to true, then you must use a relative path that points to the same Web application as the page that contains the ServiceReference instance.

In our example path is relative, so it should be Ok. However if this code runs not on the root site, but on some sub site (e.g. http://example.com/subsite) we will have problem: relative path which we specified will be combined with root url, i.e. web service will be executed in context of root site, but not in context of the sub site. I.e. full url will be the following: http://example.com/_layouts/test/test.asmx. It may cause different problems, e.g. if locale of subsite differs from locale of the root site your users may see incorrectly localized content.

In order to fix it first of all we need to comment the line which sets InlineScript to true. It will allow us to use absolute url in the Path property:

   1: string referenceProxyUrl = SPUrlUtility.CombineUrl(SPContext.Current.Web.Url,
   2:     "/_layouts/test/test.asmx");
   3:  
   4: var referenceProxy = new ServiceReference();
   5: referenceProxy.Path = referenceProxyUrl;
   6: //referenceProxy.InlineScript = true;
   7:  
   8: scriptManager.Services.Add(referenceProxy);

These changes will have the following effect. Proxy will be added as external js file via <script> tag. Src attribute will contain absolute url:

   1: <script src="http://example.com/subsite/_layouts/test/test.asmx/jsdebug" type="text/javascript"></script>

(it added “/jsdebug” to the absolute url to the asmx). As you can see js proxy is loaded from context of the correct sub site now. So problem is solved? Unfortunately no. When you will check SPContext.Current.Web.Url property in the debugger of the web method, you will see that code still runs in context of the root site (it will contain http://example.com url, instead of http://example.com/subsite). And this is regardless of the site in which content js proxy was loaded.

In order to fix it we need to perform one extra step. Open the url which is specified in the src script. You will see the code of the proxy. It contain line which we are interesting in:

   1: MyNamespace.Test.set_path("/_layouts/test/test.asmx");

set_path is internal method generated on the client side only, i.e. there is no such method in our web service. As you can see it still contains relative url. This is exactly what we need. Before to use web service proxy in the javascript, we need to override relative url by absolute. We can get absolute url on server side as shown above using standard SPUrlUtility.CombineUrl() method and then pass it to javascript. After that call set_path with passed value:

   1: MyNamespace.Test.set_path(absoluteUrlFromServerSide);
   2: MyNamespace.Test.Foo("Hello, world!");

And it fixes the problem finally. Now the code of asmx web service will be executed in the context of the sub site. Hope that it will help you. E.g. you will encounter with this problem if will use framework for loading web parts asynchronously which I wrote above in the following post: Create asynchronous web parts for Sharepoint.

PS. However the described solution doesn’t fix problem with different locales which I used as example :) Some time ago I wrote how Sharepoint sets locale of the current thread using language of requested SPWeb: see this post. But because of some reason it didn’t happen in this case. So I fixed problem with locale manually:

   1: namespace MyNamespace
   2: {
   3:     [ScriptService]
   4:     [WebService(Namespace = "http://example.com/", Name = "Test")]
   5:     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
   6:     [ToolboxItem(false)]
   7:     public class Test : WebService
   8:     {
   9:         [ScriptMethod]
  10:         [WebMethod]
  11:         public string Foo(string str)
  12:         {
  13:             this.ensureCorrectLocale();
  14:             // ...
  15:         }
  16:  
  17:         private void ensureCorrectLocale()
  18:         {
  19:             if (Thread.CurrentThread.CurrentUICulture.LCID !=
  20: SPContext.Current.Web.UICulture.LCID)
  21:             {
  22:                 Thread.CurrentThread.CurrentUICulture =
  23: SPContext.Current.Web.UICulture;
  24:             }
  25:             if (Thread.CurrentThread.CurrentCulture.LCID !=
  26: SPContext.Current.Web.Locale.LCID)
  27:             {
  28:                 Thread.CurrentThread.CurrentCulture =
  29: SPContext.Current.Web.Locale;
  30:             }
  31:         }
  32:     }
  33: }

After that current thread’s locale became correct.

Sunday, November 18, 2012

Camlex.Client 1.1 is released

In this weekend we (I and Stef Heyenrath who joined the project some time ago) released Camlex for Client object model v.1.1. In this release support of RowLimit was added. In Client OM this tag is similar SPQuery.RowLimit property of basic Sharepoint object model, i.e. it allows to limit number of rows returned from the query. In CamlQuery class which is used in the client version, there is no separate property for row limit. Instead RowLimit tag is added with query to the ViewXml property. So it was quite natural to extend IQuery interface and add new method Take(int rowLimit) in it. So it will act as standard Take() method in Linq. Here is example:

   1: var camlQuery = Camlex.Query()
   2:     .Where(x => (string)x["Title"] == "test")
   3:     .Take(5)
   4:     .ToCamlQuery();

will produce the following CAML:

   1: <View>
   2:     <Query>
   3:         <Where>
   4:             <Eq>
   5:                 <FieldRef Name=\"Title\" />
   6:                 <Value Type=\"Text\">test</Value>
   7:             </Eq>
   8:         </Where>
   9:     </Query>
  10:     <RowLimit>5</RowLimit>
  11: </View>

The idea of adding Take() method came from Stef, so all credits go to him. I helped with technical implementation only. New version is already on codeplex and in Nuget gallery.

Saturday, November 10, 2012

Http module BeginRequest is not invoked when use URL rewrite IIS module

URL rewrite IIS module allows you to define rules, conditions and actions based on incoming URL pattern and variables (host, query string, etc). E.g. using it you may setup permanent redirects (http status code 301) from one URL to another. Often it is used for SEO, for example redirect from non-www URL to www. Redirect of course is not the only possible action which can be defined in URL rewrite module. Here is the full list of available actions:

  • Rewrite
  • None
  • Redirect
  • Custom response
  • Abort request

Rewrite action is frequently used for defining user-friendly URLs, which also gives advantages for SEO and for general usability. So URL rewrite module is quite powerful tool and in my opinion every web developer which works with Microsoft stack should get familiar with it in order to create advanced web applications.

However if you use this IIS extension in conjunction with custom http modules, you may encounter with the following problem: BeginRequest handlers, defined in the http modules, are not called when URL of incoming request matches conditions in the URL rewrite module’s rule, and it tries to make permanent redirect to another URL. However EndRequest is called every time, regardless of was request redirected by IIS module or not. If you use Unit of work pattern and IoC you may get exception because of that. E.g. consider the following example (StructureMap is used as IoC):

   1: public class UnitOfWorkModule : IHttpModule
   2: {
   3:     public void Init(HttpApplication context)
   4:     {
   5:         context.BeginRequest += context_BeginRequest;
   6:         context.EndRequest += context_EndRequest;
   7:     }
   8:  
   9:     public void Dispose()
  10:     {
  11:     }
  12:  
  13:     private void context_BeginRequest(object sender, EventArgs e)
  14:     {
  15:         var instance = ObjectFactory.GetInstance<IUnitOfWork>();
  16:         instance.Begin();
  17:     }
  18:  
  19:     private void context_EndRequest(object sender, EventArgs e)
  20:     {
  21:         var instance = ObjectFactory.GetInstance<IUnitOfWork>();
  22:         try
  23:         {
  24:             instance.Commit();
  25:         }
  26:         finally
  27:         {
  28:             instance.Dispose();
  29:         }
  30:     }
  31: }

In the BeginRequest we get instance of IUnitOfWork from IoC and call Begin() method. Under the hood it starts transaction. In the EndRequest we again get instance of IUnitOfWork and call Commit() method. Without URL rewrite it works because lifetime of unit of work is defined as per-request (in terms of StructureMap it has InstanceScope.Hybrid scope, in order to be able to write unit tests without http request). But if BeginMethod handler is not called, we get exception because transaction was not started and there is nothing to commit.

I tried to search for this problem and found several mentions on the stackoverflow without solution, so decided to analyze it. First of all we need to understand how URL rewrite module works. I strongly recommend the following article for understanding the basics: IIS URL Rewriting and ASP.NET Routing. The most important thing for us is the following:

The URL Rewrite module is a native code module that plugs into the request-processing pipeline at the Pre-begin Request or Begin Request stage.

I will also copy the image from original article here for convenience:

image

So now we know where URL rewrite module is called: “at the Pre-begin Request or Begin Request stage”. I wanted to clarify on what particular step it was called in my case (don’t fully get this “or”, i.e. when it is called in Pre-begin request and when in Begin request. If you know that please share it in comments). In order to do this I enabled Trace feature in IIS and used Failed request mapping tracing for details (see this post about this IIS feature: Using Failed Request Tracing to Trace Rewrite Rules) and found that it was executed on pre-request stage:

PRE_BEGIN_REQUEST_STARTModuleName="RewriteModule"
PRE_BEGIN_REQUEST_ENDModuleName="RewriteModule", NotificationStatus="NOTIFICATION_CONTINUE"

After that for testing I created 2 simple http modules in the Hello world ASP.Net web application with the following code:

   1: public class Module1 : IHttpModule
   2: {
   3:     public static object lockObj = new object();
   4:  
   5:     public void Init(HttpApplication context)
   6:     {
   7:         context.BeginRequest += context_BeginRequest;
   8:         context.EndRequest += context_EndRequest;
   9:     }
  10:  
  11:     void context_BeginRequest(object sender, EventArgs e)
  12:     {
  13:         lock (lockObj)
  14:         {
  15:             File.AppendAllText("c:\\temp\\modules.log",
  16:                 Thread.CurrentThread.ManagedThreadId +
  17:                 " Module1.BeginRequest" + Environment.NewLine);
  18:         }
  19:     }
  20:  
  21:     void context_EndRequest(object sender, EventArgs e)
  22:     {
  23:         lock (lockObj)
  24:         {
  25:             File.AppendAllText("c:\\temp\\modules.log",
  26:                 Thread.CurrentThread.ManagedThreadId +
  27:                 " Module1.EndRequest" + Environment.NewLine);
  28:         }
  29:     }
  30:  
  31:     public void Dispose()
  32:     {
  33:     }
  34: }

And second one:

   1: public class Module2 : IHttpModule
   2: {
   3:     public void Init(HttpApplication context)
   4:     {
   5:         context.BeginRequest += context_BeginRequest;
   6:         context.EndRequest += context_EndRequest;
   7:     }
   8:  
   9:     void context_BeginRequest(object sender, EventArgs e)
  10:     {
  11:         lock (Module1.lockObj)
  12:         {
  13:             File.AppendAllText("c:\\temp\\modules.log",
  14:                 Thread.CurrentThread.ManagedThreadId +
  15:                 " Module2.BeginRequest" + Environment.NewLine);
  16:         }
  17:     }
  18:  
  19:     void context_EndRequest(object sender, EventArgs e)
  20:     {
  21:         lock (Module1.lockObj)
  22:         {
  23:             File.AppendAllText("c:\\temp\\modules.log",
  24:                 Thread.CurrentThread.ManagedThreadId +
  25:                 " Module2.EndRequest" + Environment.NewLine);
  26:         }
  27:     }
  28:  
  29:     public void Dispose()
  30:     {
  31:     }
  32: }

I.e. both modules make the same: register handlers for BeginRequest and EndRequest and just log the execution to the text file (lock is used in order to synchronize access for the log file from several threads). Then registered them in web.config in the following order:

   1: <system.webServer>
   2:   <modules runAllManagedModulesForAllRequests="true">
   3:     <remove name="Module1"/>
   4:     <remove name="Module2"/>
   5:     <add name="Module1" type="MyNamespace.Module1"/>
   6:     <add name="Module2" type="MyNamespace.Module2"/>
   7:   </modules>
   8: </system.webServer>

Here how log looks like in this case:

Module1.BeginRequest
Module2.BeginRequest
Module1.EndRequest
Module2.EndRequest

(I removed thread id as it is not relevant here. Before of testing I removed all references to css and js files from the test web application, so there was always only one thread/http request). This is quite clear: at the first Module1 is executed, then Module2, because they are defined in this order in the web.config.

Now we need to simulate redirection from URL rewrite module. In our situation rewrite module will be executed before both modules’ BeginRequest (because it is executed on pre-BeginRequest stage as we saw above). So I changed the code of Module1 which is called first and added permanent redirect:

   1: void context_BeginRequest(object sender, EventArgs e)
   2: {
   3:     lock (lockObj)
   4:     {
   5:         File.AppendAllText("c:\\temp\\modules.log",
   6:             Thread.CurrentThread.ManagedThreadId +
   7:             " Module1.BeginRequest" + Environment.NewLine);
   8:     }
   9:     HttpContext.Current.Response.RedirectPermanent("http://google.com");
  10: }

(RedirectPermanent() method was added in .Net 4.0). Now I got the following log:

Module1.BeginRequest
Module1.EndRequest
Module2.EndRequest

As you can see BeginRequest in Module2 was not executed at all, but EndRequest was executed for all modules anyway. Module1 in this example plays role of URL rewrite module, while Module2 – custom http module. This example shows that when redirect is called BeginRequest handlers are skipped (Module1.BeginRequest is not taken into account because redirect was made from it), but EndRequest are executed always, even if response is redirected (probably it is executed in finally block so it works also for ThreadAbortException which occurs when request processing is interrupted).

As we saw in example above this is the normal ASP.Net behavior. So now we only have to fix the problem in our http module with unit of work. It is quite easy now when we understand the internals:

   1: public class UnitOfWorkModule : IHttpModule
   2: {
   3:     public void Init(HttpApplication context)
   4:     {
   5:         context.BeginRequest += context_BeginRequest;
   6:         context.EndRequest += context_EndRequest;
   7:     }
   8:  
   9:     public void Dispose()
  10:     {
  11:  
  12:     }
  13:  
  14:     private void context_BeginRequest(object sender, EventArgs e)
  15:     {
  16:         var instance = ObjectFactory.GetInstance<IUnitOfWork>();
  17:         instance.Begin();
  18:     }
  19:  
  20:     private void context_EndRequest(object sender, EventArgs e)
  21:     {
  22:         if (HttpContext.Current.Response.StatusCode == (int)HttpStatusCode.MovedPermanently)
  23:         {
  24:             return;
  25:         }
  26:  
  27:         var instance = ObjectFactory.GetInstance<IUnitOfWork>();
  28:         try
  29:         {
  30:             instance.Commit();
  31:         }
  32:         finally
  33:         {
  34:             instance.Dispose();
  35:         }
  36:     }
  37: }

In the EndRequest handler we added a check that current status code is not 301 (HttpStatusCode.MovedPermanently) because we know that BeginRequest was not called in this case and unit of work is not initialized. If it is, just return without trying to commit unit of work.

Hope that this post will help to those who will face with similar problem.