August 2005 - Posts

The bits are baked for the preview of Language Integrated Query, according to Matt Warren. I almost feel guilty for taking a vacation (with hardly any Internet connectivity) immediately after the PDC. Installing the bits will have to wait until I return to the Netherlands.

Tonight I was planning on fine-tuning my presentation on blogging for the second session of a course on presentation techniques. But WinFS interfered. I couldn't resist giving it a spin.

Here's my first look on Beta 1 of WinFS. In this post I will focus on some parts of the infrastructure. I don't want to start with regurgitating the WinFS documentation, which seems to be in good shape for a beta.

Installing WinFS is a breeze. The MSI file is 40.5 MB in size. It's a no questions asked install that takes only a couple of minutes. The setup installs both the WinFS runtime, the SDK and the Visual Studio 2005 integration. A reboot is required after installation.

WinFS nestles itself in %WINDIR%\System32\WinFS. The SDK lives in %ProgramFiles%\Microsoft SDKs\WinFS. WinFS datastores reside in %SystemDrive%\System Volume Information\WinFS.

The WinFS runtime consists of three services running in three separate processes:

  1. WinFS.exe. The WinFS data store. Runs a Yukon derived database engine. 86 MB peak working set after reboot. After some fooling aroung this goes up to 120 MB. Just after the reboot this process has 4034 CLR classes from 79 assemblies loaded in 3 appdomains. This goes up to 6.985 classes from 123 assemblies.
  2. WinFSSearch.exe. Runs the WinFS Search Engine. I guess a derivative of Index Server. 11 MB peak working set after reboot. Runs no managed code.
  3. WinFPM.exe.  The WinFS File Promotion Manager. 14 MB peak working set after reboot. Goes up to 35 MB.  Has 13 CLR classes from 3 assemblies loaded in 1 appdomain after reboot.  This goes up to 1.048 from 19 assemblies.

So WinFS still heavily depends on the .NET Framework. From a programmer's perspective this is good thing. I am still worried about the memory usage though. I've created just a couple of files and folders.

WinFS stores can be accessed using a new type of shares. A WinFS looks just like a regular share:

 Screenshot of WinFS store viewed as share

You can also see the stores appearing through a new shell extension for WinFS Stores under My Computer:

 Screenshot of WinFS Shell Extension

WinFS stores filestreams as ordinary NTFS files with a GUID as filename under the System Volume Information folder. Metadata is stored in a SQL Server database. Here is a screenshot of the NTFS backing store for the same folder you saw above. Note how the filesize and date modified are equal.

Screenshot of hidden backing store for WinFS filestreams

Some random observations:

  • I could only create a new store on my system partition C: and not on one of my other partitions.
  • WinFS does not support encryption and compression (yet?).
  • No support for Windows XP document metadata in NTFS alternate data streams (yet?). You can enter this data through the Summary tab on the Properties dialog box for a file. This is a shame. Old style metadata like this should be promoted and demoted to WinFS transparantly, because that's what WinFS is for.
  • WinFS does not support the Transacted File System (TxF) of Windows Vista (yet?).
  • The query language OPath is mentioned in the WinFS documentation. There is a relation with the Integrated Query Framework according to this blog post on the new WinFS Team Blog:

    On query, many of you have heard about Anders Hejlsberg’s work on Language Integrated Query – and the new ADO.NET functionality will plug directly underneath so that you can use the new query patterns on any entity data, including of course now WinFS Items.

    I wonder if OPath is here to stay or just a left over from the PDC 2003 version that will go away once Language Integrated Query takes over.

 

Quite unexpectedly Beta 1 of WinFS has been released (not launched, but really released ;) on the MSDN Subscriber Downloads site.

According this blog post by Tom Rizzo, Microsoft has released Beta 1 this early to give people time to evaluate WinFS before the PDC. I am very curious how WinFS has progressed since October 2003. At that time it was a big memory hog.

This are the system requirements according to the release notes:

  • Microsoft® Windows® XP Professional with Service Pack 2 (SP2) or Microsoft Windows XP Home Edition with SP2.
  • A 2.0 gigahertz (GHz) Intel Pentium 4, or AMD Athlon, or compatible processor is required. 3.2 GHz or higher is recommended.
  • 512 megabytes (MB) of RAM or higher is recommended.
  • An NTFS file system partition with 700 MB of free space is required to install and run "WinFS" Beta 1.

