Galin Iliev's blog

Software Architecture & Development

IIS7 Admin Packs add analytics features

IIS7 is grew to a development platform and become the most wanted feature in the new Windows Server 2008. But this is not the end - IIS7 Admin Pack first CTP is here and provides a nice set of features that can help you to understand what is happening on the server...

here are new features in short:

  • Database Manager: Built-in SQL Server database management, including the ability to create, delete, and edit tables and indexes, create/edit SPROCs and execute custom queries.  Because it is integrated in the IIS administration tool it all works over HTTP/SSL - which means you can use the module to remotely manage your hosted applications (even with low-cost shared hosting accounts), without having to expose your database directly on the Internet.

  • Log Reports: Built-in report visualization with charting support for log files data.  Full range selection and custom chart creation is supported, as well as the ability to print or save reports.  Like the database manager you can use this module remotely over HTTP/SSL - which means it works in remote shared hosting scenarios.

  • Configuration Editor: This is a power module that provides complete control over editing all web.config settings within the admin tool.  You can configure it to track the changes you make using the UI and have it auto-generate configuration change scripts that you can then save and tweak to re-run later in an automated way.

  • Request Filtering UI: This admin module provides more control over the new request filtering feature in IIS7.  Check out Carlos' blog post here for details on how to use it.

  • .NET Authorization: This admin module provides a custom authorization rules editor which allows you to more easily manage the ASP.NET <authorization> configuration section.

  • FastCGI UI: This admin module provides more support for editing all the new <fastCGI> settings (for when you use FastCGI modules with IIS7 like PHP).

 

While DB manager can save you time jumping between applications Log Reports definitely rocks. It gives you an option to view activities on the server in very convenient form in following categories:

  • Web Server\Status code:  This report gives the comparison between number of hits and status code.
  • Web Server\Hits Per Url: This report gives the comparison between number of hits and the Url.
  • Web Server\Hits By Hour: This report gives the comparison between number of hits and the Hour.
  • Web Server\User Agent: This report gives the comparison between number of hits and the User Agent.
  • Web Server\File Extension: This report gives the comparison between number of hits and the file extension.
  • Web Server\User: This report gives the comparison between number of hits and the User.
  • Web Server\Time Taken: This report gives the comparison between Average time taken and the Url.
  • Web Server\Win32 Errors: This report gives the comparison between Hits and the Win32 Errors.
  • Web Server\Client Machine: This report gives the comparison between Hits and the Client Machine.
  • Web Server\Http Method: This report gives the comparison between Hits and the Http Method.

Just see these screenshots:

For more info visit these links:

Breaking changes in IIS7 (integrated pipeline) when hosting ASP.NET 2.0 sites

Mike Volodarsky posted a nice list of breaking changes when you run ASP.NET 2.0 web sites on IIS7 Integrated mode.

