September 2006 Entries

Since I have to define my fault details with DataContractSerializer attributes for now (I hope it's only for now anyway), I was looking at how to translate a property that was previously serialized by the XmlSerializer using XmlArrayAttribute and XmlArrayItemAttribute. Well, I figured out pretty quick there was no equivalent, found CollectionDataContractAttribute, but thought "noooo, this can't be the only way... can it?". Unfortunately a quick search revealed this post by Christian Weyer that confirmed my fears. Why oh why do I have to go writing a whole new collection class now just to decorate it with attributes when I could decorate the member itself?

Argh... there's nothing more frustrating than seeing an API try to re-invent the wheel and end up with something that is worse off than what we have today. :(

posted Thursday, September 28, 2006 2:01 PM | Comments | Filed Under [ .NET WinFx/Vista Web Services ]

Just found out WCF does not supporting XmlSerializerFormat for custom fault details (see note under Creating Strongly Typed Faults section here). Everything else in my contracts is defined using this approach and now I have to use DataContracts for my fault details? What's up with that? Seems superbly  lame and inconsistent to me.

Gonna have to take this one to the forums and possibly to the bug database...

Update: No response to my forum post as of yet, so I entered a bug. Go vote on it if you agree that this inconsistency in the API is "teh suck".

posted Wednesday, September 27, 2006 9:40 PM | Comments | Filed Under [ .NET WinFx/Vista Web Services ]

One of Robert's first show's is a visit to Printing for Less. First off, kudos to Robert for such a great show. I love the loose format and Robert asks great questions both from the perspective of a geek as well as the average end user. 

Next, it's really cool to see this industry finally get some coverage. I would take issue with some of Andrew's claims (biggest in the industry, rest of industry flat, 1bil impressions on hardware from 1976, etc.), but in all it was really cool to see how someone else is solving the same kinds of problems as Mimeo does.

I emailed Robert when he originally mentioned he would be doing a piece on Print for Less and invited him to come check out Mimeo. It would be an amazing contrast in terms of the both the type of printing the PFL does vs. what Mimeo does as well as the technology used compared to what we do. It would seem that Mimeo solves a lot more of the printing problems with technology than PFL does. At the same time we have a stellar customer care team that is available 24x7 to answer questions and solve any problems that may arise.

Anyway, the invitation is still open Robert. I'd love to give you a tour of our NY office, where most of the development team lives as well as the majority of sales people, as well as our Memphis office/production facility where all real work is done. We don't have solar lighting or a dog policy (though there's nothing that says you couldn't bring your dog in), but I still think it will make a great story and I know everyone here would be proud/eager to tell it.

posted Wednesday, September 27, 2006 1:38 PM | Comments |

I asked a question in the forums a week or so ago about how one could go about getting username credentials to be passed through HTTP. The problem is that, out of the box, WCF will not allow you to specify message credentials without using a secure transport. This is probably a really smart move for Microsoft because it will prevent people from exposing their credentials. While it certainly causes headaches with development since you need to configure certificates on all your dev boxes, that's probably still not a good enough reason for Microsoft to allow message level credentials go over HTTP (you just know the average developer will never switch to HTTPS when they deploy and will end up leaking customer credentials all over the internet). However, there is a very real world scenario where one might need clear/text credentials which is in the case where SSL is handled by a load balancing machine such as those provided by F5 networks.

First, let me explain what this SSL passthrough is all about. Basically the load balancer, in addition to it's normal duties, offloads the SSL work from the underlying server farm. There are two benefits to this:

  1. It has hardware acceleration for SSL, so you don't burn CPU cycles on your web servers.
  2. You can configure the SSL certificate in one place only.

What ends up happening is that an incoming SSL request gets decrypted and routed as a plain HTTP request to one of the underlying servers. Since the server might need to know whether or not the original request was indeed SSL, you can also optionally inject a new HTTP header to indicate that it was. Responses from the server are also plain old HTTP back through the load balancer where it is SSL encrypted before being sent back to the user. Simple, right?

Ok, so... now that we know why we might need to achieve this in WCF, let's talk about how it can be done. While the solution is included in the post I linked to earlier, I wanted to blog about it here in more detail. All the credit for the solution has to go to Pedro Felix who saw my post in the forums, figured out a way to make it work and contacted me offline with some sample code. On to the solution...

We can't use HttpsTransportBindingElement because it forces the SSL handling to be done by the service itself. At the same time we can't use a security mode of TransportWithMessageCredential over the plain old HttpTransportBindingElement. So what do we do? We create our own HTTP transport which does allow credentials to be passed. Fear not, this is actually really easy:

  1. Create a new class called HttpsViaProxyTransportBindingElement
  2. Subclass HttpBindingTransportElement
  3. Override Clone to return a new instance of HttpsViaProxyTransportBindingElement
  4. Override GetProperty<T> where you will return base.GetProperty<T> for all requests except for that of ISecurityCapabilities where you will return a custom implementation described in the next step.
  5. Create a new class called SslViaProxySecurityCapabilities and implement the ISecurityCapabilities interface with the following rules:
    • SupportRequestProtectionLevel - EncryptAndSign
    • SupportResponeProtectionLevel - EncryptAndSign
    • SupportsClientAuthentication - false
    • SupportsClientWindowsIdentity - false
    • SupportsServerAuthentication - true

Now you have yourself a custom transport which is capable of speaking plain old HTTP thanks to the base implementation provided by WCF, but by overriding GetProperty<T> and returning custom ISecurityCapabilities when the security settings of the transport are checked for the SecurityMode.TransportWithMessageCredential requirements it will allow this mode of operation.

It's at this point that I want to take this opportunity to warn everyone that this could lead to a major security risk if you were to use this approach and didn't have SSL provided by the front end. You're basically LYING about your capabilities (i.e. that you provide encryption) to allow for the credentials to be passed in clear-text. DO NOT ABUSE THIS APPROACH JUST TO WORK AROUND HAVING TO USE SSL FOR USERNAME CREDENTIALS.

Ok, so now that we have our custom transport implementation, we need to actually configure a binding to use it. This requires that we use a CustomBinding because the built in bindings revolve around the WCF native transports. While you could pretty easily put the CustomBinding together programatically, that's no fun. We want to do it with a config file, so we need to write a custom configuration element. Specifically, in WCF terms,  we need to write a BindingElementExtensionElement. Just like we did with the custom transport implementation we can simply inherit the majority of the behavior from the existing HttpTransportElement class. Let's look at how we'd do that:

  1. Create a new class called HttpsViaProxyTransportElement
  2. Subclass HttpTransportElement
  3. Override BindingElementType to return our HttpsViaProxyTransportBindingElement
  4. Override CreateDefaultBindingElement to return a new instance of HttpsViaProxyTransportBindingElement

We now have a custom binding element extension element which can use to configure a custom binding. Now let's see what a configuration file might look like that uses this:

<system.serviceModel>
  <!-- first we need to register our binding element extension -->
  <extensions>
    <bindingElementExtensions>
      <add name="httpsViaProxyTransport" type="YourNamespace.HttpsViaProxyTransportElement, YourAssembly"/>
    </bindingElementExtensions>
  </extensions>
  <!-- now we need to create a custom binding that uses our transport -->
  <bindings>
    <customBinding>
      <binding name="testBinding">
        <textMessageEncoding />
        <!-- require user name to be passed over the transport -->
        <security authenticationMode="UserNameOverTransport" />

        <!-- use our custom transport which has no proprietary settings, but 
             exposes all thesame settings as the plain old http transport -->

        <httpsViaProxyTransport authenticationScheme="Anonymous" />
      </binding>
    </customBinding>
  </bindings>

  <!-- here we would use the testBinding in our service endpoint -->
</system.serviceModel>

That's all there is to it. Now when the message comes into the front-end as SSL it is decrypted and sent as a plain HTTP request to on of the servers where the web service is running. With the changes we've made we are now allowed to received the user name credentials in clear text and process them at the service. When the service responds, the message is re-encrypted by the front-end and sent back to the client. The only limitation, which is discussed in the post, is that there no support for auto-WSDL generation. We would need to provide a custom implementation of ITransportTokenAssertionProvider and IPolicyExportExtension. For now I leave up to the reader though it may be the subject of a future post. :)

