Just Released: Mayando v1.2!#

Ok maybe it's not just released but still I'm happy to finally put the word out that you can now install Mayando v1.2 directly from the Microsoft Web Application Gallery!

Install Mayando using the Microsoft Web Platform Installer

Mayando is a full-featured photo blogging application that you can use to showcase your photos online.

Mayando-Logo-Medium

What's new in this release:

  • Dates on photos are now hyperlinks to other photos taken or published on the same date.
  • The Flickr photo provider no longer synchronizes machine tags (because they are not intended to be displayed).
  • You can now configure the photo provider to synchronize automatically at regular intervals (e.g. every 60 minutes).
  • You can also use a command-line client application (or if you're a developer, a client API) to remotely trigger a photo provider synchronization through the use of a new Service API.
  • You can now filter the event log by severity.
  • Mayando is now compatible with ASP.NET "medium trust" hosting providers.
  • You can now disable distributed transactions (in the AppSettings.config file) if your hosting provider does not allow them. Note that this can cause data loss and/or corruption so only change this if you accept the risks associated with disabling transactions.

If you want to see it running: check out the Mayando Demo Site or of course my own photo blog.

Wednesday, August 25, 2010 7:51:46 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

What Has Jelle Been Up To (a.k.a. The Last Post)#

Since it’s been almost two years since my last blog post, I figured I owed the remaining 3 subscribers of my blog a short update on what I have been up to...

#1 – Maya

There have indeed been a couple of interesting things going on, and first and foremost, that would include the birth of our amazingly beautiful and unbelievably cute daughter Maya in June last year :-)

Prinses  Koekjestijd Verjaardagskroon

She just turned one year old this week, so time flies indeed! If you would be interested in seeing some more pictures, then I’m sure you can figure out where her own website would be located if you studied the incredibly complicated naming pattern I used to locate my own website :-)

#2 - Mayando

Because Project #1 called for a way to keep the family up to date and to regularly show off exactly how cute Maya is, and (almost equally importantly) because I was looking for an excuse to learn ASP.NET MVC, I decided to write a photo blogging web application. “What, another photo gallery site”, you might ask? Eh, yeah, exactly. But in my defense: I looked hard at the existing ones and couldn’t find one that covered my requirements so this is one I built to fit my needs :-)

Nonetheless, I didn’t just want to build a one-off “baby web site for Maya”, but really a generic application that I could also use later on use as the engine for my own photo blog – and that you, dear reader, might also want to use if you want to publish a collection of photos in a nice and user-friendly way. (For example, I have an architect friend who is interested in using it as a portfolio site for the houses he designed.)

And so, Mayando was born: a full-featured photo blogging application that you can use to showcase your photos online.

Mayando-Logo-Medium

Now I did not want to reinvent solutions to the problem of globally storing and serving images on the web, so I figured that I should only build a rich front-end on top of existing photo storage services such as Flickr. So I built a provider model where the URL’s of the photos and their details (and comments) just get “sucked in” from a photo sharing site and you can work with them from your own website. So basically, the photos get pulled in from a service such as Flickr and then displayed through Mayando, using a lot of navigation possibilities (by creating static pages and dynamic galleries, by browsing through photos, comments, tags, dates, ...).

It also allows visitors to post new comments and obviously I needed to handle comment spam so again I implemented a provider model for anti-spam services (such as Mollom).

And finally, the whole thing had to be easily customizable so I made sure to allow different themes for the photo blog’s look and feel, with customization options ranging from simple (e.g. simply changing the CSS stylesheet) to advanced (completely changing the entire site layout and/or individual pages). Thankfully, by now I know that the ASP.NET MVC framework is so flexible it easily let me do all this with surprisingly little effort. Anyway, I won’t go into the many details – if you’re interested in how it works: it’s open source so feel free to look at the Mayando source code and let me know if you want to contribute!

If you just want to see it running: check out the Mayando Demo Site or of course my own photo blog :-)

#3 – Flickr Schedulr v1.4 & v2.0

Because Project #1 and Project #2 meant I would be using Flickr more, I figured it was also time to give my Flickr Schedulr application an update to incorporate feedback from a number of users.

In case you’re wondering what it is: Flickr Schedulr is a Windows desktop application that automatically uploads pictures to Flickr based on a schedule (e.g. to post a new picture every day at a certain time). It allows you to create a queue of pictures to be uploaded, along with their titles, descriptions, tags, and the photosets and groups into which they should end up.

Schedulr-Logo-Small

I published v1.4 last January; new features include the possibility to upload multiple pictures at a time in batch, better handling of multiple selected files and overall UI improvements.

I’ve also been working really hard on v2.0 which is a complete rewrite of the application in Windows Presentation Foundation (WPF), and as such looks and feels so much nicer in many ways than the previous version. It will also have a few new features of course. I’m still polishing some things but you can expect to see a release in the next few weeks.

Since I’ve been very happy with CodePlex for my other projects, I decided to move the source code and work items there and lo and behold: here is the new Flickr Schedulr homepage on CodePlex!

#4 – Proxy Monitor

Last October, the trend continued: another release around a year after the last one. This time, I got the help from David Huntley, who was kind enough to finally get something off my list I’ve been planning to do for a while now: properly setting the proxy via the Win32 API’s instead of just writing to the registry. This more robust way of setting the proxy came for free with the new feature he implemented, which is support for multiple connections. This allows you to specify proxy servers for other connections than the default LAN (such as dial-up or VPN connections).

To make it easier to work together, I decided to move this project to CodePlex as well. So for all information, downloads, forums, etc. go to the new Proxy Monitor homepage at CodePlex!

#5 – The NOT Part

So after a small list of things that I have been up to the last two years or so, it’s quite clear what I have not been up to: blogging. And that’s probably going to stay that way. I either have too little to say (which is increasingly the case), or too much (which would take too much time to write down). So honestly, I expect this would be the last entry on my blog for quite a while – if not eternity.

In case it becomes the latter: thanks for having followed my random thoughts for the last 7 years, and if you want to keep up with what I’m doing on the technical side of life, follow my projects on CodePlex:

If you want to keep up with the non-technical side, check out my photography site - <plug>based on Mayando of course, and updated with the help of Flickr Schedulr</plug> :-)

Blog | General | Photography | Programming | .NET | ASP.NET | WPF | Websites | Windows
Thursday, June 10, 2010 1:03:08 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

IIS virtual directory names and mapped file extensions#

Just a quick note to mention a little quirk in Internet Information Services (IIS) I discovered recently: when you have a virtual directory name that ends in a registered file extension, you'll get an HTTP 404 error when browsing to that directory.

We were using http://localhost/MyCompany.MyProject.Svc/MyService.asmx as our web service endpoint, but that kept giving us HTTP 404's. At first, we thought it had to do with the dots in the name (causing us to change our guidelines and drop part of our naming consistency) but I later found out it has to do with the .svc file extension being mapped to the ASP.NET isapi dll. So even though it's clearly a directory name and not a file, we still got the 404.

So we changed our guidelines (once more) to MyCompany.MyProject.Svc.WebServices and all was fine again...

Blog | Programming | .NET | ASP.NET | Quirks
Sunday, June 25, 2006 10:45:29 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Visual Studio 2005 Web Application Projects Released!#

I don't know about you, but I've never been very fond of the new Web Project System in ASP.NET 2.0. I'm sure it has its advantages for some types of users but I've definitely had more than my share of problems with it. Specifically the way that it sometimes (and randomly) starts checking in binaries in Source Control has shortened my life with at least 4 months. Furthermore, having each page compile into its own assembly (by default anyway) and therefore not having a nice place to put assembly-level attributes or define strong naming that work on the entire website has surprised me (in a negative way, that is). What I don't get is that Microsoft had abandoned a familiar and working concept (the Web Application model used in the previous versions of Visual Studio) and replaced it entirely without supporting the old way of working. To me this has always been a major breaking change, and a cause of much frustration.