WinFS Beta 1 requires Beta 2 of the .NET Framework to be installed. The SDK can cooperate with Beta 2 of Visual Studio 2005.

I seem to qualify and I like living on the edge with alphas and betas so I am going to install it on my main Windows XP partition. This installation has survived several alpha and beta installs, so if WinFS drives it over the edge, so be it.

Tell tale signs that a reinstall is due:

  • A couple of months ago my Windows logo + E key combination inexplicably stopped working. It should fire up a new Explorer window but is now a no-op. All the other Windows logo key combinations work fine and Google hasn't helped me.
  • The programs menu starts to fill up the entire screen and it takes about 10 seconds before it appears the first time I click Start | Programs.

Confusing isn't it: BizTalk Server 2006 will be launced on the same date as Visual Studio 2005 and SQL Server 2005.

At first I thought this was just because the release of Visual Studio and SQL Server 2005 was delayed after the naming had been finalized. The new version of BizTalk Server was announced later and so it could have 2006 in the name without looking a year old just two months after the release.

Well according to this interview with Scott Woodgate at TheServerSide.NET it seems the product is launched only for marketing reasons on the same date as Visual Studio and SQL Server. Apparently it doesn't mean anything for the release date. BizTalk Server will not be released on November 8, 2005 but somewhere in the first half of 2006. Here is a part of the transcript of the interview:

Q: You mentioned BizTalk Server 2006. It was just announced that BizTalk Server 2006 would be launched with Visual Studio 2005 and SQL Server 2005 with a release to be sometime in the first part of 2006. Can you explain the difference between launched and released and when are we actually going to be able to buy BizTalk Server 2006 and deploy?

A: Well, you have to put with some Microsoft jargon here while I address that question Paul, So BizTalk Server 2006, I would love to talk to you about the features later in a minute, and SQL Server 2005 and Visual Studio.NET 2005 are incredibly related products. With those three products, you can do a whole ton of things in the integration space. They are all built on the .NET framework 2.0. We support BizTalk supports SQL Server 2005, Visual Studio.NET 2005. So, these products, they are just meant to be together and this is really the first time in the history of the development cycle that all three products are lining up for a release in a similar timeframe. One of the challenges, however, as the BizTalk guy that builds on top of Visual Studio and SQL Server is for me to release I have to be waiting like everybody else, I am sure is on TheServerSide for SQL and Visual Studio to release. So once those products have RTMed, it will take me some time in terms of the development cycles to make sure that our product is on top of the RTM versions and released BizTalk Server. So, we want to be able to release the RTM on the same time. On the other hand, the SQL guys and the Visual Studio guys are doing some massive launch events around the world and it just makes so much sense for BizTalk Server to be in then. Just from a marketing perspective, lots of noise on BizTalk Server, you probably have been hearing more and more about BizTalk Server well you're going to hear it louder and louder through those. So, actually what Paul Flessner announced in his Tech-Ed keynote was that Visual Studio, SQL and BizTalk Server would launch on November 8, if I remember rightly and what launch means is a set of events where everybody has a party and I am sure that Visual Studio and SQL will be done by that point. On the other hand, BizTalk Server will not be done. We expect that BizTalk Server will ship in the first half of calendar year 2006, right now having just released the community technical preview, I would say I would be feeling pretty good about early in calendar year 2006. But I am going to leave it a little open to first half given that we haven't yet made it to a Beta one. The idea here is launching these products together from a marketing perspective builds to really work with each other and we will be delivering it shortly after them.

Note that the interview was just released on TheServerSide.NET, but seems to be recorded shortly after TechEd USA. So before Beta 1 of BizTalk Server 2006 was released.

Another thing that still confuses me is the dependency of  BizTalk Server 2006 on SQL Server 2005 and. Scott calls them "incredibly related products". I installed Beta 1 and noticed that the documentation recommends installing on top of SQL Server 2000 instead of SQL Server 2005. Some parts of Beta 1 of BizTalk 2006 even require some SQL Server 2000 components to be installed even if you are running on SQL Server 2005.

On his blog Scott calls Beta 1 "functionality complete". Considering the dependencies on SQL Server 2000, I fail to see how BizTalk Server 2006 takes advantage of new features of SQL Server 2005. I would be really disappointed if by RTM BizTalk Server 2006 will only run on SQL Server 2005 and no longer on SQL Server 2000. Microsoft wouldn't be pushing the sales of SQL Server 2005 without technical merit or would they? ;)