posted Tuesday, September 26, 2006 4:10 PM | Comments | Filed Under [ .NET WinFx/Vista Web Services ]
  • Startup time still too slow. OSX puts Vista to shame here.
  • Hibernate shutdown and resume time wayyyyy too slow. Both, OSX and XP put Vista to shame here which is interesting considering this was supposed to be a much improved feature of Vista.
  • In my dual monitor configuration, Vista gets confused which is my primary monitor when I disconnect and take my laptop home and then come back into work. It seems to think my external monitor is the primary monitor all of a sudden. And by that I mean it actually thinks the external monitor is the hardware of the primary monitor and vice versa. (I gotta file this as a bug...)
  • Explorer performance when deleting files is just completely f'd. I don't know what it is, but if I go to delete files from my Temp directory it will claim it will take hours for data as small as 21 megs... and then it will literally take an hour with all kinds of prompts about making sure I really want to do it. (Gotta file bug...)
  • Explorer performance when working with compressed folders (zip files) is also f'd. Aside from the fact that it just takes for ever to decompress, they always unzip to your Temp dir first which could be a completely diff. physical device which means that it needs to be unzipped there first, then copied over to where you really want it. Not a good implementation at all. Just put the files where I want them in the first place. (Gotta file bug...)

I hope some of these have been improved in the latest build, but I just don't have time to upgrade right now.