Here is the list (for workarounds take a look at Mike's blog post).

Migration errors
  1. ASP.NET applications require migration when specifying configuration in <httpModules> or <httpHandlers>.
  2. ASP.NET applications produce a warning when the application enables request impersonation by specifying <identity impersonate=”true”> in configuration.
  3. You receive a configuration error when your application configuration includes an encrypted <identity> section.
Authentication, Authorization, and Impersonation

  1. Applications cannot simultaneously use FormsAuthentication and WindowsAuthentication.
  2. Windows Authentication is performed in the kernel by default.  This may cause HTTP clients that send credentials on the initial request to fail.
  3. Passport authentication is not supported.
  4. HttpRequest.LogonUserIdentity throws an InvalidOperationException when accessed in a module before PostAuthenticateRequest.
  5. Client impersonation is not applied in a module in the BeginRequest and AuthenticateRequest stages.
  6. Defining an DefaultAuthentication_OnAuthenticate method in global.asax throws PlatformNotSupportedException.
  7. Applications that implement WindowsAuthentication_OnAuthenticate in global.asax will not be notified when the request is anonymous.
Request limits and URL processing
  1. Request URLs containing unencoded “+” characters in the path (not querystring) is rejected by default.
  2. Requests with querystrings larger then 2048 bytes will be rejected by default.
Changes in response header processing
  1. IIS always rejects new lines in response headers (even if ASP.NET enableHeaderChecking is set to false)When the response headers are cleared with HttpResponse.ClearHeaders, default ASP.NET headers are not generated.  This may result in the lack of Cache-Control: private header that prevents the caching of the response on the client.
  2. When the response is empty, the Content-Type header is not suppressed.
  3. When the response headers are cleared with HttpResponse.ClearHeaders, default ASP.NET headers are not generated.  This may result in the lack of Cache-Control: private header that prevents the caching of the response on the client.
Changes in application and module event processing
  1. It is not possible to access the request through the HttpContext.Current property in Application_Start in global.asax.
  2. The order in which module event handlers execute may be different then in Classic mode.
  3. ASP.NET modules in early request processing stages will see requests that previously may have been rejected by IIS prior to entering ASP.NET.  This includes modules running in BeginRequest seeing anonymous requests for resources that require authentication.
Other application changes
  1. DefaultHttpHandler is not supported.  Applications relying on sub-classes of DefaultHttpHandler will not be able to serve requests.
    It is possible to write to the response after an exception has occurred.
  2. It is not possible to use the ClearError API to prevent an exception from being written to the response if the exception has occurred in a prior pipeline stage.
  3. HttpResponse.AppendToLog does not automatically prepend the querystring to the URL.
Other changes
  1. ASP.NET threading settings are not used to control the request concurrency in Integrated mode.
  2. ASP.NET application queues are not used in Integrated mode.  Therefore, the “ASP.NET Applications\Requests in Application Queue” performance counter will always have a value of 0
  3. IIS 7.0 always restarts ASP.NET applications when changes are made to the application’s root web.config file.  Because of this, waitChangeNotification and maxWaitChangeNotification attributes have no effect.

WebResource.axd reported Error 404, images - 403.1 - Forbidden

Recently I had interesting experience with web applications that deserves a blog post. We decided to run broken link checker on huge ASP.NET site on staging server (Win 2003 & IIS6). This could also act as a small load test.

So far so good but I've noticed two main reports:

  • WebResource.axd with one specific parameter reported Error 404.0 - File not found
  • some requests to images (.gif) reported Error 403.1 - Forbidden

These errors are logged on IIS log. 

This is quite strange because when I try to run them in the browser manually everything is fine. The hardware seems not very loaded.

 

While investigating it further (and getting a clue from IIS.NET Forums) I got that IIS is actually trying to executed .gif files (See IIS Status codes). Probably same happens to WebResource.axd...

Then I went on link checker side and noted that it makes "HEAD" request (point 9.4) in order to reduce traffic.

 

I wrote this little tool to check my assumption.

1: using System;
2: using System.Net;
3: using System.Threading;
4:  
5: namespace UrlChecker {
6:     class Program {
7:         static string URL_TO_CHECK2 = "http://localhost/WebResource.axd?d=long-param-here";
8:         static string URL_TO_CHECK = "http://localhost/Photo/1116.gif";
9:         static int LOOPS_NUM = 10;
10:         static int THREADS_NUM = 10;
11:         static int REQUEST_TIMEOUT = 10000;
12:         static string REQUEST_METHOD = "HEAD"; // or "GET"
13:  
14:  
15:         static ManualResetEvent sync = null;
16:         static void Main(string[] args) {
17:             sync = new ManualResetEvent(false);
18:             Thread[] threads = new Thread[THREADS_NUM];
19:             for (int i = 0; i < THREADS_NUM; i++) {
20:                 threads[i] = new Thread(new ParameterizedThreadStart(CheckLink));
21:                 threads[i].Start(i);
22:             }
23:             sync.Set();
24:             Console.Write("Press 'Enter' to exit!");
25:             Console.ReadLine();
26:         }
27:  
28:         static void CheckLink(object ThreadId) {
29:             sync.WaitOne();
30:  
31:             for (int i = 0; i < LOOPS_NUM; i++) {
32:                 string statusCode;
33:                 try {
34:                     HttpWebRequest rq = (HttpWebRequest)WebRequest.Create(URL_TO_CHECK);
35:                     rq.Method = REQUEST_METHOD;
36:                     rq.Timeout = REQUEST_TIMEOUT;
37:                     HttpWebResponse resp = (HttpWebResponse)rq.GetResponse();
38:                     statusCode = resp.StatusCode.ToString();
39:                 } catch (WebException ex) {
40:                     statusCode = string.Format("Exception: {0}", ex.Message);
41:                 }
42:                 Console.WriteLine("{0} - '{1}'", ThreadId, statusCode);
43:             }
44:             Console.WriteLine("Thread {0} finished.", ThreadId);
45:         }
46:     }
47: }

And this helped me to confirm it..   Note on line 12 is set HEAD request and all requests fails with the messages shown above (404 and 403.1 accordingly). When GET request is used everything is OK. Luckily the link checker supported GET request on failed although I had some difficulties setting it.

Building a Volta Control : A Flickr Widget

Tanzim Saqib wrote a nice article about Microsoft Volta in which he gives step by step instructions on how to write a Flickr control that you can reuse  in your pages.

Microsoft Live Labs Volta is Microsoft's emerging toolset that enables developers to build multi-tier web applications by applying familiar .NET techniques and patterns. The intended use of this toolset is for Developers to build web application as .NET client application, and then specify the portions of the codes that will run on the client and server side. The compiler then creates cross browser JavaScript, Web Services, communication, serialization, security etc. to tie the tiers together. This article is based on the first CTP of Volta considering its current limitations. We will see how we can create a Volta control that the compiler can convert into an AJAX Widget without requiring us writing a single line of JavaScript code. We will write code in our very familiar C# language.

Interesting reading! Full Article.

Text/Value pair in ASP.NET AJAX Autocomplete Extender

The scenario

I guess you are familiar with the case when user have a screen in which ClientId is needed in text box but it is quite unusual to let the users and clients to remember all those numbers. To facilitate users and clients you put DropDownList control (in case you are developing ASP.NET app) filled with ListItem elements and every item has it's Text and Value properties. Sounds common, isn't it?

The challenge

In today's world of Web 2.0  and DHTML mashups you may have same scenario like one above but needed to be implemented in similar behavior like ASP.NET AJAX Autocomplete extender does.

In other words - you have a textbox and a list with items but when user select an item instead if item's text some number or ID is put in the extended textbox.

The Solution

ASP.NET AJAX Autocomplete extendeer can be adjusted to behave that way.

First we should provide Text and Value pair... How to do that as there is strict definition of expected XML Web Service method?

ServiceMethod - The web service method to be called. The signature of this method must match the following:

[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public string[] GetCompletionList(string prefixText, int count) 

Note that you can replace "GetCompletionList" with a name of your choice, but the return type and parameter name and type must exactly match, including case.

There is still way. We just need to pass pair in serialized way. If you take a look at Autocomplete test page source you will see that method

   1: [System.Web.Services.WebMethod]
   2: [System.Web.Script.Services.ScriptMethod]
   3: public static string[] GetCompletionListWithContextAndValues(string prefixText, int count, string contextKey)
   4: {
   5:     System.Collections.Generic.List<string> items = new System.Collections.Generic.List<string>(GetCompletionListWithContext(prefixText, count, contextKey));
   6:        for (int i = 0; i < items.Count; i++){
   7:           items[i] = AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(items[i], i.ToString());
   8:        }
   9:            return items.ToArray();
  10: }

So if we use helper method below we can get serialized pair

AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(text, val);

But that's not all. Unfortunately we have to modify the AutoCompleteBehavior.js in order to get value instead text property. More precisely we have to add one more line in it... in function _setText - it should start like this:

_setText: function(item) {
/// <summary>
/// Method to set the selected autocomplete option on the textbox
/// </summary>
/// <param name="item" type="Sys.UI.DomElement" DomElement="true" mayBeNull="true">
/// Item to select
/// </param>
/// <returns />

var text = (item && item.firstChild) ? item.firstChild.nodeValue : null;
text = (item && item._value) ? item._value : text;

Note: The very last line is added by us. This is enough to test. Rebuild the AjaxControlToolkit source, use produced assembly instead of downloaded one and enjoy.

Hope this helps!

ADO.NET Data Services CTP is released!

ADO.NET Data Services aka Project "Astoria" December CTP is released. Mike Flasko (PM @ Astora team) posted some key points:

The following features are in this CTP:

  • Support to create ADO.NET Data Services backed by:
    • A relational database by leveraging the Entity Framework
    • Any data source (file, web service, custom store, application logic layer, etc)
  • Serialization Formats:
    • Industry standard AtomPub serialization
    • JSON serialization
  • Business Logic & Validation
    • Insert custom business/validation logic into the Request/response processing pipeline
    • simple infrastructure to build custom access policy 
  • Access Control
    • Easily control the resources viewable from a data service
  • Simple HTTP interface
    • Any platform with an HTTP stack can easily consume a data service
    • Designed to leverage HTTP semantics and infrastructure already deployed at large
  • Client libraries:
    • .NET Framework
    • ASP.NET AJAX
    • Silverlight (coming soon)
  • For more information see ADO.NET Data Services official site.

    Meet Microsoft Live Labs Volta

    Here is another codename project from Microsoft that aims at Web UI experience - meet Microsoft Live Labs Volta:

    The Volta technology preview is a developer toolset that enables you to build multi-tier web applications by applying familiar techniques and patterns. First, design and build your application as a .NET client application, then assign the portions of the application to run on the server and the client tiers late in the development process. The compiler creates cross-browser JavaScript for the client tier, web services for the server tier, and communication, serialization, synchronization, security, and other boilerplate code to tie the tiers together.

    Developers can target either web browsers or the CLR as clients and Volta handles the complexities of tier-splitting for you.  Volta comprises tools such as end-to-end profiling to make architectural refactoring and optimization simple and quick. In effect, Volta offers a best-effort experience in multiple environments without any changes to the application.

    Programming model:

    In essence Volta is a recompiler. Volta works on MSIL rather than on a textual source language. Volta rewrites MSIL into any number of target languages, including, today JavaScript and MSIL itself. Rewriting, as a general technology, lets us delay permanent decisions about architecture, execution platform and browser until after our code is basically working. Furthermore, it frees us from having to express all these irreversible decisions in your source code. The result is a programming model that enables us to easily reshape a working application, and finally realizes the promise of one application running anywhere.

    Volta effects recompilation through 3 general capabilities: refactoring, retargeting, and remodulating. Refactoring converts single-tier code into distributed, concurrent code as directed by user-supplied annotations. Retargeting converts MSIL code into code for other virtual machines. Remodulating tailors a single piece of code for multiple browsers. The next 3 sections explain in more detail.

    See detailed architectural and fundamental description here.

    Links:

    &quot;Internet Explorer cannot open the Internet site&quot;, &quot;Operation aborted&quot;

    If you're web developer and write JavaScript/AJAX-driven web sites you probably have seen such message (in IE of course)... If you haven't seen it yet just save this as html file and open it in IE:

    <html>
    <head>
        <script type="text/javascript">
        function appendToBody() {
            var span = document.createElement('span');
            document.body.appendChild(span);        
        }
        </script>
    </head>
    <body>
        <form>
            <script type="text/javascript">
                appendToBody();
            </script>
        </form>
    </body>
    </html>
    
    

    The code is taken from blog post Dealing with IE "Operation Aborted". Or, how to Crash IE.

    So as a rules of thumb for DOM manipulations inside browsers:

    • The problem is you can't append to the BODY element from script that isn't a direct child to the BODY element.
    • Do not place script inside <table> tags.
    • Do not try to manipulate with element in Javascript which are not loaded yet! (e.g div placed on the very bottom at the page and not loaded by browser at the time when JS function is executed).

    These rules can save you many hours of guessing what's wrong...