Well, the pain has now officially ended: the Visual Studio 2005 Web Application Projects has been released, meaning that the old model is back with a vengeance. With a free download from Microsoft, you can get your familiar working environment back in Visual Studio 2005, but with lots and lots of improvements over the previous versions of course (not even mentioning the fact that it's now ASP.NET 2.0 with all its goodness around it).

Some highlights:

  • A project file (which I don't consider a feature, more a bugfix over the previous model)! This fixes the problems with the references getting checked in, and lots of other things.
  • Because of the project file, you also have pre- and post-build events again (the new Web Project System doesn't support them).
  • You can create working Web Setup projects again, containing the content and primary output of the project. With the new Web Project System, you have to download and install a separate update (the Visual Studio 2005 Web Deployment Projects).
  • It builds one assembly by default. This fixes the problem with the assembly-level attributes and strong naming.
  • The Global.asax file isn't ugly inline script anymore but a proper class in a code-behind file. The "Application_Start" and similar methods are still "magic" though, discovered through reflection I assume, in stead of properly overriding them from the base class or something.
  • No more Frontpage Extensions required. Be gone, _vti_*!
  • Built-in Development Web Server. Be gone, IIS! Well, not for enterprise scenarios of course, but it's still a very nice feature :-)
  • MSBuild support.
  • Better web publishing options.
  • ...

I've immediately installed and tried it and it works great! One specific detail that I think is a very nice feature (just to show that it's not a quick fix of the old model to run on Visual Studio 2005 but a real full-blown upgrade) is the "Create Virtual Directory" button in the project settings, which allows you to setup a virtual directory in IIS without having to go to the IIS console:

Great!

Anyway, this add-on has made me very happy with ASP.NET 2.0 again. It's the little things that make the difference, but the big things in this case made my day :-)

Blog | Programming | .NET | ASP.NET | VS.NET
Thursday, May 11, 2006 8:30:11 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Faking a current HttpContext#

I was recently looking for a way to unit test a piece of security code that would retrieve the User principal from the current HttpContext in an ASP.NET scenario. Now it was just a plain unit test, not a web test, so I didn't actually have an HttpContext. But how hard could it be to cook one up, right?

So I first tried to set the HttpContext.Current property, but IntelliSense popped up to say: "Gets the HttpContext object for the current HTTP request". So I figure it's a read-only property (because the phrase starts with "Gets...", where read-write properties typically start with "Gets or sets...") and I can't do it directly.

Then I found a post by Steve Maine that seemed to allow setting the current HttpContext by injecting it into the messaging CallContext of .NET Remoting. While that looks like a bit of black magic, I'm never too shy to throw in some snake blood and salamander eyes if it makes my code compile so I tried that, but it didn't seem to work right away. It did, however, provide me with a good way of creating a dummy HttpContext in the first place, which I also needed to do:

SimpleWorkerRequest request = new SimpleWorkerRequest("/dummy", @"c:\inetpub\wwwroot\dummy", "dummy.html", null, new StringWriter());
HttpContext context = new HttpContext(request);

So we just create a dummy worker request that the HttpContext requires and we pass it into the constructor.

Because the black magic wasn't working for me, I looked at the HttpContext class in my favorite .NET tool of all time, and quickly realized that the property was settable anyway [1]. So I guess that salamander had a lucky day:

HttpContext.Current = context;

And we're done. A valid current HttpContext for use in unit tests.

[1] Side comment: property documentation that doesn't follow the "Gets..." versus "Gets or sets..." pattern is pretty frustrating. It could have saved me quite some time if the documentation would just say "Gets or sets the HttpContext object for the current HTTP request"...

Blog | Programming | .NET | ASP.NET | Samples
Wednesday, April 05, 2006 10:07:31 AM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

ASP.NET 2.0 References#

I've been using the Release Candidate of Visual Studio 2005 lately, and I'm very pleased with the overall look and feel of the application. There are still some issues left to work out (I get the occasional crash and burn), so I hope they'll all be gone by the time they RTM in the week of November 7th...

One of the things I really wished they would have fixed, though, is the way references are handled in ASP.NET 2.0 websites or WebService projects. This is what I had to say about references in June 2004, and it still holds true:

Although certainly not always possible, the ultimate solution to problems with references has always been using Project References. So that's what I'm doing now, but in ASP.NET they tend to switch from project references to fixed binary references that don't get updated anymore. And you wonder why you get runtime errors... So you need to check those references regularly and reset them to project references. Joy! What's even funnier is that an ASP.NET site doesn't have a project file anymore, which would be fine if there was nothing to remember for an ASP.NET project. But what about these references? I'm sorry to have noticed that, but they're stored in the solution file. Bad, bad, bad... If you have multiple solutions with the same ASP.NET project in them, it would depend on the solution file which kind of references the project would use. If you really need project-settings, revive the project file guys and recall the "no project file needed"-hype. What's one file extra going to do anyway?

Apart from the project references randomly becoming binary references (I've seen it happen again in the RC!) I still think it's an even bigger problem that project properties are put into the solution file. If you want proof, this is a part of a solution file that contains a WebService project:

Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = http://localhost/TestWebService/,
"http://localhost/TestWebService", "{F7389224-931A-4652-A0E2-3A932D1B40C6}"
 ProjectSection(WebsiteProperties) = preProject
  ProjectReferences = "{BC53180F-394F-4F31-A61E-BFBC4DBF9B32}|BusinessLayer.dll;"
  Debug.AspNetCompiler.VirtualPath = "/TestWebService"
  Debug.AspNetCompiler.PhysicalPath = "..\..\..\..\POC\TestWebService\"
  Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\TestWebService\"
  Debug.AspNetCompiler.Updateable = "true"
  Debug.AspNetCompiler.ForceOverwrite = "true"
  Debug.AspNetCompiler.FixedNames = "false"
  Debug.AspNetCompiler.Debug = "True"
  Release.AspNetCompiler.VirtualPath = "/TestWebService"
  Release.AspNetCompiler.PhysicalPath = "..\..\..\..\POC\TestWebService\"
  Release.AspNetCompiler.TargetPath = "PrecompiledWeb\TestWebService\"
  Release.AspNetCompiler.Updateable = "true"
  Release.AspNetCompiler.ForceOverwrite = "true"
  Release.AspNetCompiler.FixedNames = "false"
  Release.AspNetCompiler.Debug = "False"
  SlnRelativePath = "..\..\..\..\POC\TestWebService\"
 EndProjectSection
EndProject

The rest of the settings are also project-specific (hence the ProjectSection) so I think it's all unacceptable. But I guess it's too late to change any of this...?

Update: I did some thinking and some of this might actually make sense... As the line in the solution file above actually states, it's a Project Reference. Since project references refer to other projects within the same solution file by definition, this is actually quite logical. I tried to do the same thing with a non-project reference (i.e. a binary reference) and it's not stored in the solution file. But before you start cheering, be aware that the reference isn't stored anywhere at all. The assembly is just copied over to the website and you'll have to update it manually if the reference changed. Not too brilliant either... The fact that project references tend to switch to binary references might have something to do with adding the website to a new solution which doesn't contain the referenced project, but I'm not so sure the reason is that simple.

Blog | Programming | .NET | ASP.NET | VS.NET | Whidbey
Thursday, October 13, 2005 8:23:50 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

When ASP.NET 2.0 throws 404's at you...#

If you're getting curious HTTP 404 errors in your ASP.NET 2.0 application, be sure to check for a zero-length "magic file" called app_offline.htm and delete that. If this file is present in your web site, then the entire application will be considered offline by the ASP.NET runtime.

While certainly useful as such to quickly disable an entire site, it's not so great that the "magic file" can also "magically appear", especially since there's no indication as to why you're getting the 404, so you can spend quite some time chasing bugs that aren't there. Fortunately, post-beta 2 builds will be providing a proper explanation.

The reason it can appear by itself is that it's used to "take the application offline" when copying a web site. If this operation crashes somewhere in the middle for some reason, the file doesn't get deleted (while we wait for a transactional filesystem anyway) and bite you in your, errr, isapi filter.

Blog | Programming | .NET | ASP.NET | Whidbey
Monday, May 23, 2005 11:10:53 PM (Romance Standard Time, UTC+01:00) #    Comments [4]  | 

 

More on .NET Remoting and customErrors#

Yesterday, David Boschmans blogged about a problem with .NET Remoting and customErrors we noticed at the customer's site earlier this week. It basically boils down to the fact that the customErrors tag in the <system.web> part of the web.config file is being read by the remoting infrastructure (if you're hosting in IIS anyway) to determine whether or not to flow remote exceptions to the caller. I find this very bizarre, as does David. Ingo Rammer left a little note in the comments about the way Indigo will handle this situation, and I'd simply like to add my opinion to the matter here.

I think some confusion lies in the fact that .NET Remoting was designed to be as transparent as possible. I think of it this way: exceptions are part of the contract of a class; .NET Remoting is "only" a means to provide location transparency, so the remoting stack should always ensure that the exception is transferred to the client. There shouldn't even be a setting that influences this, as far as I'm concerned. Especially if that setting lives in the <system.web> section, since I expect that section to only affect ASP.NET sites. Up until now, that wasn't a section I would typically associate with the remoting stack.

The same configuration setting does exist in the <system.runtime.remoting> section as well though, where I can somewhat accept its existance, but certainly not its default value ("remoteOnly") since that can effectively change the behaviour if you scale to multiple servers as David states. That means that if you host your client (e.g. a web app) and server (remoting backend) on the same physical machine, everything will appear to work correctly since the exceptions are transferred locally. If you decide to scale out and move your remoting layer to another server, you'll see an unexpected RemotingException where your own application exception used to be and your app won't work as it used to do (if you're using structured exception handling anyway).

Now, concerning Ingo's comment... Indigo is different. I would actually expect Indigo to have a means to specify the way server-side exception information is exposed, because Indigo was never meant to be transparent - quite the opposite actually: "Boundaries Are Explicit", remember. And with Indigo, you don't typically "trust" the client, whereas with remoting you tend to have a lot more control over the caller so you would allow more trust about the exceptions being transferred. Anyway, I'm looking forward to seeing the new Indigo model in action, and how the [FaultContract] will interact with the various .NET and non-Microsoft clients out there...

Blog | Programming | .NET | ASP.NET | Quirks | Samples | Indigo
Thursday, March 10, 2005 9:24:55 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

ASP.NET Comments#

I've just expressed my love for comments (which generated some interesting discussion as well) and a while ago I've been quite active in ASP.NET 2.0; so let me take the opportunity to raise a personal concern of mine when combining the two.

Remember that one goal of ASP.NET 2.0 was to reduce the code needed for typical scenarios by 70%. That's a lot and I don't have any metrics yet, but they've certainly managed to eliminate a lot of keypresses that I hope I will never need to break my fingers on again. They've also overhauled the databinding system (just look at the ObjectDataSource) to reduce code and you can even use the Web.config file to declaratively create a strongly-typed Profile, or couple all your pages to a common basepage to include boilerplate code.

So great! With all this, ASPX has definitely become a double-JITted programming language of its own - as Early & Adopter so beautifully put it during the last PDC.

The only problem I have with it, is that when hiding more and more code behind markup, where do we document what we're doing? We don't. Do you? Thought so... So come on, be nice: comment your markup when it gets anywhere near semi-complex.

And don't just write <!-- html comments --> either, but be sure to use the <%-- server-side comments --%> in ASP.NET, since they don't get sent out to the browser (which would increase your final page size and possibly even leak information about your business logic to the browser for everyone to see).

Still, this doesn't do anything to promote itself as metadata (that can be used by tools) like the well-known XML comments, so it's still fairly useless apart from serving as in-line documentation. But then again, if you're writing structured code that needs structured comments, you should really put it in code anyway, and not in markup.

Blog | Programming | .NET | ASP.NET | Whidbey
Monday, January 24, 2005 8:04:35 PM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

Upgraded to dasBlog 1.7!#

I couldn't wait to upgrade to the new 1.7 version of dasBlog Community Edition (as it's called nowadays) because of all the great new features: far better performance, anti-spam measures, drafts (finally!), and lots more. Three cheers to Omar Shahine, Scott Hanselman, and everybody else who dedicated some precious time to it!

Unfortunately, there seems to be a small bug in the drafts functionality, since posts that aren't marked as Public (i.e. drafts) still show up in the RSS feed. Whoops ;-) I'll be keeping an eye on the bug I submitted to the SourceForge tracker because I really want to start using drafts... Update: My eyes must be deceiving me, the draft version of this post worked perfectly without showing up in the RSS feed... It did fail on my test machine though... Anyway, I'm sure it was my fault then.

If you're planning on upgrading too, you'll notice that you have to run an upgrade tool against your contents directory. The fix for the "Comments may disappear when moving content across GMT timezone boundary" bug I briefly mentioned before and submitted to Omar Shahine may have something to do with that since I believe that triggered the filename changes, sorry about that ;-)

Still, I had a little problem upgrading my content, and I believe it's related to that bug. I pulled the content from my server (which is on time zone GMT-7) to my machine (GMT+2) and ran the upgrade tool. Everything seemed fine on my test machine, but I noticed that the comments on some (what appeared to be) random posts had disappeared. I dug a little deeper and noticed these posts were submitted quite early in the night so I suspected a time zone issue again. I reflectored (uhm, yes, that's a word) the upgrader exe to see what it was doing and I noticed it was using the local time zone for some date-time calculations. So on a hunch I switched my local timezone to the one of my server and everything worked just fine. Whew :-)