posted Monday, September 25, 2006 2:52 PM | Comments |

Weird Al's White n' Nerdy. Sheer genius. Nothing more even needs to be said.

posted Saturday, September 23, 2006 4:16 PM | Comments |

So, this is my first week running Vista (RC1) on my primary machine. It's a laptop that I use exclusively both at work and at home. The specs are:

 

Alienware M7700

  • 3.8GHz Intel P4 w/HT
  • 2GB RAM
  • 100GB 7200RPM SATA HD (two NTFS partitions)
  • nVidia GeForce 6800 Ultra Go (beta WDDM drivers)
  • Realtek High Definition Audio card (beta drivers)

I get a "Windows Experience Index" of 4.4 and that's really only because apparently a 3.8GHz ain't much these days. My graphics card gets me a whopping 5.9 and everything else is around 5.0.

 

I have to say first that I'm a sucker for pretty presentation and so I love Aero Glass. I find it both aesthetically pleasing as well as functional. For the most part it runs smooth as a baby's bottom on my machine. Video playback is a little chunky as is transitioning to and from Flip3D. Like others, I do wish there was a little more eye candy that could be enabled. I understand that Microsoft has to target a broad audience, but that doesn't mean they had to rip out the fancy features... just disable them by default. Also, I haven't played any games on here yet, but then again I don't really do that on the PC so much these days... that's what the 360 is for. ;)

 

Audio is a little rough. I don't have a very good soundcard to begin with... in fact the worst thing about this laptop is that the audio is absolutely the worst I've ever had in a computer in a long time. Vista wise I get a lot of cracking and stuttering with the most recently available beta drivers.

 

Disk performance has mixed results. To some extent, things feel infinitely faster than XP. Launching applications, loading media, building... they all seem quicker. However, if I do ANYTHING with zip files the performance is absolutely unacceptable. I don't know what they're doing, but they need to fix it. I do know one thing... they need to stop extracting zip files in the user's temp directory because if I'm not targeting the files to be extracted to that drive I have to pay a move penalty. Dumb. Also strange is deleting medium size directory structures. I went to delete my Temporary ASP.NET Files folder today and it estimated over 3hrs and constantly popped up confirmation dialogs about deleting subfolders. It really did take over an hour to delete what XP would have deleted in about 10 seconds max. Both of these problems however seems related to explorer and not really the I/O subsystem.

 

Now on to User Account Protection. Uhh... I like it! However the implementation is downright painful right now. I'm not even talking about the fact that I have to encounter it so often... that part is actually quite comforting to me because I feel protected. What I'm talking about is the actual UI implementation itself. How come the blacking out of the screen is so jarring? Hello... how about taking advtange of DWM? Eeeeaaaaase in the semi-transparent black background and confirmation dialog box instead of causing the screen to blank and then pop in. Ugh. I turned it off because of this alone... not because I don't like the protection it offers me. That's a BAD sign. Fix it quick!

 