Via Chris Anderson's blog I found this video done by a couple of interns at Microsoft. Its description is:

Five Microsoft interns decided to "celebrate" the end of their time at the software giant by making a wonderfully dorky music video.

It's dorky indeed. I haven't seen anyone running around in and on top of our company building shooting a music video. So I wonder if it's just our company policy or our European culture that prevents this ;)

(BTW: This reminded me of one of my youth sins. Guess which one. No, it's not making a music video ;)

Time for another Visual Basic 9.0 posting. Paul Vick is giving us another teaser in a very short post titled What if everything could be queried with SQL?. Paul doesn't mention VB 9.0 in this post, but I'm pretty that's what he is talking about (and the Integrated Query Framework of course).

Also related to this is the Channel 9 video CLR Team Tour, Part II - The Future of Languages (PDC panel preview). In my opinion this is one of the best Channel 9 videos because you will see and hear a lot of interesting people from the CLR team, like Brad Abrams, Rico Mariani, Jason Zander and Jim Miller. It is nice to see how these people interact.

At about 40:30 minutes into the video Erik Meijer has an interesting exchange with Robert Scoble on VB. Here is a transcription of that part:

Eric: One of the things I want to stress is that there is a big spectrum from a completely dynamic language like IronPython to a completely static language like C# or C++. There is also an interesting kind of middle ground. The funny thing is that Visual Basic is right there in the middle, because it allows you to do static typing but it also allows you to do dynamic typing.

Robert: Isn't that where the marketing problem of VB is right now, because it doesn't stand for anything? There is not a religious thing that you can put a stake in the ground for. So you gotta use VB for this or that.

Eric: That will change, I will bet you.

Robert: (big laugh)

Eric: In a year's time people will point at VB as an example of modern language design. Especially because it allows you to span these two worlds  between static and dynamic typing.

As you may know I am a fan of more relaxed typing but I hope I will not have to suffer the VB syntax to get these benefits. Anders Hejlsberg is always very concerned about putting things in a language, like C#, that will age it quickly.  In my opinion one of the problems with VB is that it is already an aged language and as a result it struggles a bit with ambigous syntax. I admit a lot of that was cleaned up with the move from VB 6.0 to VB 7.0 (aka VB.NET 1.0) but not enough to win me over.

Also I love my angle brackets and case-sensitivity. If C# 3.0 will not get the cool new dynamic features of VB 9.0, I hope a language will arise which has both these features and the C-language family syntax.

It was an interesting read to learn how the ATLAS project, that the ASP.NET team is working on, originates in part at MSN. As you can read on Scott Guthrie's blog ATLAS is a new framework for developing AJAX style web applications using ASP.NET.

Dare Obasanjo quotes Omar Shahine and adds:

Trying to build a complex AJAX website with traditional Visual Studio.NET development tools is quite painful which is why the various teams at MSN have collaborated and built a unified framework. As Omar points out, one of the good things that has come out of this is that the various MSN folks went to the Microsoft developer division and pointed out they are missing the boat key infrastructure needed for AJAX development. This feedback was one of the factors that resulted in the recently announced Atlas project.

(...)

If you're going to be at the Microsoft Professional Developer's Conference (PDC) and are interested in professional AJAX development you should definitely make your way to the various presentations by the MSN folks.

My PDC schedule is already heavily overbooked due to the incredible abundance of interesting sessions. I'll try to stick in one or two of these sessions since I have a love for AJAX since long before it was called that way. Let me copy in a comment I made in Dennis' blog back in the days when I did not have my own blog yet:

AJAX = Old technology ;) At the bank I work for we have used a similar approach since 2000. We call our framework R***SCO. SCO stands for Server Communication Objects and R*** stands for part of the name of the Dutch bank that is to remain anonymous. Hard guess, hey?

Our technology dates back from before the XmlHttpRequest days. We designed a method using posting requests to and from hidden frames and returning data as client-side JavaScript code generated with ASP with server-side JavaScript. This can be fast because Internet Explorer is very good at parsing and interpreting JavaScript. With this data dynamic parts of the page presentation are generated using DHTML.