So here's a word of advice: if you upgrade your content directory, be sure to temporarily set your local machine to the same time zone as the server the blog will be running on!

Blog | General | Programming | .NET | ASP.NET
Sunday, January 23, 2005 4:25:38 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Fixing the IExtenderProvider in ASP.NET#

Very, very cool: Fixing the IExtenderProvider in Visual Studio's ASP.NET designer.

The fact that Extenders Providers don't work in ASP.NET has been bothering me for a very long time, and this article shows a way how to fix that once and for all. And all it needs is an extra attribute on your IExtenderProvider class. Sweet!

In case you're wondering: extenders aren't supported in ASP.NET because the team didn't really see a scenario for it. Mainly because they're mostly used to hook into control events and that just doesn't really happen as much on ASP.NET like in WinForms.

But you could still do useful things with it (translation and data binding jump to mind) so I was really bummed about that. I talked to Scott Guthrie about it on the PDC03, explained a few reasons why I'd use them and he agreed I had a good point but it was unlikely that they would actually implement it.

Blog | Programming | .NET | ASP.NET | VS.NET | PDC03
Tuesday, January 11, 2005 12:58:40 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Avoiding WebSite_1 when pulling an ASP.NET Site from SourceSafe#

Today was frustration day. I got all cooked up a few times and got mad at

  • my next-door neighbour (for playing loud music at 2:30 AM)
  • some printer (for paperjamming 66% of the time)
  • Visio (for generally sucking; well either that or I'm just too much of an idiot to understand how to properly draw a UML sequence diagram in there)
  • aspnet_wp (for not finding some system dll's in its own runtime cache until I nuke the process)
  • SourceSafe (see Visio; and for the reason below)
  • Visual Studio .NET 2003 (for pestering me with the "Object type cannot be converted to target Type" CopyLocal bug again)

Luckily, I also picked up what could be the trick to avoid an all-too-common SourceSafe mess.

If you're getting a new solution from SourceSafe that includes an ASP.NET Web Site or Web Service you probably encountered this as well: chances are that you don't keep your sources under IIS's wwwroot but under your local SourceSafe working directory and then create VRoots (Virtual Roots) in IIS to the proper directory. If you did that before you opened the solution in Visual Studio .NET for the first time, you're doomed with a feeble attempt of SourceSafe to create the web for you, again. It notices that there's already a web with that name, creates a new one with the same name and a "_1" suffix and then complains that it can't bind to the proper web site. Here's a trick that worked for us:

  • Create the directory but keep it empty (don't get a local copy out of SourceSafe)
  • Create the VRoot to that directory with the proper name
  • Make sure Anonymous Access is enabled on the VRoot
  • Open the solution in Visual Studio .NET, SourceSafe should be getting the files in the right directory now
  • Disable Anonymous Access on the VRoot if required

If you have other or better solutions, don't hold back and share them :-) I've seen a trick via David to avoid some other problems by making SourceSafe treat a web project as a class library, but I think the friction is pretty high on that one.

And I'll still be holding my breath for the source control system included with Visual Studio 2005 Team System of course. That, and the fact that Visual Studio .NET 2005 doesn't need IIS anymore, or creates web sites under wwwroot by default. Shoosh, now be gone SourceSafe.

Monday, January 10, 2005 10:09:55 PM (Romance Standard Time, UTC+01:00) #    Comments [4]  | 

 

SmartPart for SharePoint v1.0 released#

Jan Tielens - SharePoint Connoisseur Extraordinaire - just released v1.0 of his SmartPart for SharePoint.

"SmartPart: A SharePoint Webpart that can host any ASP.NET user control. Create your webparts by using the VS.NET designer instead of coding everything by hand!"

If you're into Webpart development, you're going to wanna kiss him ;-) Way cool!

Wednesday, November 24, 2004 12:40:07 AM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

TechNet evening session on InfoPath & SharePoint#

As it happens, I'll be co-hosting a TechNet Evening session on "Customizing Collaborative Solutions with InfoPath 2003 SP1 and Windows SharePoint Services" with Yves Kerwyn on October 27. Woohoo, that should be fun :-) So if you're interested in InfoPath, XML, Web Services and SharePoint, be sure to register for the session and come say hi!

There should be lots of demos and I fully intend to make sure Murphy's Law is upheld... So there's a big chance you get to point and laugh at me in public - don't miss this unique opportunity!

Sunday, October 10, 2004 3:51:45 PM (Romance Standard Time, UTC+01:00) #    Comments [3]  | 

 

Update to my dasBlog hack for showing public referrers and search engine queries#

A while ago, I hacked dasBlog so I could browse my public referrers. Afterwards, I moved the google and feedster queries to a separate list so they don't clutter the 'real' referrers. Now, I made the code more generic so I could easily add some more search engines like Altavista, Yahoo! Search and MSN Search. So I figured I'd post the code here since I like to think it's pretty cool to have :-) So if you're running dasBlog, just copy the files in the zipfile into your root blog folder and enjoy your new PublicReferrers page!

PublicReferrersAndSearchQueries.zip (5,98 KB)
Blog | General | Programming | .NET | ASP.NET
Sunday, September 26, 2004 11:10:20 PM (Romance Standard Time, UTC+01:00) #    Comments [3]  | 

 

The ASP.NET 2.0 Profile#

Tough luck. I had been busy (well, "busy", as I mentioned: the summer has been a bit of an idle time tech-wise) writing an article on the all-new Profile concept in ASP.NET 2.0, but I just noticed that I've been pre-empted by MSDN where the article "Storing User Information with ASP.NET 2.0 Profiles" just went online. It's a great read though, and it covers pretty much everything I had to say about it (and more of course) except the part about Profile migration on which I'll add my 2 cents now.

Let me just briefly summarize the Profile, which is one of the cornerstones of the new Personalization framework: the Profile is a "personal, type-safe, persistent data store" for each of your website's users. You can use it to remember settings (like language or culture, UI theme, ...), data (favorite color, shopping cart items, ...) or anything else you can think of really. Type-safety is ensured because it is an actual object with typed properties, and the data is automatically persisted into a data store of your choice [1]. Furthermore, you can configure the Profile to work for users that aren't known or logged in yet. When the user decides he likes your site so much that he wants to create an account, you can migrate his anonymous profile very easily in Global.asax by implementing a method like the following one:

Sub Profile_MigrateAnonymous(ByVal s As Object, ByVal e As ProfileMigrateEventArgs)
    
    ' Fish up the profile belonging to the anonymous user that just logged in.
    Dim anonProfile As HttpProfile = Profile.GetProfile(e.AnonymousId)
    
    ' Move the settings over to the authenticated user's profile.
    Profile.FavoriteColor = anonProfile.FavoriteColor

End Sub

So far for the article's example. There's a little issue with this approach though. Imagine a user who already created an account and is now just browsing to your site. He hasn't logged in yet so he gets the default settings for an anonymous user. Then he logs in, thereby migrating and overwriting his own settings (which were persisted from last time) with the default ones. Too bad, you just lost your shopping cart.

Unfortunately, there's currently no way of checking if the profile being migrated to is new - i.e. if the user already had an account and is now just logging in, or if he just created an account. Only in the latter case will you want to migrate the profile, so that's pretty tricky. Hence the following feature suggestion: provide a ProfileMigrateEventArgs.IsProfileNew flag so we can check if we actually need to migrate the profile.

Another option would be to check on the default values of the profile [2]. But what if the user changed one of the properties before he logged in? You would wrongfully not migrate his settings. Not good.

So until there's a better way of doing this, I'd suggest putting a flag on the Profile itself that says it's a new profile and flip it over once you've migrated the anonymous profile, e.g.:

<profile>
 <properties>
  <add name="FavoriteColor" allowAnonymous="true" defaultValue="Red" />
  <add name="HasMigrated" type="System.Boolean" defaultValue="false" />
 </properties>
</profile>

Sub Profile_MigrateAnonymous(ByVal s As Object, ByVal e As ProfileMigrateEventArgs)
    
    ' Migrate the profile preferences only if the user is new.
    If Not Profile.HasMigrated Then
    
        ' Fish up the profile belonging to the anonymous user that just logged in.
        Dim anonProfile As HttpProfile = Profile.GetProfile(e.AnonymousId)
    
        ' Move the settings over to the authenticated user's profile.
        Profile.FavoriteColor = anonProfile.FavoriteColor
        
        ' Indicate that migration has been done.
        Profile.HasMigrated = True

    End If
    
End Sub

One last remark about the Profile: a VaryByProfileProperty option for output caching would make sense. Imagine you have a multilingual website and you keep the user's Culture setting in the Profile. Then you could easily configure your page to be cached for all users that share the same culture as such:

<%@ OutputCache Duration="60" VaryByProfileProperty="Culture"  %>

It's not really shocking but it's just a bit easier than using VaryByCustom and returning the Culture manually...

[1] The Profile derives from the System.Configuration.SettingsBase, which is the new configuration system available in .NET 2.0. It's also used in Windows Forms so you can have type-safe access to application- and usersettings in this environment as well. Goodness!

[2] If you're working in VB.NET, you might wonder how you can access the default value of a Profile property. It's not listed in IntelliSense (I'm still puzzled why not because it does show up if you use C#) but there's a Properties collection you can use to access a certain Profile property and get the default value out of it as follows:

Dim defaultValue As Object = Profile.Properties("FavoriteColor").DefaultValue

Blog | Programming | .NET | ASP.NET | WeFly247 | Whidbey | Samples
Tuesday, August 24, 2004 6:57:30 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Brandnew Look: BlogXP Theme#

If you're reading this through an aggregator: there should be no difference whatsoever for you, carry on ;-)

If you've actually fired up that trusted ol' webbrowser (have a drink to wash away the dust), you might have noticed that I finally got around creating a new look for my site/blog. I'd been planning on doing that for a while now, especially because the sidebar was growing too large and I wanted the individual panels to be collapsible. Note that I can collapse some panels by default now, but I just can't seem to decide which ones ;-)

So I built sort of a "webpart" look-and-feel into dasBlog (without the flashy "moving" webparts though, and unfortunately it also doesn't "remember" your settings - maybe later). I snatched a few images and ideas, drew or enhanced some myself, scripted the collapsing and then spent far too much time playing with the css to make the whole thing look good. It still has a few minor quirks I ought to work out (mostly in the admin area) but all in all, I'd say it looks pretty nice. It looks best in IE (due to the gradient filters at the top) but it also seems to work great in Mozilla's new Firefox 0.9.

So how do you like it?

I've named the theme BlogXP, here's a zip file if you want to use it yourself (go wild):

blogxp.zip (14,21 KB)
Thursday, June 17, 2004 8:26:50 AM (Romance Standard Time, UTC+01:00) #    Comments [6]  | 

 

Rotating an image around its center in .NET#

As you can see on the new screenshots for the WeFly247.NET Passenger website, there's a dynamic flightmap image displaying the route the plane has already traveled and where the plane is at now.

As I was replacing some hard-coded info (like the image to use for the map, the start- and endpoints of the flight on the map, ...), I figured I was also going to need to rotate the plane dynamically so that it would follow the path (I wouldn't feel too comfortable if I was looking at a flightmap where my plane seemed to fly sideways). Before that, I had just rotated the static image itself, but if the flight path can change, so can the rotation.

There is an Image.RotateFlip method but that only allows rotating over 90/180/270 degrees. I also looked at some matrix transformations on a Region object using Matrix.Rotate, but that seemed a little too hard to get working. Furthermore, I wanted to rotate the plane around its center (not around the upper left corner as most rotations do) so I sat down and thought deeply about rotation equations (so my math teacher was right, it does come in handy sometimes!), decided I forgot all about it (sorry teach), and looked it up again.

After rotating a point (x, y) around the origin over an angle a, the new coordinates (x', y') are:

x' = x cos(a) + y sin(a)
y' = -x sin(a) + y cos(a)

Now you can use a Graphics.DrawImage method overload to draw the image in a given parallelogram extrapolated from an array of three points. That would do just fine to rotate the image if I could calculate the three points, which I could using the simple formulas above. So my final implementation to draw a rotated image onto a graphics object became (beware: VB.NET snippet coming up ;-) ):

' Draws an image onto the given graphics object. The image is rotated by a specified angle
' (in radians) around its center and then drawn at the given center point.
Private Sub DrawImageRotatedAroundCenter(ByVal g As Graphics, _
    ByVal center As Point, ByVal img As Image, ByVal angle As Double)

    ' Think of the image as a rectangle that needs to be drawn rotated.
    ' Rotate the coordinates of the rectangle's corners.
    Dim upperLeft As Point = RotatePoint(New Point(-img.Width / 2, img.Height / 2), angle)
    Dim upperRight As Point = RotatePoint(New Point(img.Width / 2, img.Height / 2), angle)
    Dim lowerLeft As Point = RotatePoint(New Point(-img.Width / 2, -img.Height / 2), angle)

    ' Create the points array by offsetting the coordinates with the center.
    Dim points() As Point = {upperLeft + center, upperRight + center, lowerLeft + center}
    
    ' Draw the rotated image.
    g.DrawImage(img, points)

End Sub

' Rotates a point around the origin by the specified angle (in radians).
' Rotation adheres to the following rules for the new coordinates:
' x' = x cos(a) + y sin(a)
' y' = -x sin(a) + y cos(a)
Private Function RotatePoint(ByVal p As Point, ByVal angle As Double) As Point

    Dim x As Integer = p.X * Math.Cos(angle) + p.Y * Math.Sin(angle)
    Dim y As Integer = -p.X * Math.Sin(angle) + p.Y * Math.Cos(angle)

    Return New Point(x, y)

End Function

Wednesday, May 26, 2004 9:53:56 AM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Last month on WeFly247.NET#

It's been quite a while since the last progress report on WeFly247.NET, but we've been very busy getting a more or less stable build out for the rest of the team to review - luckily that also means a lot of work has been done in the mean time :-)

Last time, I left off with a "standalone" Passenger web site that looked like it was designed by a developer (well, it was :-) ), but since then I've updated the look and feel to match the great designs from Elevator Digital and connected it all to the business tier. The website is pretty much done right now, it's all talking to the backend over Web Services through smart Agents that handle security and custom authorization Soap headers.

The home page:

The "panels" (flight info, destination info, crew info, ...) on the homepage are Web Parts so you can customize the whole lot and look only at what you would want to see during your flight. The Flight Map on the homepage is a dynamic image (easy as pie with the new .asix handler and the DynamicImage control in ASP.NET 2.0) which displays the the route the plane has already traveled and where the plane is at now.

There's also an InfoPath form that allows you to fill in your Customs & Immigration information; it also pulls and pushes data from and to the backend through Web Services (but since InfoPath doesn't talk Soap headers yet, it's not automatically secured yet).

The Duty Free Shop:

So with that part pretty much done, I've started working on the Maintenance application, which is a Smart Client application for the pilots that can be used on a Tablet PC. They use it to go over a checklist before takeoff (there are no gas stations in mid-air so better check if you're fueled up) and to monitor some statistics in-flight (to make sure you won't be fined for speeding). There's some custom controls here with transparency, and the whole app is supported by smart Office documents: the new ActiveDocumentHost control allows you to embed those directly into your WinForms app! If there's a problem with one of the readings (e.g. your altitude is too low), you can look at an Excel sheet showing the data and you have a Research Pane ready to help you diagnose the problem before you submit a problem report in Word.

The Maintenance Application:

So we've already covered quite a lot of the scenarios but there's still a lot of work (especially on the Flight Attendant app on Pocket PC) - so I'm off coding again!

Wednesday, May 26, 2004 9:12:07 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

ADO.NET 2.0 Quickies#

Writing data access code will probably remain useful for quite some time, especially since ObjectSpaces is being rolled into Longhorn's WinFS data store. I sure do understand why, but I'm still a little sad to see it go (although it's not really gone of course).

Anyway, here's a quick dump of some things I picked up from a recent MSDN TV episode on ADO.NET 2.0. Especially cool is the "provider-agnostic data access code" so you're never coding against an actual provider (SQL Server, Oracle, ODBC, plain text, whatever, ...) but use the generic versions through a factory...

// Get the configured providers if you want to see them all.
DataTable providers = DbProviderFactories.GetFactoryClasses();
// The "InvariantName" column contains the invariant name to be passed to GetFactory.

// Use a specific provider.
DbProviderFactory factory = DbProviderFactories.GetFactory( invariantName );
using( DbConnection c = factory.CreateConnection() )
{
    // Use generic methods to create commands and other ADO.NET goodies.
    c.ConnectionString = "...";
    DbCommand cmd = c.CreateCommand();
    cmd.CommandText = "...";

    // Something else that's new: load a DataTABLE directly in stead of a DataSET.
    DbDataReader r = cmd.ExecuteReader();
    DataTable table = new DataTable();
    table.Load( r );
}

// And for perfomance, in stead of updating each row separately to the DB,
// batch them all at once to lower the number of connections to the DB.
// This will call sp_executesql(""); with a sql string that contains the batched statements.
DataAdapter da; // Initialize this...
da.UpdateBatchSize = 100;

Blog | Programming | .NET | ASP.NET | Whidbey | Windows | Longhorn
Monday, May 24, 2004 2:53:00 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Random Visual Studio Whidbey Annoyances#

I guess I'm in bitch-mode anyway so why not: some random things that are driving me nuts in the Visual Studio .NET Whidbey CTP:

  • Those damn datasets that keep generating an extra SomeDataSet1 file and class! It's great that we get typesafe datasets from the MSDataSetGenerator, really, but one class will do just fine thankyouverymuch. It's probably because the dataset is under source control, thereby making all the associated files readonly. This makes it pretty hard for the generator to write to the file and in stead of checking out the original file, it has the great idea of ignoring it altogether and appending a number to it in stead - thereby introducing multiple versions and breaking builds. (Just my guess.) It even messes things up sometimes if you're just looking at the dataset. What's wrong with looking at a file? Never let looking at a file trigger a checkout!
  • Clicking a project item in the solution explorer when you're coming from another project makes the solution explorer scroll so that the current project node is made visible. Contrary to what someone must have thought on the design team: that's not cool. I don't expect any window to change its position or layout by just clicking in it. But what's a lot worse: if you double-click, say, a classfile and it decides to scroll then the double-click fires afterwards and you're really opening a different file. Combine that with the previous remark and you can have the great effect that double-clicking some regular class in solution explorer can cause the window to scroll, thereby making itself think you clicked a dataset, triggering it to be displayed, checked out and having it generate a SomeDataSet1 file. Did I mention this wasn't a cool feature?
  • And last but not least... The eternal pain of references. This is killing me. References have been bugging me before, so please, please, pretty please with sugar on top, fix them once and for all! Although certainly not always possible, the ultimate solution to problems with references has always been using Project References. So that's what I'm doing now, but in ASP.NET they tend to switch from project references to fixed binary references that don't get updated anymore. And you wonder why you get runtime errors... So you need to check those references regularly and reset them to project references. Joy! What's even funnier is that an ASP.NET site doesn't have a project file anymore, which would be fine if there was nothing to remember for an ASP.NET project. But what about these references? I'm sorry to have noticed that, but they're stored in the solution file. Bad, bad, bad... If you have multiple solutions with the same ASP.NET project in them, it would depend on the solution file which kind of references the project would use. If you really need project-settings, revive the project file guys and recall the "no project file needed"-hype. What's one file extra going to do anyway?

Anyway, ASP.NET 2.0 still pretty much rules apart from that so that makes up for a lot :-)

(That doesn't mean that this shouldn't all get fixed of course, so if you're reading this and can do anything at all about it that would be greatly appreciated :-) )

By the way, I realize it's an alpha build so it's not perfect; this post will just help me re-evaluate the beta once it ships :-)

Blog | Programming | .NET | ASP.NET | VS.NET | WeFly247 | Whidbey
Tuesday, May 04, 2004 9:32:36 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

The ASP.NET 2.0 ObjectDataSource Revisited - or - Give Me That Extra Inch!#

Since I cried tears of joy over the new ObjectDataSource in ASP.NET 2.0, two things have happened:

The first one is only important if you're doing, well, anything at all in .NET really. By that I mean: go get it already dammit! It can now load, visualize, search and decompile assemblies from any .NET runtime, including the Whidbey ones, so this killer tool just became even better! I just used it to check upon my remark to see if the ObjectDataSource would cache the runtime type information it found - but it doesn't look like it does. This would imply a significant overhead on assembly probing and reflection each time the data is fetched (if it isn't read from the cache of course). Anyway, let's call that "room for improvement" or "never mind you twat they know bloody well what they're doing so stop decompiling and jumping to conclusions already".

Regarding the second one, I thought about naming this post "ASP.NET 2.0 DataBinding - Close But No Cigar" or even "Microsoft still doesn't get DataBinding" - but that's just a little harsh and arrogant ;-) It would probably generate more attention though, but for now, I'd just like to subtitle it "Give Me That Extra Inch".

So what's the problem? Let me just briefly sketch the right context here... Most modern applications are n-tier, which means your data is stored in a data tier (which is backed by a relational database most of the time), it passes a business tier holding all your core business logic, and then reaches your user interface tier. The data itself is "disconnected", meaning no connection (to a database or other data store) is kept alive and the data has no memory of where it came from. In .NET land, this is represented by the DataSet object with embedded DataTables, primary keys, relations, constraints, ... - thus providing an in-memory representation of a relational database. But I'm sorry for boring you; you know all of this, right?

So the two main points in modern data-driven enterprise development are: n-tier and datasets.

And although we (and certainly Microsoft) have known all this for years, there's never been any real support for this in the .NET framework or in the samples: 95% of all examples still go straight from the UI to the database. And that's frustrating for you as an enterprise developer, since they're not realistic or useable in your world.

Now I thought for a minute that the ObjectDataSource would finally be able to solve this issue - as I've said before, it's a DataSource control that fetches data from any object through declarative configuration. So just hook it up to a remote business component or web service that returns a dataset and you've succesfully decoupled your UI from your other tiers, while maintaining your easy-to-use declarative ASP.NET databinding.

Well, yes, but only partially. While this works great for a lot of scenarios, it fails when things get just a little bit more complex: it won't work when you have multiple data tables in your dataset, which is a very common practice when you're fetching related data. Since you're working with multiple tiers, you'll want to reduce the number of calls and get chunky in stead of chatty conversations. So you try to group as much related data in a dataset as possible. And then the client can look at this data as individual tables but also navigate the relationships between them.

And a data source having multiple tables has always been supported in databinding as well, using the data member to indicate which table in your dataset should be used. The new databinding classes also support this through "views" on the data, which you can retrieve by the view name. Unfortunately, here's the drawback: the ObjectDataSource only supports one table from the dataset. It actively checks on the retrieved object to see if it's a dataset and if it is, it just uses the first table to create its one and only view. (How do I know? Reflector for president!) Even the documentation says so: "The ObjectDataSource control supports only one data source view". So that's where it ends I guess. They really did come close this time, but I'm still a little disappointed.

I need to get a little more chunky than chatty too, so just to summarize: please make the ObjectDataSource support multiple views if there are multiple DataTables. Thanks. That's all I wanted to say really :-)

Monday, May 03, 2004 3:27:56 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Working around some ASP.NET AdRotator limitations#

I'm playing working with the updated AdRotator in ASP.NET 2.0, and I had to work around some limitations so I figured I'd best share what I came up with...

The AdRotator is a control that shows a random advertisement, which is basically just an image and a link to a target page (like a shopping page or an e-commerce site). And that's the problem. That's all it is. An image and a link. What I wanted to do is make an advertisement that also shows a description and a price next to it, but unfortunately there's no templating mechanism for the AdRotator to customize the control. (Spot the hidden feature request.)

Another problem I had is that I pull the advertisement data from the database (the new AdRotator supports the cool new ASP.NET 2.0 databinding so you're not limited to xml files anymore like before). But there's no NavigateUrl in the database, and I need to give the AdRotator a URL to which it should navigate when you click the image. Unfortunately, I can't make the NavigateUrlField "smart". I have a ProductID in my datasource, so I'd like to have it construct a url based on that, a little something like this:

<asp:AdRotator (...) NavigateUrlField='<%# Eval("ProductID", "~/Shop.aspx?ProductID={0}") %>' />

But that doesn't work of course, the NavigateUrlField has to point to a field in the datasource (and I'm not sure if this <%# %> construct would work anyway)...

I could add a NavigateUrl field on the business tier but frankly, I don't want to. It's not the business tier's business (pun intended) to know there's an AdRotator somewhere down the line that needs this funny Shopping URL. It only knows about products. I could add the column on the client tier but then I'd lose my beautifully simple databinding since I'd need to preprocess the data. Well in fact the databinding would still be easy, I'd just bind it to a local "proxy" preprocessor object in stead of to the actual webservice. But it's less transparant and I still wouldn't have my price and description anywhere near my image...

In the end, I decided to do it a little differently. I created a simple Advertisements user control with an AdRotator in it, and labels for the price and description. Then I just use the AdRotator's AdCreated event to play around a little bit. The trick is, you can get to the data source fields through the AdProperties dictionary on the AdCreatedEventArgs. I'll just let the code speak for itself:

<%@ control language="VB" classname="Advertisement"%>
<script runat="server">
 Private Sub shopAds_AdCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AdCreatedEventArgs)
  e.NavigateUrl = "~/Shop.aspx?ProductID=" & e.AdProperties("ProductID")
  description.Text = e.AdProperties("Description")
  price.Text = e.AdProperties("Price")
 End Sub
</script>
<table>
 <tr>
  <td>
   <asp:AdRotator ID="shopAds" Runat="server" DataSourceID="advertisementData" ImageUrlField="ImageUri" OnAdCreated="shopAds_AdCreated" />
  </td>
  <td>
   <asp:Label ID="description" Runat="Server" />
   <br />
   <asp:Label ID="price" Runat="Server" />
  </td>
 </tr>
</table>
<asp:ObjectDataSource ID="advertisementData" Runat="server" TypeName="WeFly247.UI.Proxies.PassengerWebService" SelectMethod="GetProducts">
 <SelectParameters>
  <asp:ProfileParameter Name="cultureName" Type="String" PropertyName="Culture" />
 </SelectParameters>
</asp:ObjectDataSource>
Blog | Programming | .NET | ASP.NET | WeFly247 | Whidbey | Samples
Wednesday, April 28, 2004 10:14:37 AM (Romance Standard Time, UTC+01:00) #    Comments [13]  | 

 

DataBinding in ASP.NET 2.0#

ASP.NET 2.0 features a whole new DataBinding infrastructure, which allows you to define and consume data sources declaratively. Sounds fancy, and it is. If you look at last week's coding summary, you can see this in action:

<asp:ObjectDataSource ID="infoData" Runat="server" TypeName="WeFly247.UI.Proxies.PassengerWebService" SelectMethod="GetFlightData" />
<asp:GridView ID="info" Runat="Server" DataSourceID="infoData" />

As you can see, there's that new GridView control, and in stead of binding it in code (you know, set the DataSource property and don't forget to call DataBind!) you just set a DataSourceID. This is a reference to some data source object, which can now be just a control as any other (under the "more markup! less code!" motto).

Now there are a number of data source controls: SqlDataSource (accesses SQL Server), AccessDataSource (accesses Access (whew)), SiteMapDataSource (reads a sitemap file), DataSetDataSource and XmlDataSource (which speak for themselves), and last but certainly not least: the ObjectDataSource.

Now this is what I call goodness. They've finally come to their senses and realized that not everyone uses a database on the client tier. They've heard themselves say "Web Services" one time too many I guess, and this ObjectDataSource is the solution for everyone who has data living on another tier. What it does is create a new instance of the type you specify, and then call a method on it to get the data. After that, the object is disposed again but your disconnected data remains alive in the data source control.

Possibly (I'm just guessing - hoping actually - here, I haven't checked since I can't use Reflector to decompile this yet :-) ) they'll cache the object and method information (not the object itself, the documentation states clearly that it's disposed of) somehow to prevent every call from having the overhead of using reflection to find the type and the method to call. Anyway.

So in our case this little piece of markup just creates a new Web Service proxy for the passenger Web Service, calls the GetFlightData method on it (which effectively sets the whole SOAP story in action, talk about hidden complexity) and uses the returned data for data binding.

Sounds easy, and easy usually means limited. Fortunately, they've thought well about it, and provided quite a range of extra options. DataSource controls support parameters to be passed in or out, through parameter controls which can fetch their values from other controls, form fields, cookies, the new ASP.NET Profile, the query string, the session, or you can build your own. (A literal parameter value would be nice to pass in a constant though, but it doesn't seem to be there...). For example, this one fetches the user's culture from his Profile, and passes that along to the GetProducts method:

<asp:ObjectDataSource ID="advertisementData" Runat="server" TypeName="WeFly247.UI.Proxies.PassengerWebService" SelectMethod="GetProducts">
 <SelectParameters>
  <asp:ProfileParameter Name="cultureName" Type="String" PropertyName="Culture" />
 </SelectParameters>
</asp:ObjectDataSource>

And in case you were worried about two-way data, DataSource controls also support updating, deleting and inserting through other properties - again with parameters like before. For a lot more information, look at the excellent MSDN article on databinding in ASP.NET Whidbey by Early & Adopter.

So this is one of the reasons I'm pretty impressed with ASP.NET 2.0. More reasons are bound to follow - stay tuned :-)

Wednesday, April 28, 2004 9:59:20 AM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Setting a general base class for all your ASP.NET pages#

Since ASP.NET 2.0 is making such an effort to reduce the need for writing actual code, it's now becoming less likely that you will be using code-behind files. It's still possible of course, but if you don't actually create a page class yourself, ASP.NET will just do that for you. And the good thing is, you can just specify the base class it needs to use - so you can slide in your own custom base class in stead of the standard System.Web.UI.Page. Very convenient in scenarios where you're writing framework-like base pages, or if you want to do something extra in every page of your site. Just use the <pages> section in the web.config file as such:

<pages pageBaseType="Acme.Framework.Web.UI.SharedBasePage">

You can do the same for controls by the way. Actually, you can do a whole lot of things in that tag, like adding namespaces that need to be imported by default, pre-registering tag prefixes, well basically just managing your pages in a single place. Cool!

Blog | Programming | .NET | ASP.NET | Whidbey
Monday, April 26, 2004 2:42:32 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Last week on WeFly247.NET#

Well it's been a bumpy ride so far, I can tell you that. Working with alpha builds is always a bit of a "challenge" so of course we knew we could expect some trouble, but regular crashes and excessive memory consumption are now part of my regular day :-) Let's just say there's still quite a lot of work on Visual Studio, so I think I know why they're calling it "2005" nowadays :-)

So for now, we're still on the CTP build released on MSDN a few weeks ago, but maybe we'll switch over to a newer build if there's a chance of getting a more stable one. Anyway, it's a good thing I'm developing inside a VirtualPC, so when all else fails I can still revert to a more or less clean VPC and just pull the sources from SourceSafe.

But the good news is that there's such a flood of really great stuff coming in Whidbey errrr "Visual Studio .NET 2005 formerly known as Whidbey" (I think I'll stick to calling it "Whidbey" though :-) ) so I'm really excited about it! I've been mostly working on the ASP.NET side of things, and it's just incredible what they've been doing over there. Security, Personalization, DataBinding, Web Parts, Themes, Masterpages, ... It's all there and it's really well architected. And best of all: it even seems to be pretty stable in this build :-)

