Willem Odendaal

the coder's point of view

<July 2008>
SuMoTuWeThFrSa
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789


Navigation

I Read

Subscriptions

Post Categories



.NET (RSS)

.NET
Probing Path Doesn't Work

Yeah! It took me a while to figure this one out.

I've mentioned before that to force the CLR to look for assembly in a different folder(not 'bin'), you can add the 'probingPath' element to your web.config file. This article by Scott Hanselman describes the process.

However, I could not get this to work at all. That was only because of my stupidity of course. I overlooked Scott's instruction to add the <% Assembly %> tag to the top of your .aspx page.

This is very very important. Otherwise the probingPath element won't work when you try to load your page. All you'll get are “Could not load type...” errors.

Thank-you Scott!

posted Tuesday, May 24, 2005 3:10 AM by willemo

.NET Licensing

I was surprised to find out that .NET has a built-in licensing model. That means the .NET framework can be used to check if users are using a valid, non-pirated version of your application or control. For the purposes of this post I'll only talk about Control licensing, not application licensing.

You apply licensing to a control by adding the LicenceProvider attribute to your class. This tells the .NET framework which license provider to use to manage your licensing. For example...

[LicenceProvider(typeof(LicFileLicenseProvider))]
public class MyFancyControl { …

The .NET framework comes with one license provider - LicFileLicenseProvider.

I still can't figure out if this provider is really worth anything. It checks that you have a .lic file with(or within) your assembly. If anybody copies your assembly and your license file, the control will work. Not much piracy protection there.

But… you can write your own license provider. And it isn't too complicated either. Check out this article on developer.com to see how to write your own provider. The author, Kenn Scribner, explains how to write a license provider that checks your registry for a specific key and value. So a simple copy of your assembly won't work anymore.

posted Tuesday, May 17, 2005 6:25 AM by willemo

ASP.NET Plugin Architecture

I've spent the last couple of weeks working on an ASP.NET plugin architecture. Our application(web-based) allows the user to use “plugins”. A plugin can be a simple class that executes some code when a button is clicked, or the plugin can actually be a small website with its own custom pages.

If you want to write ASP.NET plugins that are simple classes, the process is straight-forward. I suggest deploying the plugin assemblies into a custom folder. Add the <probingPath> section to your web.config file to tell the CLR where to look for your assemblies. Scott Hanselman has written a good article on how to do this.

If you want to write ASP.NET plugins that use custom pages - Beware! There's a couple of pitfalls you might come accross.

Disclaimer: The advice I give here is not necessarily the correct advice. It's only what I've learn throught a couple of weeks through trail and error. Hope it helps out someone with the same problems. Below are some of the important things I've learnt...

1. The BIN folder

When you load a custom aspx page, the custom page needs to find it's assembly. The CLR looks for the assembly in the current web application's 'bin' folder, then it checks the GAC. Naturally you'd want to put the plugin assembly in the application's 'bin' folder.

There is one catch: when your session state mode is InProc, you cannot deploy plugin assemblies to your 'bin' folder at run-time! When IIS sees that the bin folder has been altered, it silently restarts your web application. You'll lose all your session variables without warning.

One way to get around this is to set your session state mode to SQLServer or StateServer (check out this article for more information). When you do this, make sure that the objects you store in session state are Serializable. Note that these two modes are also extremely slow compared to InProc session state management.

2. The plugin folder

You can deploy your 'plugin' application to a sub-folder in your root application. For example: http://localhost/MyApplication/plugins/MyPlugin.

This folder should contain your custom aspx, js, asax... files (remember, the assemblies are sitting in the root application's 'bin' folder). When you do this, the sub folder should not be configured as an IIS application. If the sub folder is turned into an IIS application, you won't be able to share session variables between your plugin and your root application.

3. The web.config file

Your 'plugin' application will inherit your root application's web.config settings. For this reason, your plugin application's web.config file should only contain the bare minimum settings. I only keep the <authorization> section to configure authorization in my plugin files.

posted Monday, May 16, 2005 7:49 AM by willemo

Wanted: Server Control Documentation

I've written a lot of custom ASP.NET server controls. But my work has evolved enormously during the last two years. Mainly because server control documentation is very sparse. I usually start doing things the wrong way, then only later learn what the correct way is.

For example: I started out by Response.Writing any custom javascript in the OnRender method. Then later I read that this should rather be done in OnPreRender using Page.RegisterStartupScript.

So little by little my code is improving. However, I've never found a comprehensive MSDN document or website article that explains server control development properly. That leaves me with having to take tidbits from hundreds of websites to put the server control puzzle together.

If anyone can point out a good (comprehensive) server control e-book or articles, I'd be happy to publish the link on a blog post. I'm sure it'll help a lot of developers that make the same mistakes and struggle with the same problems.

posted Monday, May 16, 2005 12:08 AM by willemo

Web vs. WinForms

I believe many people are writing web applications for the wrong reasons. The most common reason for choosing a Web application over a WinForms application is - "with a Web application, deployment and version updates aren't required on the client's computer"

Or even worse - "build a web front-end, because that's what everyone else is doing." How's that for teenage mentality? I've heard this from (non-technical) managers a number of times.

Not having to worry about deployment and updates is great, but that's not a good enough reason to choose Web over WinForms. Giving a WinForms application the ability to update itself is actually very easy. Check out this article on TheServerSide to see how No-Touch deployment, the Updater Application Block and Click-Once(.NET2) can be used. That's not one, but three, different ways to handle automatic updates!

WinForms is such a rich, powerful platform. I think it's really important to use the right technology for the job. If you're writing a Web application only because it's the cool thing to do and it'll take care of updates, think about it… maybe it could do better as a WinForms app?

posted Wednesday, May 11, 2005 7:50 AM by willemo

Enterprise Library

If you haven't heard about the Microsoft Enterprise Library, do yourself a favour and check it out. The Enterprise Library (from now on called the EntLib) is bunch of application blocks that you can use to build your application.

Most applications require some of the same fundamental components. EntLib contains the following application blocks -

  • Caching
  • Configuration
  • Cryptography
  • Data Access
  • Exception Handling
  • Logging and Instrumentation
  • Security

From what I've seen, these things are very (very) well written. Why re-invent the wheel? With these components it's possible to save yourself many weeks of development. Then you can spend time on the business-specific requirements.

However - I'm not 100% comfortable using these application blocks. Why?

Not because they are badly designed.

Not because they are hard to use.

Only because I did not write them. I feel like I would be a failure as a coder if I didn't write these things myself. Will I tell my manager - “Here's the application, but the data access block and that fancy configuration screen is actually a Microsoft thing.” 

It's very difficult to shake this (childish?) feeling. Has anybody else experienced this?

posted Wednesday, May 11, 2005 1:31 AM by willemo

Disturbing Web Page Hacks

I'm no hacker. But in order to write secure web applications I try to get into the mindset of one.

Here's my current challenge: I've got a web application that should allow connections from the internet. It should use forms authentication and run under a specific windows user account. In other words: the IIS application requires “Anonymous Access”.

But... here's the catch - in some instances the application should be able to retrieve the current connected client's username. With “Anonymous Access” enabled this isn't possible, because Internet Explorer won't post the LOGON_USER session variable!

Ok... one way around this would be to write an ActiveX component that can detect the username and put it in a hidden textbox. Then post the hidden textbox value to the server.

Now, a hacker's question - “Can I modify that hidden textbox's value before posting to the server?” That way I can spoof some other user. Unfortunately this is very simple. You can add a bookmark/favorite that will execute javascript! On [this site] you'll find a lot of interesting scripts.

Among other things you can easily do the following -

  • Show hidden text fields.
  • Show contents of password fields
  • Re-enable disabled controls
  • Remove maximum length bound on a textbox

All with some simple javascript. Any monkey can do this. Scary stuff! This is why it's very important to validate on the client AND the server. Luckily this is done automatically using the ASP.NET validator controls.

posted Monday, May 09, 2005 2:26 AM by willemo

Spoofing LOGON_USER

When an IIS web application has "Integrated Windows authentication" enabled and “Enable anonymous access” is disabled, the LOGON_USER server variable will contain the name of the user accessing the website.

I wasn't sure if this method is really secure. Can't the LOGON_USER server variable be modified? These are my findings -

  1. IE will try to authenticate the user by hashing the username and password and sending it to the server.
  2. The server will then compare the hashes to the user on the domain.
  3. If the hashes match, the user has been authenticated successfully.

Note that no passwords are passed directly. Also, because both the username and password are hashed, it's not possible to simply spoof the username. You need the password as well.

Sounds pretty secure to me.

posted Thursday, May 05, 2005 3:57 AM by willemo

Become a better coder

I think most of us want to be better coders. After all, what's the point of doing something if you're not learning and getting better? Here are a couple of ways I think a coder can become a really good coder -

WebCasts
I download WebCasts and view them when I have time. Most of my time is spent in C# files. But I was curious about ISA Server. I've heard about it, but what is it? There's so much documentation out there, so it's hard to get started. A WebCast is like attending a personal training session. It's interesting and focuses only on the necessary details.

Patterns and Practices
Flex your coding muscles by studying some patterns and practices. Patterns are tried and tested ways of solving problems. Why not use them? It also makes architectural discussions much easier. You can say "Use the observer pattern here", instead of saying "Let this thingy monitor that thingy by exposing events in that thingy".

RSS
I'm an avid supporter of RSS. I never start a day without reading my RSS feeds first. Drop a comment if you'd like me to send you my feed list.

Books
Something I haven't done in a while - read a technical book. In a normal working day a developer only works with a limited number of technologies. I've been worknig on the same ASP.NET application for the past 6 months. By reading you expand your mind and get new ideas.

Play
And don't take things too seriously! Make some time to code for fun. It's a great way to learn new things.

In short, becoming a better coder is like becoming a better chess player. It takes a lot of practice, studying and enjoying the process. If you're not having fun, maybe you need some time off.

posted Thursday, April 28, 2005 2:45 AM by willemo

What is "HTML Help Workshop"?

When you install Visual Studio, “Html Help Workshop” is added to your start menu. I thought it was an html tutorial of some sorts.

Wrong! Actually, Html Help Workshop is a CHM help file editor/compiler/decompiler.

It's actually very useful for decompiling NDoc-generated CHM files.

posted Tuesday, April 26, 2005 1:58 AM by willemo

Dont use exceptions, use return codes (?!)

There's a discussion going on at Alex Papadimouli's blog about exceptions. According to an MVP, return codes should be used instead of exceptions (because they are faster). Hmmm.

Most people are saying - don't use exceptions for program flow, only use them in exceptional circumstances. There's a good quote for this - “Don't piss in your pants just to check if your fly is open.” That's what I believe as well.

posted Tuesday, April 12, 2005 6:34 AM by willemo

String Comparisons

In Java you were not allowed to compare strings using the == operator (the == operator would do a reference comparison). So you had to use the Equals() method instead. For example...

if (userName.Equals(”Willem”)) { ... }

Instead of...

if (userName == “Willem“) {...}

That stuck with me. Now, in C#, I always compare strings using the Equals() method. However, according to this acticle, System.String overloads the == operator and calls Equals() internally. Good to have that one cleared up.

On the rare occasion that you really do want to do a reference comparison, I guess you would have to use Object.ReferenceEquals.

posted Tuesday, April 12, 2005 5:43 AM by willemo

Cyrus on Intellisense

Cyrus is Mr. Intellisense. He wrote a very interesting post - When capabilities don't meet requirements, where he discusses two bugs found in the Visual Studio 2005 Intellisense system. A nice read that talks about some of the Intellisense inner workings.

posted Tuesday, April 12, 2005 1:54 AM by willemo

DropDownList SelectedIndex in CreateChildControls

Thank you, Lutz Roeder! After two (frustrating) days I have finally solved my problem by looking at the System.Web source code using Reflector.

Here's the scenario - I have a DropDownList that gets created in a custom control's CreateChildControls method. Lets call the custom control ParentControl and the dropdown MyDDL. I tried to access MyDDL's SelectedIndex from ParentControl.CreateChildControls, but the selectedIndex was always wrong.

That I did not understand at all. When MyDDL is added to ParentControl's controls collection, the dropdown list should play catch-up. Since ParentControl's state is “Loaded“, MyDDL should load its viewstate, load its postback data and set its SelectedIndex, then call its own OnLoad method (don't know what I'm talking about? Check out this post).

The problem - LoadPostData is not part of the control's catching-up process.

MyDDL.LoadPostData is called by the web page itself. The web page has a method called ProcessPostData. This method steps through the postback data and tries to find the related controls by calling FindControl for each postback value. FindControl in turn calls EnsureChildControls. See what I'm getting at? EnsureChildControls then calls CreateChildControls (where we are trying to get MyDDL's SelectedIndex).

The important thing to note is that at this point LoadPostData has not been called on MyDDL yet! So the SelectedIndex has not been set yet.

Congrats to anyone who actually followed this. Usually I am not very good at explaining things :)