The reason we did this back in 2000 because we were confronted with the demand that the output of dynamic web pages could not be larger than 5-10 kB due to very strict bandwidth restrictions. So we had to separate presentation code from data. Static code was preloaded on proxy servers at remote locations. Some applications loaded some 400 kB of static HTML and JavaScript code from the proxy server or the browser cache on startup and just a couple of kB with dynamic data from the web server.

Unfortunately this technology is proprietary to the R*** bank so it cannot be borrowed. Heavy use of frames and clientside JavaScript has fallen out of favour with the enterprise architects of the bank. Also our code is very IE4-6 specific. So now we use plain old ASP.NET ;)

 

Tonight I went to the monthly dotNed user group meeting. Dennis Mulder and Pieter de Bruin of Avanade gave a presentation and a demonstration of Visual Studio 2005 Team System Client + Team Foundation Server.

Not a lot of people in the audience had experimented with Team System. Maybe this is due to the hefty system requirements. At my department of LogicaCMG we have installed and used several versions of Team System up till Beta 2. That last version was stable enough to use as source control system for a small project and looked very promising.

During the meeting there was a discussion on checkin policies and whether or not a policy existed to check for build errors before allowing checkins. Dennis and Pieter had not seen it. I remembered using it together with Lennard Bakker (a colleague from LogicaCMG) in the project mentioned above.

Unfortunately I cannot connect to our Team Foundation Server from home to check it, but I found a blog entry about it on the Team Foundation's WebLog. In Beta 2 it is called the Clean Build checkin policy. The post indicates that it is integrated in the Code Analysis checkin policy after Beta 2 and no longer a separate policy. I haven't checked out the July CTP so I am not sure if the change is there. The Team Foundation's WebLog has gone silent after May 2005, so I guess everybody on the team is hard at work on Beta 3 of TFS.

Maybe Dennis will give me a warning for polluting the photo galleries, but I couldn't resist sharing this photograph. I shot this photo this morning at 6:30 AM from my appartment with my Canon camera.

Photograph of a beautiful morning in Zeist (click for larger version)

And to make this blog post about .NET so it can be syndicated on the main feed. Today I gave a presentation about blogging and BloggingAbout.NET at a LogicaCMG course on presentation techniques. Unfortunately I couldn't convince the audience (that included some non-techies) to start their own blog. But my goal was creating awareness, not conversion. Now they know what RSS is!

Blogging about the YouBastardException reminded of another funny thing that was added to that Intranet application. After a code review I had a discussion with one of the developers on his "dark side coding practices". To annoy me, after this discussion he put in the following line of code:

bool theDarkSideRules = true;

Notice how it conforms nicely to the MSDN capitalization guidelines. But, this was the only line in which this local variable was used. So it gave a nice The variable 'theDarkSideRules' is assigned but its value is never used compiler warning every time the assembly was compiled.

This line is still present in the code to this day ;)

Please post a comment or a trackback if you have any nice examples of inside coding jokes.

I was just listening to the latest .NET Rocks! Show featuring Brad Abrams and Joel Pobar. I have been a fan of Brad and his blog since just before PDC 2003. Go listen to the show if you are interested in the CLR.

Brad was talking about a dev on the CLR team putting in a YouMoronException for a rare pathological error case. This reminded me of a YouBastardException that I defined in one of my first .NET projects a couple of years ago. This type was thrown when somebody deliberately tried to hack the application by passing invalid parameters. The application (an Intranet application) is still up and running and I can still trigger this exception type by messing with the query string in the URL. However the name of the exceptiontype will only show up in the logfile and not in the error page shown to the user.

Recently somebody asked me if I had included a similar exception in my current project. The answer was, no I didn't. You better not do this in an Internet facing application. Showing track traces to the user should be turned off, but a configuration error is easy to make. I have settled for the more neutrally named InvalidParameterException this time ;)

Please read my earlier post on generating XHTML output from ASP.NET 1.1 before reading this post.

Summary:

  • We use custom controls to generate XHTML 1.0 Strict markup.
  • We parse the ASP.NET output as XML.
  • We tweak the form element and an input element to make the entire page XHTML 1.0 Strict.
  • We map parts of the XHTML tree of the ASP.NET output into an XHTML 1.0 Strict static page produced by a content management system (CMS).

The last point is our answer to how to ensure and maintain a common look-and-feel between the static XHTML pages published by the CMS and the dynamic ASP.NET pages. In this post I will give more background and detail on this design decision. Because it's not the only approach possible.