The trick here is to try and forget some "best practices" from ASP.NET 1.x because there are just a lot of new ways to do things now, and most of them don't require any code at all. Take DataBinding for example, with just 2 lines of markup, you pull your data from your Web Service and bind it to the new GridView control:

<asp:ObjectDataSource ID="infoData" Runat="server" TypeName="WeFly247.UI.Proxies.PassengerWebService" SelectMethod="GetFlightData" />
<asp:GridView ID="info" Runat="Server" DataSourceID="infoData" />

Goodness!

So I'm pretty much done with the general structure of the website, I'm now going to focus on connecting it to the business tier and feeding it some actual live data.

Blog | .NET | ASP.NET | VS.NET | WeFly247 | Whidbey
Monday, April 26, 2004 1:22:23 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

ASP.NET & XAML - I'm so slow#

I just made the most obvious observation: ASP.NET 2.0 and XAML are mother and daughter. And their hereditary determined angle-bracket beauty will only be increasing by the laws of natural selection.

Although that shouldn't come as a surprise at all since it's often been said that "XAML is to WinForms what ASP.NET was to the web". I just hadn't had the physical real-world click just until now. (Of course it's already been shown extensively that XAML isn't really tied to WinForms at all, but it's probably still the most useful scenario for it.)

So what triggered the click? I just noticed that some ASP.NET controls provide a kind of nested properties like <SomeControl Property-NestedProperty="[value]" />, e.g. <GridView HeaderStyle-Font-Bold="True" />. That's just like the nested properties syntax in XAML (only here they're using a dash in stead of a dot). I don't think the syntax here is as universally supported (I've only seen it with a number of properties, mostly to do with styles) but it's conceptually the same.