posted Thursday, April 07, 2005 7:46 AM by willemo

New Keyword

I learnt a new c# keyword today - continue.

In this code, while i > 10, ProcessTwo() will never be called.

for (int i = 0; i < 50; i++)
{
    ProcessOne();
    if (i > 10)
        continue;
    ProcessTwo();
}

posted Thursday, April 07, 2005 7:20 AM by willemo

ASP.NET 2.0 QuickStarts

This is great. I haven't got round to reading a .NET 2 book or tutorial. So I know that master pages and generics and all that exists, but I don't know how to use them.

Luckily the DotNetTemplar pointed out the ASP.NET 2 QuickStarts(beta). I learnt .NET 1.0 through the original QuickStarts. It sounds like a logical place to start learning about the new stuff.

posted Thursday, April 07, 2005 12:17 AM by willemo

Custom Assembly Path

In a previous post, I mentioned that my ASP.NET Session Variables were getting lost. This was due to the fact that I was deploying 'plugin' assemblies in my bin folder. Because I was altering the bin folder, my web application had to silently restart. Not nice.

One solution to this would be to use a different state management system. SQLServer or StateServer will work fine. However, these methods are not as fast as InProc.

Another solution (in my case), is to specify an alternate bin folder. In other words, I need to tell the CLR to look for assemblies in the normal bin folder, but also in another folder for my 'addin' assemblies. This is done by adding the following section to web.config...

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="AddinBin" />
    </assemblyBinding>
  </runtime>