The CMS we use is of Dutch origin. Unlike Microsoft's CMS it publishes pages to the web server that have no runtime dependency on the CMS. So they are static from the CMS perspective. The choice for the CMS in question was fixed before ASP.NET entered the picture. One option to make some pages dynamic is to publish .asp, .aspx or .jsp pages that contain code to be executed on the web server. But they will still be static from the CMS perspective. Anything that the CMS does, like creating a common layout and helping with links among web pages and to resources like images, is done at publication time. Not when the page is served to a browser by the web server.

The old style approach would have been to use frames. The static part of the page with the common look-and-feel would be published by the CMS and the dynamic part would be framed inside it. Using frames has well-known drawbacks so this approach was quickly ruled out.

We thought about letting the CMS publish the .aspx pages for the .NET modules. This way the XHTML markup for the common look-and-feel and navigation menus on the .aspx pages can be build by the CMS from the same building blocks as the static XHTML pages. However a CMS is good at publishing content and not really good at managing and publishing source code. In the ASP.NET case you have depencies on assemblies containing the compiled code-behinds. Do you want these to be published by the CMS as well? Do you want to run the risk of a content editor messing up the markup of your ASP.NET page and breaking the close relationship with the code-behind assemblies which they cannot edit?

So we decided to take a different approach. The ASP.NET pages and the assemblies live separate from the CMS content on the web server and are not managed or published by the CMS. The ASP.NET page knows what content template it should use, fetches it and maps its own output into container elements (like divs) in the XHTML content template. The resulting XHTML document is what gets sent to the browser.

Well it is not really the ASP.NET page itself that performs the mapping, but an IHttpModule which I will call the content mapper. So how does it know what content template to use? One of the requirements was that a single ASP.NET page might be mapped into several different content templates depending on the context in which the .NET module in question was being used.

The .NET modules are linked to from static XHTML pages published by the CMS. A static page that links to a .NET module represents a navigation state which I will call the navigation context for the .NET module. You can see the navigation state as the highlighting of menu items and in the folder structure in the URL. It shows you where you are in the navigation structure of the site. One of the requirements was that the .NET modules would keep the visual navigation state intact. They should support different navigation contexts, i.e., a .NET module should adapt like a cameleon to the page that linked to the module. In the old days the easiest way to solve this would be to use frames. As I mentioned before these are out of the question.

The first idea to keep track of the navigation state was to read the HTTP referrer header value to see which page linked to the .NET module. This value was to be passed along in a hidden field if the .NET module itself has multiple pages. But I didn't like the strong dependency on an HTTP header that is sometimes blocked by proxy servers or personal firewalls. I wanted it to be possible to explicitly tell the .NET module what navigation context to use. Also I disliked the hidden field idea. It puts an extra burden on developers of .NET modules to pass it along. You always have to use HTML forms to pass it along, and you have to use POSTs instead of GETs for those forms or you'll end up with all form fields in the URL and not just the navigation context parameter. 

I wanted the whole content mapping thing to be as much a black box as possible for the developers. I felt the best place to keep track of where you are in the site is the URL you see in the address bar of your browser. And I don't mean the query part, but the path part of the URL. So I decided to solve this issue together with the requirement that URLs to pages in the site should not include extensions like .aspx or .html.

We settled on a URL format that looks like this: http://www.finance.nl/advice/savings/context/information/savingsacounts/. And this URL actually points to the same .NET module but in a different context: http://www.finance.nl/advice/savings/context/thisweektips/. The .NET module is deployed in a single virtual directory: /advice/savings/. The part after that in the URL does not correspond to a real virtual directory. It just identifies the navigation context. The virtual directories /thisweekstips/ and /information/savingsaccounts/ do exist. These are the locations that the content mapper uses to fetch the content template for the navigation context from.

The trick to accomplish this is to configure a wildcard mapping in Internet Information Server (IIS) for the virtual directory /advice/savings/. This means configuring the .* extension to use the ISAPI extension aspnet_isapi.dll. This way all requests for URLs within that folder will be handled by ASP.NET.