Another thing that struck me is the template mechanism; it's been there since the beginning really, but in fact it's just a way to attach template objects to controls (like grids) without using code. In other words: declarative object coupling.

So to realize their 70% code reduction claims they're providing declarative nested attributes and object coupling - exactly what XAML is so damn good at… I should've seen this long ago, I'm so slow...

Monday, April 19, 2004 1:19:22 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Public Referrers & Google-Trash#

A while ago, I wrote a simple dasBlog hack to show my referrers (use the links on the site's navigation bar or watch my public referrers directly). Works great, but there's one small issue with it... I'm getting a lot of google-trash on my site lately, and it's snowballing so I'm going to have to try and halt that.

Somehow, sometime, someone came up to my site with the word 'kcarc' (spelled backwards to try and prevent the problem you're about to discover :-) ) somewhere in his google referral. So that shows up in my public referrers page. No big deal, since I have a robots.txt file that tells google and co to bluntly ignore that page instead of indexing it.

Unfortunately, either I was too late, or something's wrong with my robots.txt file (it validates though) or google isn't playing nice - because it did get indexed. So looking for that specific word might get you here. And get your search query listed on my referrers page. And getting that indexed as well. And drawing more trashy traffic... And it's been snowballing ever since, because now I'm getting more and more referrals that come looking for "free-version-patches" of their favorite software (which I don't provide, as you might have noticed around here, it's not that kind of technology site).

So I hacked my hack to exclude all referrers that contain the dreaded c-word... Hope that'll help to keep my referrer logs clean. I wouldn't want to close the page down, they're too much fun to read once in a while really :-)

Update: I added some more words that needed to be blocked (I feel a new hobby coming up), and I've also removed the google and feedster queries from the main referrer url list (since they're already listed below) which makes the top list a lot cleaner. Cool (if I say so myself)!

Thursday, April 15, 2004 11:48:58 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Trackback between dasBlog and .TEXT not working?#

I've seen this before when posting my answer to Brad Abrams' NullReferenceException question, and I just noticed it again while linking to Dave's post about WeFly247: trackbacks don't seem to show up in a .TEXT blog when I set a trackback url from dasBlog.

I do get a dasBlog event that the referral was received:

Info ItemReferralReceived:
Item referral received for local item PermaLink.aspx?guid=66d46880-96e1-43d7-9e38-a992fac63aa4 from target http://dottext.com/Services/default.htm

But it never actually shows up in the target blog's comments section... Does anybody know if this is a bug or if I'm doing anything wrong??

Friday, April 09, 2004 1:44:22 PM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

Whidbey Impressions#

I've finally started working on the new Whidbey build. Some marketing-friendly people called it CTP (Community Tech Preview), people who like uniformly-rising integers might call it PD4 (Partner Drop 4) but real coders refer to it as "2.0.40301" of course. I've already had it added it to my list of friendly runtimes (don't worry, I still have enough tattoo-space left for years to come).

The first big thing I noticed was that Whitehorse still isn't there. The goodness of having a round-trip engineering class designer, a uml modeller, a network layout modeller, ... all within your IDE (emphasis on the 'I' here) will have to wait a little longer I guess. This means I have to go back to Visio to model my use cases and database diagrams for my current project. It's not that Visio is a bad product or anything, it just sucks that's all. It's not integrated, it doesn't look as good, it feels old and clumsy, and I hate the way it does some of its layouting (especially connectors are terrible, and too hard to correct yourself).

A nice little improvement on the Error Reporting dialog (aka crash-o-spam-a-thon, I always send error reports you know :-) ) caught my attention (actually, it's not a good thing that I noticed this, since I was hoping not to encounter the dialog altogether but well, it's still alpha software of course :-) ): there's now an option that makes the dialog close itself after the error report has been sent. Thanks, it's the little things that annoy you the most you know. They should really put this in the general Windows error reporting dialog as well (I would have figured it was actually the same component but apparently that's not the case).

I got an interesting exception when trying to view a project's properties (officially I'm pretty puzzled how I'm going to manage without project properties but still): "The type serialized in the .resources file was not the same type that the .resources file said it contained. Expected 'System.Drawing.Size' but read 'System.Drawing.Size'". Normally when I get this kind of warning, I'd expect some kind of versioning problem here. But within Visual Studio? Uh-oh...

Update: the Project Properties are working again... There seemed to be a problem with the keyfile causing the build to fail which apparently also prevented the project properties page from loading. I removed the keyfile tag in the .csproj file (xml and msbuild rule) and all is well again.

Now I'm in even more trouble: the new Pocket PC 2003 emulator doesn't seem to do a lot. I doesn't power up and freezes my Visual Studio... Deploying it to the "legacy" emulator does seem to work though, and what's pretty cool is that it gives you these confirmation dialogs to replace "mscoree.dll" so I'm really patching the emulator to the Whidbey build of the .NET CF 2.0. Ah wait a second, fortunately already an update on this: the new emulator does work! You just have to wait a long while when powering it on. It takes a minute before the Windows Mobile splash screen pops up, then you have to wait even longer for the .NET CF 2.0 to be installed, the application itself launches slow, but it works fine and I still think the whole concept rocks :-)

The Object Browser window doesn't seem to have the new view yet where you can see a class definition as an emtpy code file, too bad because I kind of like the idea: it's more natural as a programmer to view a type contract as an actual code block. You can however get a glimpse of how it will look using the (buggy) Windows Forms Class Viewer tool (WinCV.exe in the SDK 2.0 dir).

Update: It's not in the Object Browser window but it's there: View - Other Windows - Code Definition View. This gives you a window that shows a code block for whatever class happens to be under your caret. Cool!

Oh one more thing before I actually get back to work: wear sunglasses when coding. The component tray (you know, the region where your non-visual components like tooltips and extenders are shown in the designer) is in eye-bashing purple. So are the gridlines in the task list. Damn, they must have fired all the people with a working set of eyes over there...

Blog | Programming | .NET | ASP.NET | VS.NET | WeFly247 | Whidbey | WinForms
Thursday, April 08, 2004 3:10:35 PM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

Public Referrers In DasBlog#

Cool, I just finished up a quick dasBlog hack to make my referrers publicly available. Check it out in the navigation bar! I also parsed the google referrers to show the actual search they entered in stead of just the url which is less readable. Just because I got curious after Rory's google explorations :-) Furthermore, it's now also possible to show more than only today's referrers, you can specify how many days it should look up.

For those of you with fat glasses and a wireless router that has toilet-reach: here's how I pulled it off without having to touch the dasBlog codebase... If you look at the dasBlog sourcecode, the aspx pages are extremely simple: they don't contain any markup but are rendered by their code-behind classes. These are defined in the dll that makes up the dasBlog runtime (which I don't want to touch or recompile). Luckily, there's another way to get pages with code-behind without precompiling the sourcefiles: that is to use the Src-tag of an aspx page. This points to a sourcefile which will be JIT-compiled the first time the page is requested. Same goes for user controls.

Now the referrers in dasBlog are shown in the admin area only, and they're defined in a Referrers.aspx page which just checks security and loads the ReferrersBox.ascx control. So in order to bypass security (i.e. make it public) I needed to have a page with a codebehind that didn't check the security. Hence the PublicReferrers.aspx and PublicReferrers.aspx.cs files: the first one is just a copy of the original one - except that its "Src" tag points to the second file which is a C# source file. This is a copy of the original dasBlog file but with the security part stripped out and the loaded control replaced by PublicReferrersBox.ascx. Fairly simple, right?

The PublicReferrersBox.ascx is also a copy of the original ReferrersBox.cs but with the ActivityBar stripped out - it's only needed in the admin area. It points to its codebehind file PublicReferrersBox.ascx.cs which is a modified version of the original dasBlog file. So this is basically the code that provides the extra google goodness and the fact that it can show more than one day. I'm not going to bore you with the code, just take a look if you're interested.

So if you want this on your own blog: go and get your hands dirty recreating these steps. Or better yet: just download the necessary files and copy them in your root dasBlog directory :-)

PublicReferrers.zip (5,21 KB)

Blog | General | Programming | .NET | ASP.NET
Saturday, January 31, 2004 1:50:23 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Migration Step 4: Website#

Last time, I left off with all services including ASP.NET installed - ready to kick dasBlog into action.

Installing dasBlog was easy (copy, set directory security, create IIS application, edit config file, done) and I'd already tried it out before to make sure it would be up for the task at hand. That is: run a little more than a blog but make it look and behave more like an actual website.

So the blog would obviously be the frontpage, since that's the biggest chunk of the site and it's updated most (static frontpages are boring). I started off with the preinstalled 'dasBlog' theme which is pretty nice by itself, and modified that a little bit to suit my needs - you know, play around with the colors, locations, disclaimers, css, that kinda stuff. Then I dropped my OPML containing my blogroll into the site (so you know who I read, social networking baby), and I used the 'navigation links' feature to show a list of the posts I think you might want to read most (just to help you filter out the incredible noise ;-) ).