</configuration>

The <probing> element tells the CLR to look for assemblies in the “AddinBin” folder.

posted Tuesday, March 15, 2005 11:40 PM by willemo

Losing Session Variables

I had a strange problem this morning. My ASP.NET web application used to work fine. Then all of the sudden my Session State started dissapearing. This happened for no apparent reason after a postback occurred.

After looking at a number of forums I figured out what was going on...

I've been working on a 'extensible' web application and deploying 'plugins' to the bin folder. When sessionState (in web.config) is set to InProc, any change to the bin folder will cause the application to silently restart! Thus the loss of Session Variables. Strangely enough the SessionID stays the same.

Apparently this happens on IIS5 and IIS6. I've only tested it on IIS6. 

The solution is simple - switch your session management to SQLServer.

posted Tuesday, March 15, 2005 2:48 AM by willemo

Visual Studio 2003 problem

Visual Studio 2003 constantly kills my event hookups! I add an ASP.NET control, hookup some events, then a couple of days later everything stops working and I see that all the event hookups have been removed. What an insane waste of time!

I'm sure that my computer is pretty solid. It got a fresh install of everything less than a month ago, while this VS problem has been going on for ages. 

I wish there was a service pack for VS2003. One that would solve this problem, all the assembly locking problems (“Could not copy to the output folder...”) and the fact that my HTML always gets re-formatted.