ASP.NET uses the machine.config and web.config files to determine what IHttpHandler to invoke. An ASP.NET Page is an example of an IHttpHandler. We configure a wildcard mapping for * in the web.config file. But instead of specifying a concrete IHttpHandler, we specify a class that implements IHttpHandlerFactory. I will call this class I wrote the CustomPageHandlerFactory. It parses the URL and determines what the navigation context is and what .aspx page to invoke. For the two URLs above this would be a configurable default page in the savings directory, but for the URL http://www.finance.nl/advice/savings/page2/context/information/savingsacounts/ it would be page2.aspx. After parsing the URL the CustomPageHandlerFactory puts the navigation context in the current HttpContext. This way the content mapper can use it later on in the page processing. Finally the CustomPageHandlerFactory gets the IHttpHandler for the .aspx page by calling PageParser.GetCompiledPageInstance. PageParser is part of the ASP.NET infrastructure code. It's not intended to be called by user code, but it's a public class and works well. The IHttpHandler is returned to the ASP.NET runtime which invokes it to process the request.

On a closing note. I have left out some details and cannot share my code as it is owned by the client I work for. While googling for some pages to link to I found a blog post detailing a similar approach. Matias has a simple implementation of a PageHandlerFactory that you can download.

What better thing to do on a late Saturday night/early Sunday morning than to read up on service design?

Before you answer it, this is a rhetorical question and I know I should get a life ;) In fact I am going to Sail 2005 in Amsterdam later this day with a friend and it looks like the wheather is going to be good.

But back to the subject of this post. John Evdemon from Microsoft published two articles on service design on MSDN last week:

  • Principles of Service Design: Service Patterns and Anti-Patterns
    Summary: This paper, the first of a multi-paper series, provides some fundamental principles for designing and implementing Web services. The paper starts with a brief review of SOA concepts and leads up to a detailed discussion of several patterns and anti-patterns that developers can leverage when building Web services today. Guidance in this paper is applicable to any programming language or platform for which Web services can be developed and deployed.
  • Principles of Service Design: Service Versioning
    Summary: This paper is the second in a multi-paper series focusing on service design principles. This paper surveys some fundamental guidelines for versioning schemas and Web services. Six specific principles for versioning Web services are identified.

The first article is highly recommended for anyone new to service orientation, because it starts with a good introduction and explanation of the four tenets of service orientation. The patterns and anti-patterns give concrete advice on do's and don'ts when designing service interfaces. The guidance in the second article is also pretty concrete.

I am looking forward to future articles in the series. I like John's writing style and approach to giving guidance.

Since last week we have an accessibility expert blogging on BloggingAbout.NET: Nathan J Pledger. His first post inspired me to blog about my current project.

As I mentioned in a comment on Nathan's first post, I currently work in a team on the new web site for one of the major financial institutions in the Netherlands. This web site will go live sometime later this year. Most web pages on that site come from a content managent system. All web pages are designed to conform to the XHTML 1.0 Strict standard. I.e., they should be valid when being validated against the XHTML 1.0 Strict DTD. This in itself helps in creating an accessible site by separating layout and content and working well across different browsers.

Extraordinary care is taken to ensure that markup is semantically correct. Tables are only used for tabular data and not for layout. Lists are marked up using the XHTML elements for lists: ul, ol and li. Etc. etc.

One of the design goals is that pages will work well with JavaScript turned off and with CSS styling turned off. JavaScript should only enhance the browsing experience when available but it should not break the page when it is not available. This means that drop down menus are marked up as regular XHTML lists of links. These are accessible to people using screen readers or with JavaScript turned off. When JavaScript and CSS are available those lists will be converted through the DOM to drop down menus with fancy shading etc. We have had CSS and accesibilty experts working on creating the stylesheets, JavaScripts and templates for accessible pages.

ASP.NET is used for dynamic pages that depend on user input, like pages that give advice on what type of savings account is best suited for someone. I will call these types of web applications within the site .NET modules.

For the content management system this was not so difficult to implement.  But for ASP.NET 1.1 it was. As you may know the default output of ASP.NET is not XHTML compliant. Furthermore it has a lot of controls that output JavaScript that does not work well outside of Internet Explorer. There is poor support for using CSS. The HTML editor is a disaster. I could go on, but to cut the list short, I will jump to the conclusion: we had to roll our own custom controls and page rendering.