What I really like about dasBlog is that it has a severely underdocumented feature called nested categories, which can show categories in the nifty tree you can see on the site (aggregators don't get this kind of fun). So the key to making it look like a website with some non-blog pages is (ab)using these categories to make pages out of them. They'll show up in the category tree though, so I just called the tree a sitemap to fix that :-) But basically it just boils down to adding some 'posts' in 'categories' like 'Projects' and 'Stories' (reminds me of a 'laser' but never mind) and such, and then a sibling feature of dasBlog kicks into action: per-category templates! That means you can make templates defining the page layout per category. So I made a more simple template to get rid of all blog-like formatting like date and time, permalinks, trackbacks, and all that other stuff that makes aunt Jane's head hurt, and assigned those templates to the non-blog pages. Easy enough.

Finally, I used another cool dasBlog feature: Content Filters. These allow you to replace strings or regular expression matches in your posts with something else. For example, they can replace simple things like smileys you type into image tags which actually show a smiley picture. Okay so that's not Nobel Prize stuff but it works pretty well and I decided to use it for a usability feature. I'll save that for a separate post, but I'll leave the regular expression for you as a pop-quiz: href="?(?http[^"\s]+)"? gets replaced into href="${expr}" class="external" target="_blank". Shouldn't be too hard, right? Don't hold back posting your answer into the comments...