posted Tuesday, March 15, 2005 2:15 AM by willemo

RaisePostBackEvent Oddities

I enjoy writing web controls. However, the last couple of days I've been having a lot of trouble with RaisePostBackEvent. Sometimes, no matter how hard I try, I just can't get RaisePostBackEvent to fire unless I call Page.RegisterRequiresRaiseEvent(this) in LoadPostData.

Other times my eventArgument parameter in RaisePostBackEvent is null. Even if it has been specified and looks perfect in HTML. I've then had to resort to funny code (that checks __EVENTTARGET and __EVENTARGUMENT) to get around it.

When I have to hack to get something working I'm almost 100% sure that I'm doing something wrong somewhere. But with this I am really stumped. Maybe my computer needs a new install.

Update: Problem solved! Page.RegisterRequiresRaiseEvent(this) in LoadPostData was a very wrong way to solve the problem.

The reason RaisePostBackEvent was not being called was simple - the framework will only call RaisePostBackEvent on one control. In my case the wrong control's RaisePostBackEvent was being called. In another custom control I declared a hidden <input> tag with name set to the UniqueID. This is usually the way I go about creating a control that implements IPostBackDataHandler. The framework was getting confused and called RaisePostBackEvent in the wrong control (even though __EVENTTARGET pointed to the correct control).

In this case, the other control did not implement IPostBackDataHandler and shouldn't have included the hidden <input>.

Hope this post helps some poor soul having the same problems.

posted Wednesday, February 23, 2005 5:11 AM by willemo




Powered by Dot Net Junkies, by Telligent Systems