Application compatibility I haven't had any real problems. There are a couple programs I can use such as our VPN software (CheckPoint SecureRemote) and today I went to install Mr. Sell's incredibly useful RegEx testing tool and it couldn't find .NET 1.1.422 even though it's obviously installed. My main programs are IE, VS Team Suite, JetBrains Omea Reader (errors out whenever you first launch it), WMP 11+Urge, Windows Live Messenger, SQL 2005 Development Edition + Express. All are running fine. I'm also running Office 2007 B2TR on here and loving it.

 

While I don't think it's quite ready for prime time yet, I don't think MS will have a problem hitting their release date. I'm more concerned about the third parties that have to get their driver support together. Even though they've had at least all of 2006 to figure it out that's one of the biggest complaints I ever hear about Vista. Heck I had to search the internet high and low to finally find drivers for my SATA controller. The version that came on the OEM CD will not work. I even contacted the manufacturer, Promise, and they told me they had no plans to support Vista. Then I contacted Alienware and they told me to go to Promise. *sigh*

 

As I finish writing this, I see that a new build has just been released to Beta testers. I think I'll stick with RC1 until RC2 hits. All I can hope is that, once Vista lands, Microsoft makes the right decision and just builds a better consumer experience on the platform for the next 5-10 years instead of trying to write an entirely new one again. Just focus on the consumer features 'cause this kernel should carry us just fine for a while.

posted Friday, September 22, 2006 9:43 PM | Comments | Filed Under [ WinFx/Vista Personal ]

The toolkit is certainly getting better with every release. The coolest thing added this time around has to be the support for declarative animation. Very WPF like... though no where near as nice because browsers just suck at this stuff. :P

I'm still waiting on the release of Sept. CTP for Atlas itself... hint hint. :P

posted Wednesday, September 20, 2006 2:47 AM | Comments |

I stumbled upon this earlier this year, but I didn't have the time to blog about it then. Since I was just doing some more tuning around the area of code where I applied this technique I figured I'd do a quick write up on it in the hopes that it may benefit someone else out there.

If you're doing a lot of dynamic type instantiation, as one would do in a Object Relational Mapping framework for example, and you are using Activator::CreateInstance you are suffering a severe penalty if you're instantiating more than 16 distinct types. Why? Because Activator::CreateInstance uses a cache internally that speeds up type instantiation, but it's only capable of caching for 16 types max. So how can you speed this up? Well Haibo Luo has some great information and statistics on the subject and also provides several approaches you can use to optimize the situation. Reflection+Emit results in the best overall performance, but Dynamic Methods in .NET 2.0 come in a very close second and are a little easier to deal with.

posted Thursday, September 14, 2006 10:29 PM | Comments | Filed Under [ .NET ]
Chris Anderson has made a couple of posts lately about his book, Essential WPF, nearing completion. Today he lets us know that the website for the book is now available. I'm looking forward to it as it's the first book from someone who was actually on the team who made WPF a reality. I'm hoping for lots of nitty gritty inside details that the other big names haven't supplied already (i.e. "Programming Windows Presentation Foundation" by Sells/Griffiths and "Applications = Code + Markup" by Petzold).
posted Thursday, September 14, 2006 4:56 PM | Comments | Filed Under [ WinFx/Vista ]
Head over to this post to get an understanding of the control naming issue at hand and then leave comments on how you'd like to see it done. I voted for no names by default, auto-naming if none-exists but one is needed (i.e. event handler generation) and suggested they put the name as the very first thing in the smart tag panel for all WPF controls.
posted Thursday, September 14, 2006 4:47 PM | Comments | Filed Under [ .NET WinFx/Vista ]

In my last post about providing custom context I described a way that allowed you to scope the context to the operation/method level. This time I'm going to show you a way that will allow you to scope your context to the service instance level.