So basically, I'm very happy with dasBlog. I got everything I wanted out of it, and it didn't mean touching the code. I was tempted at some points to dig in and add some features but I wouldn't want to be unable to upgrade if there's a new version so I sucked it up. So great work Clemens and everyone who contributed!

Blog | General | Programming | .NET | ASP.NET
Thursday, January 29, 2004 11:59:23 PM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

Photo Album Tech Specs#

Just a quick rundown of how the photo album is implemented... Basically you have a hierarchical structure leading to a series of pictures: Collection -> AlbumGroup -> Album -> Series -> Pictures. A Picture is pretty obvious right? An Album is a set of pictures about one topic. But there's a level in between called a Series, which logically groups pictures within the same album. For instance, an album could be about one trip, and each series represents pictures taken by someone else. If there's only one series, it's not displayed to make it easier to browse the album. Now you can group these albums together in an Album Group which is basically just another higher level view. I used it to group the albums by year. The same goes for a Collection, but if you don't need this level (which I don't) you can turn it off so it won't be visible.

In retrospect, it probably would have been better to be able to define a recursive tree with arbitrarily deep nesting but well, I didn't. Maybe in a next 'version' ;-) In general, I hacked the code up pretty quickly so it's all not that pretty I'm afreaid (meaning: I won't open source it :-) )

Now for the implementation: it's a single ASP.NET custom control which uses an xml file to define the hierarchy explained above. Each level has some properties like title, description, date, keywords (not used yet), the path of how to get there, the thumbnail to be used and the security roles which are allowed to see this item. ("What, I can't see everything?!" - uhm yeah that's right :-p ). Some other advanced features: thumbnails can be created on the fly and cached on disk, and the date and time the picture was taken can be extracted from the EXIF meta data stored in the file. This all happens on startup of course, not on every request. The security aspect uses the current principal to define which roles it has - and that's where it plugs nicely into dasBlog because if you're logged in it sets that current principal automatically with the role defined in its configuration file. This means I can hand out individual logins on my blog to people I trust not to send the secret pictures around ;-)

Now of course, you're not supposed to enter every single picture in the xml file because well - that would take forever in my case... It can use filters (like *.* or *.jpg) to add all files in a directory. And the other levels (series, album, ...) will also be filled in automatically from the directory structure if you don't specify anything yourself.

I'll probably expand the photo album some more later on. As I mentioned I want to do something with keywords so you can search for pictures or have an alternative index like the cross reference on Mark Pilgrim's excellent photo album (this is where I stole the idea of course). Implementing it wouldn't be so hard actually, it's more a perseverance test to see if I could keep up adding keywords to each and every picture...

For now, there are two minor bugs I know of... If there's an album with one series, then the series won't be displayed as I mentioned before. But it will show up in the breadcrumb (navigation) above. I'll probably fix this sometime. The second one is trickier: when you're browsing the photo album, each level displays how many items are below it. For example: there are 3 albums in 2000, or 11 pictures in a certain series. Well that's certainly true but if you go look into it, it may actually be less depending on your security role. So if you see less pictures than expected - then you know you're missing out on something great :-) I could fix this too but it would have a runtime performance penalty.

Anyway, that's pretty much all there is to it I guess. All comments and suggestions welcome of course!

Sunday, January 04, 2004 12:42:21 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

My Photo Album went online!#

I'm proud to announce the new photo album on my website! Lots of pictures already, and lots more to follow I guess :-)

Blog | General | Programming | .NET | ASP.NET
Saturday, January 03, 2004 2:13:02 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Barcelona!#

Well, I'm off to Barcelona to start the new year!

Expect some pictures here soon, I'm finishing up a pretty cool photo album in ASP.NET that plugs in nicely with dasBlog - well actually it's a web control so it plugs in nicely with anything remotely related to ASP.NET :-) So stay tuned...

Everybody have a great party; and my best wishes for 0x7D4! (Ok so that was my last small act of nerdliness for this year ;-) )

Blog | General | Programming | .NET | ASP.NET
Sunday, December 28, 2003 11:15:29 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Pager Control for ASP.NET#

There's a cool Pager Control on MSDN that lets you add paging to databound ASP.NET controls other than the DataGrid. Looks pretty good!

Tuesday, October 21, 2003 9:43:21 AM (Romance Standard Time, UTC+01:00) #    Comments [3]  | 

 

Some cool ASP.NET Whidbey preview stuff#

Scott Gunnerson talks about his ASP.NET Keynote Demo and shows some screenshots. Points 6 (SQL Cache Invalidation!) and 8 (Master Templates!) must totally rock!

Monday, October 20, 2003 8:52:51 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

ASP.NET Version Switcher#
Here's a nice GUI tool that lets you swi tch the runtime version between 1.0 and 1.1 for an ASP.NET website. Wish I had this when I was manually converting the isapi mappings in IIS!
Tuesday, September 09, 2003 7:54:40 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

Relative Url's#
A lot of ASP.NET WebControls use a url, such as the NavigateUrl property of the HyperLink control or the ImageUrl for an Image. If you set such a url to a relative path, you might experience some unexpected behaviour in some more advanced scenarios - unfortunately without a clean workaround.

Internally these url's are rendered to html using the Control.ResolveUrl method. The first thing this does is deciding whether or not it's a relative url. If it's not, then the url is just returned so absolute url's remain untouched. If it is a relative url, then it is prefixed with the control's TemplateSourceDirectory - and there's the tricky part. The Control.TemplateSourceDirectory property is "the virtual directory of the page or user control that contains the server control". This means that a relative url is always relative to the containing control's directory, not to where you're setting it from. If you remember my post on ASP.NET Path Discovery, this will sound familiar. More on that later.

