2670

Optimizing reading for the CustomTextMessageEncoder

Continuing the improvement of the CustomTextMessageEncoder (see this and this), this time I'll use the XmlDictionaryWriter instead of the XmlTextWriter whenever the character encoding is utf-8, utf-16 or Unicode.

To achieve this, all that's needed is to look into the character set part of the content type and act accordingly.

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)

{

    byte[] messageContents = new byte[buffer.Count];

    Array.Copy(buffer.Array, buffer.Offset, messageContents, 0, messageContents.Length);

    bufferManager.ReturnBuffer(buffer.Array);

 

    MemoryStream stream = new MemoryStream(messageContents);

    //return ReadMessage(stream, int.MaxValue);

    return ReadMessage(stream, int.MaxValue, contentType);

}

 

public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)

{

    string charset = null;

    if (!string.IsNullOrEmpty(contentType))

    {

        System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(contentType);

        charset = ct.CharSet;

    }

    if ((!string.IsNullOrEmpty(charset)) && (charset.Equals(ValidatingUTF8.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingUTF16.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingBEUTF16.WebName, StringComparison.InvariantCultureIgnoreCase)))

    {

        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

    else

    {

        XmlReader reader = XmlReader.Create(stream);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

}

System.Web.HttpUtility.UrlEncode and character encodings

A kind reader of one of my blogs posed me a question about a problem with HttpUtility.UrlEncode. His problem was that he needed to URL encode São Marcos and instead of getting S%E3o%20Marcos he was getting S%C3%A3o%20Marcos.

The problem here is the character encoding. The default encoding used by HttpUtility.UrlEncode (and HttpUtility.UrlDecode) is utf-8 and the requested site is expecting iso-8859-1.

To solve this problem, all that is needed calling HttpUtility.UrlEncode with the required character encoding:

System.Web.HttpUtility.UrlEncode("São Marcos", System.Text.Encoding.GetEncoding("iso-8859-1"))

BUG: Using Custom Identities in ASP.NET fails when using the ASP.NET Developement Server

This bug has been around for a while and affects web site development when using custom identities (classes that implement System.Security.Principal.IIdentity) and the ASP.NET Development Server.

To reproduce this bug, you have to implement the IIdentity interface, something like this:

[Serializable]

public class MyIdentity : System.Security.Principal.IIdentity

{

    private string name;

    private string authenticationType;

    private bool isAuthenticated;

 

    public MyIdentity(string name, string authenticationType, bool isAuthenticated)

    {

        this.name = name;

        this.authenticationType = authenticationType;

        this.isAuthenticated = isAuthenticated;

    }

 

    #region IIdentity Members

 

    public string AuthenticationType

    {

        get { return this.authenticationType; }

    }

 

    public bool IsAuthenticated

    {

        get { return this.isAuthenticated; }

    }

 

    public string Name

    {

        get { return this.name; }

    }

 

    #endregion

}

And use it somewhere like this:

        protected void Application_PostAuthenticateRequest(object sender, EventArgs e)

        {

            Thread.CurrentPrincipal = HttpContext.Current.User =

                new GenericPrincipal(new MyIdentity(HttpContext.Current.User.Identity.Name, "test", true), new string[0]);

        }

It doesn't happen all the time but it happens. Eventually, you'll get this in your event log:

Event Type:    Warning

Event Source:    ASP.NET 2.0.50727.0

Event Category:    Web Event

Event ID:    1309

Date:        29-04-2007

Time:        18:34:54

User:        N/A

Computer:    ORCASBETA1VSTS

 

Description:

   Event code: 3005

 

Event message: An unhandled exception has occurred.

   Event time: 29-04-2007 18:34:54

   Event time (UTC): 30-04-2007 1:34:54

   Event ID: 8afb62b7b7604da087509636bb48fbad

   Event sequence: 16

   Event occurrence: 1

   Event detail code: 0

 

Application information:

   Application domain: 53ad158c-10-128223704725800576

   Trust level: Full

   pplication Virtual Path: /WebSite3

   Application Path: C:\Documents and Settings\Administrator\My Documents\Visual Studio Codename Orcas\WebSites\WebSite3\

   Machine name: ORCASBETA1VSTS

 

 

Process information:

   Process ID: 3880

   Process name: WebDev.WebServer.EXE

   Account name: ORCASBETA1VSTS\Administrator

 

Exception information:

   Excpetion type: SerializationException

   Exception message: Type is not resolved for member 'MyIdentity,App_Code.4broaqvc, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

 

 

Request information:

   Request URL: http://localhost:1137/WebSite3/default.aspx

   Request path: /WebSite3/default.aspx

   User host address: 127.0.0.1

   User: user

   Is authenticated: True

   Authentication Type: test

   Thread account name: ORCASBETA1VSTS\Administrator

 

Thread information:

   Thread ID: 4

   Thread account name: ORCASBETA1VSTS\Administrator

   Is impersonating: False

 

Stack trace:

   at Microsoft.VisualStudio.WebHost.Connection.ReadRequestBytes(Int32 maxBytes)

   at Microsoft.VisualStudio.WebHost.Request.ReadEntityBody(Byte[] buffer, Int32 size)

   at System.Web.HttpRequest.GetEntireRawContent()

   at System.Web.HttpRequest.FillInFormCollection()

   at System.Web.HttpRequest.get_Form()

   at System.Web.HttpRequest.get_HasForm()

   at System.Web.UI.Page.GetCollectionBasedOnMethod(Boolean dontReturnNull)

   at System.Web.UI.Page.DeterminePostBackMode()

   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

I've opened a bug on this. If you are having the same problem, vote on it.

With the bug, I've submitted this sample.

How to use Forms Authentication’s User Definitions with the Login Control

In ASP.NET 1.1 we already had definitions of name and password credentials within the configuration file. We just didn't have a Login control.


Now we have both but the Login control is set by default to use the default membership provider.


How can we use both of them together?


Well, there are two ways, depending on your will or needs:



  1. Using the Login control with FormsAuthentication

    This is the easiest way, you just need to handle the Authenticate event of the Login control.

    Login.aspx

    <!-- ... -->


    <asp:Login ID="Login1" runat="server" DisplayRememberMe="False" OnAuthenticate="Login1_Authenticate">


    </asp:Login>


    <!-- ... -->


     

    Login.aspx.cs

    // ...

    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)

    {


        e.Authenticated = FormsAuthentication.Authenticate(Login1.UserName, Login1.Password);


    }


    // ...


     


  2. Using FormsAuthentication as the membership provider

    This one is a bit trickier.


    First you don't need to handle the Authenticate event.


     

    Login.aspx

    <!-- ... -->


    <asp:Login ID="Login1" runat="server" DisplayRememberMe="False">


    </asp:Login>


    <!-- ... -->


    Then you need to implement a membership provider that uses FormsAuthentication.


     


     

    FormsAuthenticationMembershipProvider.cs

    public class FormsAuthenticationMembershipProvider : System.Web.Security.MembershipProvider


    {


        private string applicationName;


     


        public override string ApplicationName


        {


            get { return this.applicationName; }


            set { this.applicationName = value; }


        }


     


        public override bool EnablePasswordReset


        {


            get { return false; }


        }


     


        public override bool EnablePasswordRetrieval


        {


            get { return false; }


        }


     


        public override bool ValidateUser(string username, string password)


        {


            return FormsAuthentication.Authenticate(username, password);


        }


     


        // Not Implemented MembershipProvider Members


    }


    And register it in the configuration file.

What’s wrong with ASP.NET provider model? – The XmlSiteMapProvider

Besides the problem with spaces in query strings (the same thing happens for the entire URL), you cannot subclass the XmlSiteMapProvider and use it if your site has site map definitions in files placed in each folder of the site instead of the a single one in the root of the site.

Suppose you want to build a site map provider that works like the XmlSiteMapProvider but the security trimming is based solely on the user's roles and not taking into account URL or File authorization.

The way security trimming is supposed to work with the XmlSiteMapProvider doesn't allow you to do this because it will show in the site map all resources accessible to the user independently of the roles declared in the site map definition.

(Before someone starts to complain about security issues, let me remember you that I can have my own authorization module that won't allow access to resources that aren't in the site map)

Such a site map provider can easily be developed. It can be something like this:

public class MyXmlSiteMapProvider : System.Web.XmlSiteMapProvider

{

    public override bool IsAccessibleToUser(System.Web.HttpContext context, System.Web.SiteMapNode node)

    {

        if (node == null)

        {

            throw new System.ArgumentNullException("node");

        }

        if (context == null)

        {

            throw new System.ArgumentNullException("context");

        }

        if (!this.SecurityTrimmingEnabled)

        {

            return true;

        }

 

        System.Collections.IList roles = node.Roles;

        System.Security.Principal.IPrincipal user = context.User;

        if (user == null || roles == null || roles.Count == 0)

        {

            return true;

        }

 

        foreach (string role in roles)

        {

            if ((role == "*") || user.IsInRole(role))

            {

                return true;

            }

        }

        return false;

    }

}

Now, suppose your site has some sub-folders (Customers, Suppliers, Admin) and you want to define the site map structure for each sub-folder in each sub-folder. Something like this:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="~/Default.aspx" title="Home" description="Home Page" roles="*">

    <siteMapNode siteMapFile="~/Customers/Web.sitemap" />

    <siteMapNode siteMapFile="~/Suppliers/Web.sitemap" />

    <siteMapNode siteMapFile="~/Admin/Web.sitemap" />

  </siteMapNode>

</siteMap>

Well, if you are sub-classing the XmlSiteMapProvider, you can't. You'll have to fully develop your own XML site map provider. You don't have to type it yourself [^], but you'll have to maintain it.

It could be avoided if the XmlSiteMapProvider had been built with extensibility in mind (like the DataTable, for example) by adding a BuildNewXmlSiteMapProvider virtual method responsible for creating new XmlSiteMapProvider instances. This way, your provider could create its own new instances.

If you would like to see this implemented in ASP.NET, vote on my suggestion.

You can workaround this by adding a site map provider for each sub-folder:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="~/Default.aspx" title="Home" description="Home Page" roles="*">

    <siteMapNode provider="CustomersSiteMap" />

    <siteMapNode provider="SuppliersSiteMap" />

    <siteMapNode provider="AdminSiteMap" />

  </siteMapNode>

</siteMap>

Adding Presenters to MasterPages in the Web Client Software Factory

Master pages, in the Web Client Software Factory, act as equivalents to the Shell in the Smart Client Software Factory but, unlike their smart client counterpart, they don't benefit from dependency injection.

I've just cooked up a quick way to add dependency injection to master pages in the Web Client Software Factory and, thus, add a Presenter (with the associated Controller).

This can be done just by adding a few lines of code to the Microsoft.Practices.CompositeWeb.WebClientApplication class:

protected void InnerPreRequestHandlerExecute(IHttpContext context)

{

    if (HttpRequestHelper.IsHandledByPageHandlerFactory(context.Request.Url.ToString()))

    {

        ICompositionContainer moduleContainer = GetModuleContainer(context);

 

        // We need to use a non-singleton based builder object here, otherwise

        // every object created from the aspx page with the BuildNew attribute

        // will be created with hard references on the lifetime container

        // and will never be released, causing a memory leak.

        CompositionContainer.BuildItem(PageBuilder, moduleContainer.Locator, context.Handler);

 

        Page page = context.Handler as Page;

 

        if (page != null)

        {

            page.PreInit += new EventHandler(OnPagePreInit);

 

            PrePageExecute(page);

        }

    }

}

 

private void OnPagePreInit(object sender, EventArgs e)

{

    Page page = sender as Page;

 

    page.PreInit -= new EventHandler(OnPagePreInit);

 

    if (page.Master != null)

    {

        ICompositionContainer moduleContainer = GetModuleContainer(new CompositeWeb.Web.HttpContext(HttpContext.Current));

 

        CompositionContainer.BuildItem(PageBuilder, moduleContainer.Locator, page.Master);

    }

}

With this little change, master pages can be built the same way pages are:

public partial class MasterPage : System.Web.UI.MasterPage, IMasterView

{

    private MasterPresenter _presenter;

 

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!this.IsPostBack)

        {

            this._presenter.OnViewInitialized();

        }

        this._presenter.OnViewLoaded();

    }

 

    [Microsoft.Practices.ObjectBuilder.CreateNew]

    public MasterPresenter Presenter

    {

        get { return this._presenter; }

        set

        {

            this._presenter = value;

            this._presenter.View = this;

        }

    }

 

    #region IMasterView Members

 

        // ...

 

    #endregion

}