As you may, or may not, know there are a few instancing modes for WCF services. Per-Call, Per-Session, Shareable and Single. Not only that, but someone could technically invent their own mode of instancing by implementing a custom IInstanceContextProvider. Anyway, despite which mode is used, you may want to tie your custom context to the instance of the service and clean up when the instance is closed. Here's what you'd need to do:

  1. Implement a custom IExtension<InstanceContext> which will contain the state of your custom context.
  2. Implement the IExtension<InstanceContext>::Attach and Detach like so:

    public void Attach(InstanceContext owner)
    {
        // ... implement your custom context setup code here ...

       
    // Hook up to the Closed event of the InstanceContext and call 
        // our Detach implementation so that we make sure to clean up
       
    owner.Closed += new EventHandler(delegate(object sender, EventArgs args)
        {
         
    this.Detach((InstanceContext)sender);
        });
    }

    public void Detach(InstanceContext owner)
    {
        // ... implement your custom context cleanup code here ...
    }
  3. Now we need a way to apply this extension, we need to create a custom attribute to apply some behavior.
  4. Implement IContractBehavior on this attribute and specifically implement IContractBehavior::ApplyDispatchBehavior (note: you can no-op all the other IContractBehavior methods) like so:

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceContextInitializers.Add(
    this);
    }
  5. Implement IInstanceContextInitializer and specifically implement IInstanceContextInitializer::Initialze to apply your custom extension from Step 1 like so:

    public void Initialize(InstanceContext instanceContext, Message message)
    {
        instanceContext.Extensions.Add(
    new MyCustomExtension());
    }

This approach will guarantee that your custom context lives as long as your InstanceContext no matter what mode is used. If you wanted to get fancy you could combine all the functionality of my last post and this post into one attribute and extension implementation with a new property on the attribute that allows you to control whether you want your behavior custom context to apply to the InstanceContext or the OperationContext.

As far as how you expose your custom context (if it even needs to be exposed at all), you can provide a static "Current" property of your own which looks for the state in the extension using OperationContext.Current.InstanceContext.Extensions.Find<MyCustomExtension>().

posted Thursday, September 14, 2006 2:11 PM | Comments | Filed Under [ .NET WinFx/Vista Web Services ]

I've been acting as the part time DBA around here since the company started. I know way more than I care to about things like backups, indexing, clustering, replication, etc. Now the company needs things like OLAP, Report Server and all sorts of other fun things that I just don't have the time for since my job as Chief Software Architect already keeps me busy enough. So, if you've got the skillz, are interested in working for one of the fastest growing technology companies out there and would love to be the lead DBA for the whole company, drop me a line and I'll let you know where to send your resume. Here's what we're looking for:

Primary Responsibilities:

  • Support multiple databases in development and production environments
  • Working with other teams in ongoing design, testing and support of business database needs
  • Troubleshoot day to day database and related application issues
  • Assist in security of databases to ensure accurate and appropriate use of resources and data
  • Perform scheduled tests to assess the database backup plan and the integrity of the backups
  • Create hardware specs for new server purchases by using trends and benchmarking evidence
  • Traditional database maintenance tasks: back ups, restores, indexing, replication/job monitoring, etc.

Required Skills:

  • Relational Database Design / Normalization
  • OLAP Design
  • Performance Analysis and Tuning
  • Database security
  • Data access (application level) security
  • Review of developer created SP’s, triggers and user defined functions
  • Excellent troubleshooting skills
  • Experience with Analysis Services
  • Experience with MSSQL Reporting Services (writing and maintaining reports)

Additional Skills desired:

  • Clustering Experience
  • Experience with SQL 2005 and Database mirroring
  • SQL Disaster recovery planning and execution
  • Experience with Disaster Recovery Planning and Testing
  • Knowledge of server hardware and capacity planning
  • Experience with .NET
  • Replication configuration, maintenance, and monitoring

Required background:

  • Five years or more experience as a MS SQL Server DBA
  • Extensive knowledge of MS SQL Server (2000 / 2005)
  • Proficient with Windows 2003 Server
  • Ability to work in a 24x7 support environment
  • Excellent verbal and written communication skills
  • Must be a self starter who is able to work independently as well as within a team
  • Experience in an eCommerce, medium business environment