Now imagine a scenario where you have a breadcrumb-style header control (Header.ascx) with some navigational hyperlinks on it that need to be added depending on the page hosting the control. This means the hyperlink controls are contained in Header.ascx, and their url's will always be relative to this control's directory. If you use the header control from various places in various directories then you need to step away from the idea that setting these url's will be relative to the page you're working in. In stead you should always think on how to get from the header control to the current page's directory which is a pretty heavy burden. And as I mentioned in my post on ASP.NET Path Discovery there is no clean out-of-the-box way to discover this 'current path'.

As for a workaround: there is no property on a hyperlink or any other control that allows you to modify this behaviour and take the url you gave it as such without modifying the path. The only thing you can do is to manually set the href attribute in stead of using the NavigateUrl property as such: myHyperLink.Attributes["href"] = myUrl. I probably don't need to mention that this isn't my idea of clean code but sometimes you just need to get your work done too ;-)
Blog | Programming | .NET | ASP.NET | Quirks
Friday, August 01, 2003 12:37:28 PM (Romance Standard Time, UTC+01:00) #    Comments [1]  | 

 

ASP.NET Abstract Base Classes & Visual Studio#
Not a good mix ;-) Apparently when you try to open a web form in the designer, it will try to create an instance of the base class of your form's code-behind class. Typically, that will be the System.Web.UI.Page class. I can see why that's a good idea in WinForms where you actually see an instance of a Windows Form (System.Windows.Forms.Form) in the designer - but I don't really understand why the web forms designer would do such a thing. Web forms should render html to the browser, and since User Controls aren't even rendered in the webpage you're designing I don't think any other actual rendering is done by the designer, apart from your own html code for the page of course. So why create an instance of the page's base class?

The reason I came across this is that we have some custom base classes for ASP.NET pages and our design required one of those to be abstract since an overriding class should implement a certain method. Now the designer crashes on us if we derive from that since it tries to instantiate an abstract base class - no more forms designer for that page. Maybe there is a good reason for the designer to instantiate a Page object, but at least it could look further up the class hierarchy for a more suitable (i.e. non-abstract) base class if it really needs some instance to do its work.
Blog | Programming | .NET | ASP.NET | Quirks | VS.NET
Thursday, June 12, 2003 9:03:05 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

It's oh so quiet...#
Hmmm, not a lot of posts recently. Have I learnt nothing at all then the last couple of days? Sure I have!

The coolest thing I've done this week (at work anyway :-) ) is writing a sort of ASP.NET databinder for xml documents. Shortly put, it's a component that binds a property of a control to a node within an xml document using an xpath query. For example, it can bind a textbox txtCustomerEmail to the xml node "/customer/info/contact/@email" - which means it will fill the textbox with the proper attribute value from the attached xml document, and after a submit it can update the xml document with the modified email address the user entered in the textbox.

As an extra treat, if the node specified by the xpath query doesn't exist yet, an attempt will be made to create it - along with any underlying nodes that don't exist yet. So if you try to set the email address to 'billg@microsoft.com' (yes, he's a customer of ours ;-) ) but the xml only contains for example, it will create the info and contact nodes, and the email attribute within it to result in the following xml: . Cool? I think so!

I have to admit that it's still fairly limited (it can only handle basic xpath queries to be able to create nodes), and it would be great to implement this as an extender provider but since those still don't work in ASP.NET, I guess that's out of the question.

I've also been quite busy on E = m c² again, watch this space for some cool updates real soon!
Saturday, May 31, 2003 12:46:03 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Make the page title runat the server in ASP.NET#
In ASP.NET you have a (i.e.: exactly one) html form in which all your controls reside. If you want serverside access to any control, you just give the appropriate tag an ID and the runat="server" attribute. If the designer didn't already do this for you, declare an object of the proper type in your codebehind page with the exact same name as the ID you gave your tag and you're done - you now have full control over your uhm... control. You can do this with any tag - if there is no serverside equivalent for what you're trying to do, just use the HtmlGenericControl.

But what happens if you go outside the bounds of your form? A typical problem I've seen posted a few times is: "How can I set the title of my webpage in code?". This implies accessing the <title> tag in your html, which is in the <head> section (i.e. before the actual <body> and <form>). It turns out you can just as well make any tag there run at the server. So you might go:

<title id="lblTitle" runat="server">WebPage1<title>

In your codebehind you declare your object:

Protected WithEvents lblTitle As HtmlGenericControl

And voila, set the text as follows: lblTitle.InnerText = "This ran at the server!".

Now we can take this one step further. Why not create something that encapsulates a portion of the <head> tag? Just add a User Control to your project, e.g. "HtmlHead.ascx" and make it emit some header tags such as title, meta tags, link tags to import css files, ... anything you can think of really. If you want programmatic control over any of these tags, give them an ID and make them runat=server so you have them at your disposal in your codebehind class. Now you can declare nice userfriendly properties and methods on your User Control such as PageTitle, AddCssFile, etc.

In any webpage, just can now register the user control and add it to your <head> tag as follows:

<%@ Register TagPrefix="uc1" TagName="HtmlHead" Src ="HtmlHead.ascx" %>

Put an instance of this control in the <head>:

<head>
   <uc1:htmlhead id="uctHtmlHead" runat="server"></uc1:htmlhead>
   (...other tags, such as the ones generated by Visual Studio go here...)
</head>

Don't forget to declare the object in your codebehind:

Protected WithEvents uctHtmlHead As HtmlHead

And that's it - you're done: full control over your html head!

uctHtmlHead.PageTitle = "ASP.NET rocks :-)"
Monday, May 19, 2003 7:53:41 AM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

ASP.NET path discovery#
Sometimes the guys at Microsoft just strike me with amazement. This happens a lot but I'll limit myself to sharing this one with you - for now ;-)

I'm working on an ASP.NET project, I have a folder structure like /root/subdir where all my aspx pages reside. Now I learned from last time that it's better to keep my user controls (ascx) in a separate folder (/root/subdir/controls in this case) to keep them from cluttering my actual web's folder. Now inside one of those user controls I'm adding an that should point to "/root/subdir/images/help.png" - sounds easy but I don't want to use absolute url's since I want to be able to move the site into another root or rename the subdir or whatever.

My first guess was just to use "images/help.png" but apparently this becomes relative to the executing control's path, resulting in "/root/subdir/controls/images/help.png". No good. I could go for "../images/help.png" but I don't like this kind of path walking too much since it depends on my project's directory structure, not on my actual web path. Fortunately this doesn't wind up in the resulting html: it will become "images/help.png" and not "controls/../images/help.png" so that's ok.

I could use Request.ApplicationPath but that only gives me "/root" so I'd still have to append 'subdir' to it, and as I said I want to keep away from hardcoding paths in my application.

The logical thing to try next is to use the Request object since that contains the path of the executing aspx page - just what I need because it should be relative to this path. Request.Path contains the page name so I can't use that directly: it's something like /root/subdir/page.aspx and I just want the first part, the directory name. I was naive enough to hope that System.IO.Path.GetDirectoryName(Request.Path) would discover the path separator or allow me to override it easily but nope, I get "\root\subdir/images/help.png". That works in Internet Explorer but it's ugly and non-standard so there's no way I'm using that.

So I'm sniffing around in the QuickWatch window looking at the Request object and what do I see? Request.BaseDir gives me "/root/subdir" - exactly what I need! I punch it in my code but to my big surprise I find that the BaseDir property is declared private! Why? There must be some reason - at least I hope so - because I also noticed that Request.Url.BasePath points to the exact same thing, but it's also private. Again: why?! These things really blow my mind.

I guess I'll wind up doing "../images/help.png", I'm not in the mood to strip off the page and querystring from Request.Path myself. Certainly not since it's already been done by Microsoft but they decided not to share it.
Wednesday, May 14, 2003 9:51:42 AM (Romance Standard Time, UTC+01:00) #    Comments [3]  | 

 

All content © 2010, Jelle Druyts
On this page
Just Released: Mayando v1.2!
What Has Jelle Been Up To (a.k.a. The Last Post)
IIS virtual directory names and mapped file extensions
Visual Studio 2005 Web Application Projects Released!
Faking a current HttpContext
ASP.NET 2.0 References
When ASP.NET 2.0 throws 404's at you...
More on .NET Remoting and customErrors
ASP.NET Comments
Upgraded to dasBlog 1.7!
Fixing the IExtenderProvider in ASP.NET
Avoiding WebSite_1 when pulling an ASP.NET Site from SourceSafe
SmartPart for SharePoint v1.0 released
TechNet evening session on InfoPath & SharePoint
Update to my dasBlog hack for showing public referrers and search engine queries
The ASP.NET 2.0 Profile
Brandnew Look: BlogXP Theme
Rotating an image around its center in .NET
Last month on WeFly247.NET
ADO.NET 2.0 Quickies
Random Visual Studio Whidbey Annoyances
The ASP.NET 2.0 ObjectDataSource Revisited - or - Give Me That Extra Inch!
Working around some ASP.NET AdRotator limitations
DataBinding in ASP.NET 2.0
Setting a general base class for all your ASP.NET pages
Last week on WeFly247.NET
ASP.NET & XAML - I'm so slow
Public Referrers & Google-Trash
Trackback between dasBlog and .TEXT not working?
Whidbey Impressions
Public Referrers In DasBlog
Migration Step 4: Website
Photo Album Tech Specs
My Photo Album went online!
Barcelona!
Pager Control for ASP.NET
Some cool ASP.NET Whidbey preview stuff
ASP.NET Version Switcher
Relative Url's
ASP.NET Abstract Base Classes & Visual Studio
It's oh so quiet...
Make the page title runat the server in ASP.NET
ASP.NET path discovery

Recent Photos
www.flickr.com
This is a Flickr badge showing public photos from Jelle Druyts. Make your own badge here.
Advertising
Top Picks
Statistics
Total Posts: 350
This Year: 4
This Month: 2
This Week: 2
Comments: 526
Archives
Sitemap
Disclaimer
This is my personal website, not my boss', not my mother's, and certainly not the pope's. My personal opinions may be irrelevant, inaccurate, boring or even plain wrong, I'm sorry if that makes you feel uncomfortable. But then again, you don't have to read them, I just hope you'll find something interesting here now and then. I'll certainly do my best. But if you don't like it, go read the pope's blog. I'm sure it's fascinating.

Powered by:
newtelligence dasBlog 2.0.7226.0

Sign In