We use the standard ASP.NET Page model, its lifecycle and its postback model. We don't use most of the standard controls and we have build our own custom controls. These custom controls render XHTML 1.0 Strict output and can work with or without JavaScript in a cross-browser compatible way. Without JavaScript the standard ASP.NET auto postback functionality will not work. For instance when you select another radio button the page cannot not be posted back automatically. With standard ASP.NET you are out of luck if want to modify the page in response to the user selecting another option. When JavaScript is not available we render  submit buttons next to such controls to allow the user to update the page. This simulates the auto postback behaviour. So how do we know if  the user has turned JavaScript  off  when we render the page on the server? We don't. The trick is to always render these extra submit buttons, and then remove them from the page using clientside DOM manipulations when JavaScript is available.

Having custom controls that render XHTML 1.0 Strict is not enough when you want to use the standard postback model. There are two well known problems with the standard ASP.NET output. The form element  rendered for postbacks by ASP.NET contains an illegal name attribute according to the XHTML 1.0 Strict DTD. And the <input name="__VIEWSTATE" .. /> element should be wrapped in a container element like a div.

To fix these issues we post process the ASP.NET output by using a response filter. This filter is installed by an IHttpModule in the ASP.NET pipeline for each request for an ASPX page. This response filter parses the ASP.NET output as XML. If the ASP.NET output is well formed XML, this is already a good step on the way to XHTML compliance. A developer will know instantly that there is a problem if the output cannot be parsed as XML, because the filter will throw an InvalidAspNetOutputException.

Most approaches to fixing ASP.NET output mentioned on the web use regular expressions or other forms of string parsing to fix the output. We use XML parsing because we have to do additional manipulations on the output on top of fixing the XHTML issues. We have to integrate the ASP.NET output with static pages published by the content management system. Parsing the ASP.NET output as XML imposes a significant overhead with noticably longer processing times on the server, but in our case the resulting performance is acceptable.

After fixing the XHTML issues, parts of the ASP.NET output are mapped into container elements in a XHTML 1.0 Strict content template. This content template comes from the content management system. It contains the skeletons for the layout of the page and the references to external stylesheets and JavaScripts. The .NET module inserts its own title in the title tag of the template and adds additional meta elements to the document. These mappings can be configured in a flexible way using an XML configuration file that is read using the Enterprise Library at run-time. Think of our mapping functionality as "XSLT light". After the mappings have been performed, the resulting XHTML document is rendered to the standard ASP.NET output stream. If all goes well the browser receives an XHTML 1.0 Strict compliant and accesible page rendered by ASP.NET 1.1!

In another post I will go into some additional design goals that we had, like not showing the .aspx extension in URLs and I will tell more about how we integrated with the content management system.

BTW: Don't look at the HTML code for postings on this Community Server. It contains horrendous old style markup with font tags all over the place ;)

Monday I blogged about a problem I encountered with the RollingFileSink. Unfortunately deleting the logfile once and waiting for more than 15 seconds before creating a new log file solves the problem only for one day (or whatever age limit you have set). To fix the problem completely I had to change the RollingFileSink. Fortunately that is possible because Hisham Baz released RollingFileSink in source code form.

I fixed the LogRoller class. You can find the code that I changed and added below or you download LogRoller.cs. The line with CreateNewLogFile(); in the PerformRenameRollover method is new and the CreateNewLogFile method itself is new. (Note that the indentation of the code is lost due to problems with our blog engine).

/// <summary>
/// Archive the current log file by renaming it with today's timestamp.
/// Generate a new filename for the current log file using a <see cref="FilenameBuilder"/>.
/// </summary>
public void PerformRenameRollover()
{
Purge();
if (File.Exists(_info.FullName))
{
string newName = _builder.CreateNewFilename();
File.Move(_info.FullName, newName);
CreateNewLogFile();
}
}
/// <summary>
/// Creates a new current log file and explicitly sets its creation <see cref="DateTime"/> to <see cref="DateTime.Now"/>.
/// </summary>
/// <remarks>Explicitly creating the new file and explicitly setting its creation <see cref="DateTime"/> is
/// necessary due to file system tunneling. Due the file system tunneling a new file will get the creation <see cref="DateTime"/>
/// of an older file that existed with the same name but that was deleted or renamed within 15 seconds of
/// the creation operation.</remarks>
private void CreateNewLogFile()
{
FileStream newLogFileStream = File.Create(_info.FullName, 1);
newLogFileStream.Close();
File.SetCreationTime(_info.FullName, DateTime.Now);
}
More Posts Next page »