posted Thursday, September 14, 2006 2:08 PM | Comments | Filed Under [ Personal ]

I just filed a bug over on Microsoft Connect about a problem in Expression Interactive Designer with the design time support for an ObjectDataProvider where ConstructorParameters are used. I noticed it a couple weeks ago and never got around to filing, but I just got back into working on the project where I was having the problem and noticed it's still broken even in the latest build (currently Sept. CTP). There's is a workaround that I included with the bug, but it's super annoying and the target audience of EID definitely wouldn't want to have to be doing it every time they went to build their apps.

Anyway, if you check out the bug make sure to express your concerns for it being fixed by voting.

posted Wednesday, September 13, 2006 10:34 PM | Comments | Filed Under [ .NET WinFx/Vista ]

Well, the news is out over on Scott Guthrie's weblog: Atlas has received it's offical name and true to Microsoft tradition it's no where near as cool as the code-name. :P There are technically three major facets to the product formally known as Atlas and Scott does a good job breaking it down, but I'll sum it up here again:

  1. Microsoft AJAX Library - this is the client side JavaScript library. You can use this whether your backend is Microsoft or not. It's the equivalent of the .NET framework for JavaScript and helps with everything from providing an OO approach for JavaScript to animation to a cross browser abstraction layer.
  2. ASP.NET 2.0 AJAX Extensions - this is the set of .NET components that you can use in your ASP.NET web applications that keep ASP.NET developers from having to worry about learning/touching any of the gobble-dee-gook of the Microsoft AJAX Library and still get all the great AJAX functionality. It also gives you UpdatePanel which is the absolute simplest way for you to give a richer AJAX experience without having to do a complete overhaul of your existing ASP.NET application. This separate package will eventually go away as the functionality is rolled into the ASP.NET runtime itself.
  3. ASP.NET AJAX Control Toolkit - this is the open source set of controls that are built on the former two technologies that provide a real world set of functionality. This is pretty important considering that the former two technologies reallllly don't provide that much in the way of functional controls. Rather they provide the foundation on which controls can be built. So, you'll need the ToolKit, or some third party like ComponentArt or Infragistics to provide you with a rich set of re-useable controls.

Also mentioned in Scott's post is the planned release date for 1.0 and some other hints of the great tool support we're supposed to get in VS "Orcas". As someone who has been working in this world of dynamic web applications since JavaScript was born, I'm finally getting a rich framework and support in my tools for working with it. Only took eleven years! :)

The one thing I must always rant about is the lack of a true HTML component model. The fact that we still have to have a separate set of code that injects and/or hooks up to some elements in the static DOM is pretty silly. There's been a proposed specification from Microsoft (maybe that's the problem) for an HTML component model floating around the W3C since 1998. Sure it needs work, but nobody's moved on it at all. If you're doing pure IE development you'd have to be an idiot not to use it. I wish I could do that. Also, Dean Edwards even put together a Mozilla XBL wrapper that implements it for Mozilla. Seems like it may never become a spec, but with more people doing cross-browser, client side development due to the buzz around AJAX, I bet a lot more people than myself are going to start groaning about it.

posted Tuesday, September 12, 2006 12:29 AM | Comments | Filed Under [ .NET Web Development ]