If you want to see this in the Web Client Software Factory, vote on the corresponding work item.

Update

Apparently I had missed a previous post from Simon Ince on something like this.

There's a discussion on this on the community site.

David Hayden also posted something.

MSDN Webcast: How to Use the Web Client Software Factory (Level 300)

Blaine Wastell and Michael Puleio did an MSDN webcast about Web Client Software Factory.

If you are interested and missed it, you can view an online replay or download it from here:

MSDN Webcast: How to Use the Web Client Software Factory (Level 300)

Developer Tools for Internet Explorer

For the past months I've been developing ASP.NET infrastructure (authentication, authorization, profile, membership and resource providers). My job is not building web pages. My job is make the lives of web page developers a lot easier (well, they might not agree with me on that).


Nevertheless, when developing authentication providers I need to know when and where to redirect requests and to control how many postbacks are occurring.


To help developers on their tasks there are a few tools for Internet Explorer that can be used.


Internet Explorer Developer Toolbar Beta 3


This a free tool from Microsoft that helps you mostly with HTML issues.


The announced features are:


  • Explore and modify the document object model (DOM) of a Web page.
  • Locate and select specific elements on a Web page through a variety of techniques.
  • Selectively disable Internet Explorer settings.
  • View HTML object class names, ID's, and details such as link paths, tab index values, and access keys.
  • Outline tables, table cells, images, or selected tags.
  • Validate HTML, CSS, WAI, and RSS Web feed links.
  • Display image dimensions, file sizes, path information, and alternate (ALT) text.
  • Immediately resize the browser window to a new resolution.
  • Selectively clear the browser cache and saved cookies. Choose from all objects or those associated with a given domain.
  • Choose direct links to W3C specification references, the Internet Explorer team weblog (blog), and other resources.
  • Display a fully featured design ruler to help accurately align and measure objects on your pages.
  • Find the style rules used to set specific style values on an element.
  • View the formatted and syntax colored source of HTML and CSS.
  • Style Tracer: Right mouse click on a style value for an element and select Style Tracer to find the style rule that is effecting that value.
  • CSS Selector Matches: View a report of all style rules set and how many times they are used on the current page.
  • View Source: View the formatted and syntax colored source of the original page, currently rendered page, element or element with the styles that are effecting it.

    You can find more information on the Internet Explorer Developer Toolbar at its Channel 9 Wiki page.


    I had to uninstall the beta 3 version because it either hangs or kills Internet Explorer.


    If you need HTTP debugging, you'll need the Fiddler Tool, but that's outside of Internet Explorer.


    Web Development Helper


    This is a free tool from Nikhil Kothari that provides HTTP tracing, client-side script diagnostics and tracing, as well as an immediate window.


    For ASP.NET developers, when developing against your site on your local development machine, this tool provides the ability to view ViewState, ASP.NET trace messages, contents of your cache etc.


    The following is a list of features offered by the tool:


    • A warning when either debug or trace have been turned on. Ability to hide trace information from the page, and view it in a separate dialog, so it does not get in the way of your page's layout.
    • Ability to view the page's view state (in various forms: raw, parsed, and decoded) to help you optimize your state management logic.
    • Ability to view items stored in cache, and remove them for testing purposes.
    • Ability to shutdown the application (unloading the associated AppDomain), in order to test starting it from a clean state.
    • Ability to log all HTTP (and HTTPS) traffic between the browser and your server, and view request and response details, including those performed via XMLHttpRequest.
    • Ability to view the live HTML DOM using a DOM Inspector that allows viewing all elements, selected elements, or elements matching ID or CSS class. For each element, you can see the markup, attributes, and style attributes.
    • Ability to view rich error information for script errors (full call stack, script URL and line number), as well as a script immediate window to execute some script against the current document.

    I haven't tested this tool myself but I saw a friend of mine using it and it messed with all those characters (ãçõ) that we, Portuguese people, have the hasty habit of using. So, I never even downloaded it.


    HttpWatch


    This is a tool from Simtec Limited and has both a Basic (free) and a Professional (paid) version.


    HttpWatch Feature List



    Support is provided by e-mail or telephone.


    IEWatch


    This is a tool from IEWatch Software LLC and has no free version.


    IEWatch Feature List


    HTTP Features



    • Captures HTTP and HTTPS - HTTP(s) headers including authentication headers, status codes, Cookies, URLs, POST data, Query Strings and Response Content are recorded.
    • Export Data - The HTTP Log can be saved in various formats, including XML, comma separated and text format. The XML structure is described in the XML Schema.
    • Filters - IEWatch allows the most extensive filtering, including filters on HTTP headers and response content. You can store up to seven Filter definitions.
    • Find in HTTP Log - HTTP search functionality that displays the results in separate panes. Unlike the filter operation, the Find in HTTP Log function can be applied after browsing to repeatedly search in the HTTP log.
    • Dynamic HTTP Header help - Comprehensive help for HTTP headers and status codes are available by simply pressing the F1-key.
    • Compare Requests - IEWatch allows comparing two requests using an external diff utility, for example Microsoft® WinDiff.
    • HTTP Notes - You can use notes to tag specific HTTP requests. Notes can be useful to relate HTTP requests to HTML pages.
    • HTTP Performance Charts - Use the Timeline Chart to spot performance bottlenecks and to tune the performance of your web site.
    • Automation Interface - You can use the automation interface to integrate IEWatch with your favorite testing framework.
    • Docking Windows - Configure your work area with Visual Studio® style docking windows.

    HTML Features



    • Tree view of the HTML structure - The tree view reflects exactly the structure of the HTML page even if the page contains many sub documents. You can drill down on HTML elements to display details on links, images, scripts, style sheets, applets, ActiveX objects and forms.
    • Page Summary - The Page Summary window displays statistical information on the web page including page load time and page weight.
    • Image List - IEWatch shows you the image size, height, width and the download time of the image in one glance.
    • HTML Designer - Allows visual HTML modification by clicking and editing items in the web page.
    • Rapid Prototyping - You can modify the HTML Style Sheets and Scripts of any web page to quickly test code or develop prototypes without having to create development environments.
    • Script Debugging - Use the Immediate window to trace debug messages, evaluate variables or issue commands.
    • Highlight HTML elements - Locate and highlight HTML elements in the HTML code window. This feature applies to any link, image, applet, ActiveX control or form element.
    • HTML Spotlight - This feature allows quick pinpointing of any element in the HTML code by directly clicking in the web page (Patent Pending).
    • Docking Windows - Configure your work area with Visual Studio® style docking windows.

    IEWatch Tools



    • Capture Screenshot - Take screenshots of a complete web page or Internet Explorer window and email or save the screenshot.
    • Window Transparency - You can apply transparency to the IE window which is useful for comparing a modified page or image to the original. Additionally you can apply transparency to the IEWatch window to monitor HTTP traffic while viewing the web page.
    • Resize IE Window - This tool allows developers to resize and fine tune web pages to different screen sizes.
    • Color Picker - You can pick the color of any pixel on the screen or you can choose a color in the color palette. This tool integrates seamlessly with the rapid prototyping features.

    Support is provided by e-mail through a web form. There is also an online FAQ.


  • Your Own


    And you can always build your own Browser Helper Object (BHO).

    ASP.NET Controls – The Bridge between Client and Server-Side

    Nuno has just published his second article on a series about ID generation for ASP.NET controls.

    ASP.NET Controls – Understanding id generation

    Nuno has just published his first article on a series about ID generation for ASP.NET controls.