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:
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:
- 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>
<!-- ... -->
// ...
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
e.Authenticated = FormsAuthentication.Authenticate(Login1.UserName, Login1.Password);
}
// ...
- Using FormsAuthentication as the membership provider
This one is a bit trickier.
First you don't need to handle the Authenticate event.
<!-- ... -->
<asp:Login ID="Login1" runat="server" DisplayRememberMe="False">
</asp:Login>
<!-- ... -->
Then you need to implement a membership provider that uses FormsAuthentication.
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
}
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:
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
- Records HTTP
- Decrypts HTTPS Traffic
- Integrates with Internet Explorer
- Compact & Comprehensive Log Files
- Standalone Log File Viewer
- Summary of Recorded Traffic
- Collect Log Files From Customers
- Automation Support
- Millisecond Level Timing
- Advanced Filtering
- HTTP Compression
- Dynamic Sorting
- Extended Cookie Information
- Network Level Performance Data
- Raw HTTP Streams
- Shows Interaction with Browser Cache
- Keyboard Accelerators
- Export Data to XML and CSV
- Accurately Records Requests and Responses
- Access to Cached and Downloaded Content
- UTF8 Support for International Characters
- Easy, Simple and Powerful
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).
Recent Comments