We officially rolled out a release of the "My" Mimeo.com web application this weekend. While we actually added some really great customer features, one of the biggest things in this release development wise was a full upgrade to use several features of ASP.NET 2.0 that were previously solved by a bunch of proprietary code that I wrote and the famous Wilson MasterPages. Here's a rundown of features we are now leveraging as opposed to relying on third party:

  • Master Pages -- we used Wilson MasterPages, they served us well :)
  • Validation Groups -- I had written a method called ValidateContainer which would walk the entire hierarchy of a container (like a Panel) that was passed in as a parameter, find each validator, execute it and return a boolean indicating if any of them had failed. 
  • ClientScriptManager -- we were of course using the Page level method that were the only thing available in .NET 1.1, since the methods were basically the same on ClientScriptManager this was pretty much a straight forward conversion. For most people the thing that ClientScriptManager provides is guarenteed order of output. Since we had already solved this problem by ensuring that we do things in the client in window::onload we didn't really gain anything from that. That said, it's nice to know that we can count on it now. Then again we're moving to Atlas and using the ScriptManager now, so we'll probably be off of the ClientScriptManager soon.
  • HtmlHead Control -- we already had a <head runat="server"> in our MasterPage, so what this did is prevent us from having to call FindControl to get it. Now we just use Page.Head and we're all set.
  • Resourcing -- This was the biggest change for us. I knew Microsoft was working on this for ASP.NET 2.0, so I implemented our proprietary version using the same approach so that conversion would be easy when we were finally ready to convert... and it was! We kept our .resx files in directories called LocalResource and GlobalResources (MS later changed to add the App_ prefix, but that was no problem). I had a set of methods on our base Page and Control classes that resolved the correct resource file name based on the ASPX or ASCX page type that was calling it. I loaded the resources via ResourceManagers which I kept in the cache.

    The biggest problem with this approach was that we still had no good way to declaratively get these resources assigned to the controls which needed them. So, not wanting to force these calls to be made in the code-behind, we did some perf testing and made the decision that the easiest approach would be to use databinding expressions (the <%# %> syntax) in the code in front and just call Page::DataBind() all the time. Now, this wasn't all that bad, but it did cause us problems with some of our real databinding scenarios. We don't use viewstate very much because of the amount of data that would be pushed out to the clients, so we pretty much always databind our controls anyway. However, we don't always want to databind all the controls on the screen because they may not even be visible! The new Expression API/syntax, which resourcing is based on, solves this problem because code is generated at compile time to retrieve the resource when the page is loaded. The expression API is definitely one of the coolest "lower level" features of ASP.NET 2.0.

    Long story short, we basically renamed our directories to have the "App_" prefix and did a giant find and replace on all the <%# base.GetResourceString("someControlId.SomeProperty") %> to now be <%$ Resources: someControlId.SomeProperty %> and everything worked like a charm. We then went back to the places where we were doing databinding "for real" and cleaned them up to make sure we only called DataBind when it was necessary and that our pages/custom controls only actually databound what they needed to.

The one thing we did not use in ASP.NET 2.0 and have stuck with a proprietary implementation of is Theming. I could be missing something, but I just don't think the themeing implementation is very good. It focuses too much on theming server controls and not enough on how content is actually delivered to the client. For example, as far as I know (please correct me if I'm wrong!) theming in ASP.NET 2.0 just takes all the CSS files in a Theme directory and pushes them out via <link> tags. Well... I have way too many CSS files for that to be scalable. Sure we have a base stylesheet that that makes sense for, but each one of our pages usually has some specific styles, not to mention our controls, each of those has a separate stylesheet of their own. So at any given time theres maybe five to ten diff. style sheets loaded for a given page1. If I put them all in a dir and they were included each time it would be horrible for the end user. That said, I did take advantage of the expression APIs that I talked about before to implement our custom approach to theming now because, just like I metioned about our proprietary resourcing approach, we were relying on databinding expressions for theme URL generation that was bad. With the new expression, we just did a find and replace of <%# base.ResolveThemedUrl("MyImage.gif") %> with <% ThemedUrl: MyImage.gif %>.

Performance wise, while I realize we were taking a hit with the call to Page::DataBind every time and now we're not, I am still extremely impressed with the overall performance improvements in ASP.NET 2.0. I haven't had enough time to gather an extensive set of performance data, but our average page execution times were roughly somewhere in the 300ms range on average. Now we're in the 150ms range! 50%, not entirely for free, but for the two weeks of upgrading and testing it took... that's a hell of an improvement!

So, needless to say, I'm extremely happy with ASP.NET 2.0 on all fronts. Feature wise they've added everything I had to write myself in 1.0. Productivity wise, the designer support for ASP.NET is vastly improved. We still don't use it entirely due to some problems it has with our custom controls, but we're looking to use it more. Performance wise, well... I'm still gathering more data on the live system since it just went up, but things are looking good with an average 50% boost for our application across the board. Granted, a lot of that had to do with the databinding fixes we made, but based on the testing I originally did when we decided on that approach it really didn't cost us more than 10-15%. So the other 35-40% is most certainly due to the other features and all around performance tuning they did on the CLR and ASP.NET 2.0 runtime. Kudos to Microsoft for such fantastic work!

1I realize people may be like "holy crap you're loading way too many files!!!". Well don't worry... I'm a stickler for performance on all fronts. ;) First, we use GZip compression so initial page loads aren't so bad, but there's definitely a noticeable delay when you first hit the site. Nothing you can do about that unless you stuff everyting into a single file, but then you're stuck trying to manage all that at development time. From that point on we rely on HTTP caching to do it's job. We send out all the standard HTTP cache headers for all our static content (CSS, Images, etc.) that tell the browser not to check again for back for a day. Then, when they eventually do have to check back, it's just a HEAD request that they have to pay the price for.

posted Monday, September 11, 2006 10:23 PM | Comments | Filed Under [ .NET Web Development ]

Nikhil has posted a control which aims to fix a common problem with most AJAX frameworks where users tend to lose the all too familiar history navigation paradigm that they are used to relying on.

What Nikhil has provided is an elegant solution based on the awesome UpdatePanel feature of Atlas. If you're doing AJAX with Atlas and want to solve this problem for your users, you definitely ought to check it out. Hopefully this control will become a part of the Atlas Toolkit Project.

posted Monday, September 11, 2006 6:00 PM | Comments | Filed Under [ Web Development ]

Sam Gentile has an absolutely awesome post on the importance of the role of the Software Architect even in Agile based development. As Chief Software Architect here at Mimeo, this obviously touches close to home. We've adopted Agile, but I still make sure that we budget time for architecture tasks for each iteration. As Sam points out, architecture isn't alwyas about Big Design Up Front. He also points out that some types of generic architecture tasks transcend projects and, thus, iterations (such as logging, exception handling, etc.). So what I do there is make sure we budget time for these specific tasks into each iteration that involves changes that might need those tasks fulfilled. It's like the bug fixing window where you always make sure to set aside a relative block of time for fixing bugs because you know you're going to need it... same thing should go for architecture.

posted Thursday, September 07, 2006 3:04 PM | Comments | Filed Under [ Personal ]

First off, I'd like to say that I absolutely love how extensible WCF is. So far there hasn't been anything I can't do. Unfortunately the documentation, examples and guidance around extensibility is still lacking a bit at this point. This is somewhat disturbing considering that RC1 just went out.

Now, on to what I really want to talk about here: providing custom context to your service implementations. We have an in house framework here at Mimeo, called our system framework, that provides some context much like System.Web's HttpContext or even System.ServiceModel's OperationContext. This in house framework exposes the current instance via a Current property (again, just like HttpContext::Current and OperationContext::Current). How and when the "current instance" is constructed is completely configurable via a factory method (provided via a delegate) that can be implemented per hosting environment. Built in factory method implementations include per-thread and per-appdomain, but in an environment like ASP.NET we actually maintain the lifetime in paralell with HttpContext::Current by storing it in the HttpContext::Items collection. Similarly we want the lifetime of this framework context to be tied to the call context of a WCF operation.

I took a couple diff. approaches while figuring out the best way to accomplish this in the world of WCF extensibility. Ultimately I fell into using a custom IServiceBehavior implementation, applied as an attribute, which extends the operations by hooking up a custom ICallContextInitializer. This approach allowed me to do some initialization right before a service operation is invoked and, when invocation completed, do some clean up. For more details on exactly what setup is required and what the order of execution is, check out this thread over on the WCF MSDN forums.

posted Tuesday, September 05, 2006 11:39 PM | Comments | Filed Under [ .NET WinFx/Vista Web Services ]

Just found out via Rob Relyea that .NET 3.0 RC1 is now available. Here's everyone's last chance to file show-stopper bugs! Also note that Rob points out that EID and Orcas aren't available yet for this build, but they should be available soon. So, if you need those tools, you might want to postpone your upgrade.

posted Friday, September 01, 2006 10:16 PM | Comments | Filed Under [ WinFx/Vista ]