Wednesday, December 28, 2005

Getting Ruby on Rails 1.0 running on Gentoo

After ignoring the advice to use Ruby 1.8.2 instead of the more recent 1.8.3, I got the "uninitialized constant Mysql" error and decided to downgrade.  With Gentoo, this was very easy:
sudo emerge -ua =ruby-1.8.2
ruby --version
# just to verify correct downgrade.
But this didn't solve the "unitialized constant Mysql" error.  So even now I do not know what, if any, problems this solved.

I did solve the problem by applying a suggestion I found on a Gentoo forum:
sudo emerge -a mysql-ruby
Apparently somehow the previously emerged mysql-ruby package was corrupt or something, and re-emerging it was all it took to fix it.

Ruby on Rails is a very amazing framework for writing web applications fast. If I were a Mac developer, I would use Ruby and Rails.  Since I'm a Windows developer, I still use ASP.NET, primarily.

Monday, December 19, 2005

Microsoft Award for Customer Excellence Program

It turns out that the 30+ bugs and suggestions that I filed through MSDN Product Feedback during Visual Studio 2005's beta cycle won me what looks like an acrylic trophy.  It should be "in the mail" at this point.  How exciting!  (I'm not even an MVP -- wish I were!).

I was so happy to see that Microsoft add a bug reporting tool for VS 2005 while it was under development.  I used it tons.  I was amazed at the fast response time that I (usually) saw on it.  A great many bugs I found were fixed for the RTM version.  A few were not.  One of them ghastly.  I can't believe they didn't fix it before the RTM version.  Oh well.

Friday, December 16, 2005

How I find performance bottlenecks in my ASP.NET projects

Have you ever heard of a product called Ants Profiler by Red Gate?  An absolutely phenomenal product for profiling .NET code.  At the time of this writing, it runs at $295, and worth much more than every penny in its price.  I usually try to use free software as much as possible, or write my own.  Somehow writing a check for software hurts me.  But in this case, I recommend it to anyone.  And lest you feel like this is an ad, Red Gate is not paying me for this blog.  Any code profiler by definition does what Ants Profiler does.  I haven't found another product, however, that does it as intuitively as Ants Profiler does it, or throws in as much extra information as it does.

Very Common Scenario for me

I have several ASP.NET web projects that are based on NHibernate.  For the most part the web sites run decently fast.  Where there are problems, I find that enabling lazy loading seems to do the trick.  In one of my use cases, a user will want to download a dataset that has to be put together on-the-fly (or close to it) from several tables, including a table with > 42 million rows -- and all the information in that large table has to go into it.  When the operation took several hours, I blamed NHibernate, or the database server.  I added indexes to the database -- to no avail.  I stuck SQL Profiler on NHibernate to find out what time wasting activities it was doing -- but NHibernate was behaving perfectly. 

I turned on Performance Monitor and watched the CPU of my web server box and my db server box.  I was very surprised to find out that even as it pulled down the 42 million rows, the db server was just idling away while my web server was sweating bullets.  Clearly some code on my part had to be causing a bottleneck somehow.

Then I turned on Ants Profiler.  I ran a small version of the several hour operation.  This one took about 30 minutes.  Ants Profiler pointed to about 5 lines of code that were executing several million times, and taking up (between the several lines it pointed out) about 95% of the time spent in the operation.  These slow operations were things like case-insensitive string comparisons and O(n) array searches.  These may go fast on short strings and arrays, but when they execute several million times, they apparently turn into the bottleneck of otherwise well-tuned code.  Having been shown the problem code, I very easily changed the string comparisons and arrays to hash table lookups and sorted collections.  Having invested a few hours in total to this optimization and having changed only a couple dozen lines of code (at most!), my app is now about 10x faster at executing that operation.  Sweet.

Synopsis

I like coding using best practices and good class models with business objects.  I like my code to be readable.  If I'm coding and I think of two ways to code, one readable, the other optimized, I'll default to readable.  I'll optimize only when I find that that code is what slows my app down, like in the case above.  Using code profiling tools such as Ants Profiler, I can very quickly find that problem code and fix it when I'm about finished with my app. 

Tuesday, November 22, 2005

FreeTextBox 3.1.1 without aspnet_client directory

I have already blogged about how to get FreeTextBox 3.0.x  working without an aspnet_client subfolder with its hundreds of files.  FreeTextBox has seen several revisions since that post, and amazingly they still have not got it right.

I just tried FreeTextBox 3.1.1.  They have it much closer.  Now I don't have to decompile their assembly to fix their obvious bugs to get it working.  But their README file that comes with the assembly and their online installation instructions wiki still claims that with ASP.NET 2.0 you don't have to add httpHandlers to your Web.config file or the SupportFolder="~/FtbWebResource.axd" attribute to your web page.  And it's still wrong, at least for one, maybe both of those points, depending on your ASP.NET version.

So here are the instructions (much simpler than the old ones for 3.0.x) to get your FreeTextBox 3.1.1 working without aspnet_client in ASP.NET 2.0:

  1. Add FreeTextBox.dll to your web application's Bin directory.
  2. If you are using any version of ASP.NET 2.0 prior to the RTM version, add this xml to your Web.config file between your tags.  I experimented and found that even Microsoft's RC version required this next segment, although its RTM version does not.
    <system.web>
     <!-- rest of your Web.config file content -->
     <httpHandlers>
      <add verb="GET" path="FtbWebResource.axd" type="FreeTextBoxControls.AssemblyResourceHandler, FreeTextBox"/>
     </httpHandlers>
    </system.web>
  3. Add this tag to the top of your web page:
    <%@ Register TagPrefix="FTB" Namespace="FreeTextBoxControls" Assembly="FreeTextBox" %>
  4. And this tag where you want your FreeTextBox to appear on your web page.  The SupportFolder attribute is not mentioned as required on the FreeTextBox's installation wiki or in its readme file, but it's still required.
    <FTB:FreeTextBox ID="FreeTextBox1" SupportFolder="~/FtbWebResource.axd" runat="Server"/>

See?  Much simpler than FTB 3.0.x, but still, the FTB claims you can leave out step 2, and part of step 4 (the SupportFolder attribute).  Beware. 

And remember, if you want to test my instructions and remove the SupportFolder attribute, that you must re-save Web.config with each change of your tag to force a web app restart, because FTB caches settings and doesn't notice your changes right away, so you'll be getting some bad tests unless you restart your web app.  Note that this provision only appears to be true in pre-RTM versions of ASP.NET, so this may have been a Microsoft issue rather than a FTB one.

Tuesday, November 08, 2005

Gaining total control of URL rewriting for ASP.NET/IIS (or mono)

More often lately I have wanted to handle "nice" URLs in my web application by forwarding those requests on to their actual URLs. ASP.NET offers HttpContext.RewritePath that you can use inside your Global class (HttpApplication descendant) to change one URL to the other.  But what about those requests that IIS never hands to ASP.NET because no .aspx or similar extension is included in the URL?  This blog discusses what I have recently learned about how to take total control over URL redirection, without any third-party software at all.

The first step is to insert some code into your Global class to check for the old URLs.  This can be done in Application_BeginRequest or Application_Error.  The latter is good for when you only want the special handling to occur after ASP.NET has already tried to find the URL being sought.  If you are expecting these redirected URLs to come in frequently, you probably will want to use Application_BeginRequest.

Suppose you wanted to change all incoming requests for /a.aspx to /b.aspx.  This is how you could do it:

protected void Application_BeginRequest(Object sender, EventArgs e) {
	if (Request.Path == "/a.aspx")
		Context.RewritePath("/b.aspx");
}

You can imagine how to create variants of this to suit your purposes. There are even HttpHandlers that you can write or download, and install in your Web.config file that allow you to declaratively list lots of substitutions using regular expressions.  One such that I know of is available from CodeProject.

For my purposes I wanted to handle only those requests that were not found already by ASP.NET, so rather than Application_BeginRequest, I implemented Application_Error, and it looked like this:

protected void Application_Error(Object sender, EventArgs e) {
	Exception ex = Server.GetLastError();
	if (ex.Message == "File does not exist." ||
		Regex.IsMatch(ex.Message, @"\AThe file .+ does not exist.\z")) {
		CheckForCustomizedStartUrl();
		return;
	}
	DatabaseInternal.Rollback();
	Log.Error("Web application error: ", ex);
}

Notice how I still handle application errors in the traditional way if my URL rewriting fails to find a match.

The shortcoming of using only this method of redirection is that you are relying on IIS calling up ASP.NET to handle the request, which it only does if it recognizes an ASP.NET extension in the URL (like a.aspx).  What if you want to handle requests made to just /a, as in http://www.mycompany.com/a?  Well you could make a directory in your web site called "a", and put a default.aspx file in it.  I personally have far too many (and end user controlled) keywords like "a" to create folders for them all.  So I had to find another solution.

First, let's prepare your web app to handle a spoofed page called 404.aspx.  This imaginary page will invoke the ASP.NET interpreter when IIS calls for it, and rewrite the URL as needed.  Add some variation of this code to your Global class.

private void CheckForCustomizedStartUrl() {
	string appPath = Request.ApplicationPath;
	if (!appPath.EndsWith("/")) appPath += "/";
	if (Request.Path == appPath + "404.aspx")
		CheckForCustomizedStartUrl(Get404RequestedPage());
	else
		CheckForCustomizedStartUrl(Request.Url.ToString());
}

private string Get404RequestedPage() {
	// Check to see if this URL is a customized start URL.
	// This is the case when the URL doesn't end with .aspx or some 
	// other extension that invokes the ASP.NET interpreter. 
	// We have IIS configured to use this 404.aspx page as a 404 page
	// so we can catch these cases.
	if (Request.QueryString[null] != null) {
		Match m = Regex.Match(Request.QueryString[null], @"^404;([^:]+:[^:]+)(:\d+)(.+)$");
		if (m.Success) {
			if (m.Groups[2].Value == ":80")
				return m.Groups[1].Value + m.Groups[3].Value; // Rip out port number if port 80
			else
				return m.Groups[1].Value + m.Groups[2].Value + m.Groups[3].Value;
		}
	}
	return null;
}

public static void CheckForCustomizedStartUrl(string url) {
	if (url == null || url.Length == 0) return;
	// Look for customized URLs coming in.
	if (url == "http://www.mycompany.com/a") {
		HttpContext.Current.RewritePath("/b");
	}
}

Obviously I have some customized code in there already that you may not need, or may need to extend.  The meat of the code is the 404 handler, and how the original URL is extracted from that request.

If you want to process site-relative URLs rather than the absolute URLs handed to you from IIS, you can use these two simple methods I wrote:

private static string MakeRelativeUrl(string url) {
	return MakeRelativeUrl(new Uri(url));
}

private static string MakeRelativeUrl(Uri uri) {
	return "~" + uri.AbsolutePath.Substring(HttpContext.Current.Request.ApplicationPath.Length);
}

Now we need to get IIS or Apache to pass all these not found requests to ASP.NET, even if those URLs don't include .aspx in them.

If you are using IIS, instruct it to send 404 error pages to your custom /404.aspx URL, by following these steps:

  1. Open up your web site Properties box in IIS
  2. Custom Errors tab
  3. Select the row starting with "404" (not the ones that say 404;2 or 404;3).
    Click Edit...
  4. Copy the existing 404 filename to the clipboard.  Open the file in Visual Studio.  It will look like a 404 page your browser displays when you hit a non-existant page.  You'll use this later, so keep this file open.
  5. Back in the "Edit Custom Error Propeties" box, change "Message type" from "File" to "URL"
  6. In the URL box, type in "/404.aspx".  Note the .aspx ending, which will force IIS to start ASP.NET even on those URLs that IIS cannot find on the hard disk.
  7. Click OK on each box until you return to IIS.

If you are running mod_mono and Apache together, getting total control is as easy as "SetHandler mono" in your configuration file.  Suddenly all requests to that virtual host go through the mod_mono interpreter, even .gif and other static files.  When this is done, you can just stick your code into your Global.BeginRequest method and have everything right there.  You don't even need to handle 404's.

I hope you find this useful.  It took several hours of research on my part, and thanks to other web resources I was able to figure it out.  I brought it all together here so you could learn it all at once.

Microsoft 2005 Launch events in Orem and SLC areas

The local .NET User's Group here in Utah County (UCNUG) and Microsoft are hosting/sponsoring three upcoming events.  I'll be hosting/volunteering at both of them myself.  Here's a little piece for them.

Come learn about the new development and server products Microsoft has launched Nov 17 and/or Dec 1 at Microsoft-sponsored events in this area!  Visual Studio 2005, SQL Server 2005 and BizTalk 2006 (beta) all launched on Monday.  These events are FREE and offer prizes to attendees.

Nov 17 @ 6pm-8pm: UCNUG celebrates the launch date with INETA with free food, software and prizes.  A 75-minute presentation gets you started on all that's new with VS 2005.

Dec 1 @ 8am-noon: Best of SQL Server 2005 Launch

Dec 1 @ 1pm-5pm: Best of Visual Studio 2005 Launch

Wednesday, November 02, 2005

Generics and nullables in NHibernate

This is one of the more frequently requested features for NHibernate
Rightly so, for those who are using .NET 2.0.  Once you have
generics and nullable types, it is hard to do without them.  NHibernate Contrib
is the more open project that adds in features that are not stable or
supported well enough to be put into NHibernate itself.  It has
some classes to help with nullable types, but they are not .NET 2.0
nullables, and no generics support exists.


That's why I wrote MyNHibernateContrib
I'm afraid documentation is poor, but I have some unit tests, and I'm
hoping to add better documentation and example code soon. 
Meanwhile, I have a forum set up where users can post questions and
I'll do my best to answer them.  I use MyNHibernateContrib in all
my projects to enable me to use .NET
2.0 generics and nullables.  It does the job quite nicely.  I
hope others find it useful.  It's licensed LGPL.



I use it to solve one other problem popular in the Hibernate world:
parent-child relationships where one of the relationships has to be
inverse='true'.  See, when you establish the parent-child
relationship, you add the child to the parent's collection, and you set
the child's parent reference to the parent.  It's two steps to
create the relationship.  Conceptually, all you should have to do
(IMO) is one of those two and have the other done for you.  It
fits the business object model better (at least for me).  So I
wrote a few new collection classes that implement all the right
interfaces so you can use them anywhere you use normal
collections.  These collections automatically set the parent
reference for you when you add a child to the parent's
collection.  It takes a little extra code in the collection
definition, but writing code that accesses the objects is such a nicer
experience that for me it makes up for it well.  At least until
the NHibernate group comes up with a better solution.

Monday, October 31, 2005

one-to-one mapping bug in NHibernate

I just filed a bug with one-to-one mapping using foreign keys with NHibernate that at least affects version 0.9.1 through 1.0.0. 



If you like one-to-one mappings, please visit the bug, download the
test case (which is a VS 2005 test project) and run it.  Evaluate
it for yourself and if you agree that it is a bug, please vote on it in
NHibernate's JIRA.



Updated 11/21/05: This bug has been fixed and closed.  Thank you, NHibernate team!

Enabling log4net in .NET 2.0

I am just getting into using log4net, and for the most part I like what I see.  It works with .NET 2.0, but it has a couple of gotchas that do not seem to be documented anywhere.  Here they are:

For ASP.NET 2.0 web sites, since there is no longer an AssemblyInfo.cs file, enable log4net by telling it to search the Web.config file for the appender configuration inside Global.asax:

protected void Application_Start(Object sender, EventArgs e) {
	log4net.Config.DOMConfigurator.Configure();
}

For .NET 2.0 class libraries, test projects  and applications, call this same method where your application starts, or in some static method for your test project or class library.

Not a fan of scripting languages

Let me first be clear, that I am not a fan of scripting
languages.  They certainly have their place, but I would never
write an entire application with one.  I wouldn't even write anything that amounts to more than a macro.  I need compile-time errors.  I hate making typos and never finding out about them until runtime, or never.  [6/7/06 update: I feel better about them lately, and might write much more than a macro.]



That being said, among scripting languages I think Ruby rocks! 
The object-oriented nature of it permeates every element.  Even a
fixed number has methods.  Every object is extensible at runtime
as well, and mixins are brilliant.  Not everything about Ruby is
great (it is a scripting language, after all).  But it's cool
enough that I use it here and there.  So I'll blog about the
lessons I learn and the stuff I create.



Lately I've been  working in an embedded Linux lab, writing
software to drive a car with gizmos on it to collect colored balls and
drop them into a goal.  The lab material suggests C.  I
started with C#
, and it worked great.  The problem is that even
though my code was more readable and object-oriented, it turned 20 line
C program into 60 lines.  Sure, most of those lines were reusable
libraries, but I thought it would be hard to sell my teammates on the
larger codebase. 



Then I tried it in Ruby.  I found that the libraries just looked
smaller.  No compilation was necessary (on an embedded system,
that's convenient for debugging when no compiler is on board). 
The biggest boon was the interactive interpreter so that code could be
run on the fly.  So Ruby is how I'll finish this lab.  Cool.

Sunday, October 30, 2005

Community Server is now running

I have been using Blogger to manage my several blogs up to now.  It is really a great engine, but I find I want a little more control and flexibility, so I am moving to Community Server, because it is built on ASP.NET, is free, and comes highly recommended.  Now that it is installed, I realize it is really a massive system that I understand very little of.  Even figuring out how to create this first post was much more difficult than I expected.  There is no tutorial (that I have found) so I have done a lot of poking around to find it. 

As I said I have a few blogs already.  I am in process of copying all the content to this server.  It's somewhat tedious, so the content will appear over time.  The most useful content (on this blog) is already copied over.

Friday, September 23, 2005

How I got FreeTextBox 3.0 working without aspnet_client

[11/22/05 Update: FreeTextBox 3.1.1 requires fewer fixes, and an updated blog on the process is here].

FreeTextBox is a (free) rich text editor control for ASP.NET 1.1 and 2.0. It is pure JavaScript, supports Mozilla, IE, and other popular browsers, and works great (almost). You can add it to your web designer toolbox and just drop it onto a web page and you have rich text editing for free. It's incredibly easy, and the other has done a great job. With the release of FreeTextBox 3.0, the requirement for a very hefty aspnet_client subdirectory was replaced with an http handler that can fetch all of the control's dependencies (gifs, jpgs, js, etc.) straight out of the control's assembly. That means deployment is as easy as copying a single FreeTextBox.dll file into the Bin directory of your ASP.NET web application and you are ready to launch. Swell... except it doesn't work. Not quite.

To get the FreeTextBox control to pull its dependencies out of the assembly rather than external files, its installation instructions claim that with ASP.NET 1.1 you have to add an HTTP handler to your web app's Web.config file, and that with ASP.NET 2.0, you don't. You actually have to modify Web.config for both versions of ASP.NET. Just follow the instructions that they give for ASP.NET 1.1 for modifying Web.config, and your ASP.NET 2.0 app will be on its way to using just the .dll. In my next blog post, I'll talk about enhancing their instructions so your FreeTextBox.dll assembly doesn't even have to be in your Bin directory.

The way FreeTextBox 3.0 comes from their download page, it has a few bugs that get in the way of completely eliminating dependencies on aspnet_client (at least up to version 3.0.6, the current version as of the time of this writing). I'll enumerate them here, and how to get around them. But first, let me prescribe the code you use to try to get it working for yourself, and then I'll list the gotchas that you'll likely run into, and how to solve them.

For the purpose of this blog, I will be assuming that you are following along using ASP.NET 2.0. However, very nearly all (if not all) of the steps would be the same for ASP.NET 1.1.

  1. Modify your Web.config file so that it includes this snippet between the <system.web> tags:
    <httpHandlers>
     <add verb="GET" path="FtbWebResource.axd" type="FreeTextBoxControls.AssemblyResourceHandler, FreeTextBox"/>
    </httpHandlers>
  2. Now open up an empty .aspx page. Add this line just below the <%@ Page ... %>line:
    <%@ Register Assembly="FreeTextBox" Namespace="FreeTextBoxControls" TagPrefix="FTB" %>
    Now add this tag where you want the rich text box to appear:
    <ftb:freetextbox id="FreeTextBox1" supportfolder="~/FtbWebResource.axd" focus="true" runat="Server"/>
    Notice that you must explicitly set these attributes as given. A few hiccups may/will happen, and are listed below, if you don't. For now, just do it. :)
  3. Copy the FreeTextBox.dll assembly that you downloaded into your web application's Bin directory. If you are using ASP.NET 2.0, grab the copy of the .dll that resides in the "bin\Framework 2.0 Beta 2" subdirectory of the downloaded zip.
  4. Start your web application and browse to the .aspx you just created.

At this point, you will either see a working FreeTextBox, or (and much more likely) you will run into one or more of the issues below. Next to each issue is its fix.

  • FreeTextBox improperly caches certain HTML attributes for the life of the web application. If you change attributes in a tag (like SupportFolder or any of the ...Location= attributes), you will typically need to restart your web site/server in order for the changes to actually get noticed. The easiest way to do this is to re-save your Web.config file. You don't need to make any changes to Web.config. Just save it to get ASP.NET to dump the web app and reload it, effectively dumping FTB's cache.
  • Failed to map the path '/aspnet_client/FreeTextBox/Languages/en-US.xml'.
    This comes up when you haven't set the SupportFolder attribute to point to your .axd handler. Be sure to work from the snippet I include above, with emphasis on the SupportFolder="~/FtbWebResource.axd" attribute. And remember to re-save Web.config so that the new attribute will be noticed.
  • FreeTextBox has not been correctly installed. To install FreeTextBox either:
    1. add a reference to FtbWebResource.axd in web.config:
      <system.web>
       <httphandlers>
        <add verb="GET" path="FtbWebResource.axd" type="FreeTextBoxControls.AssemblyResourceHandler, FreeTextBox"/>
       </httphandlers>
      </system.web>
    2. Save the FreeTextBox image and javascript files to a location on your website and set up FreeTextBox as follows
      <ftb:freetextbox id="FreeTextBox1" supportfolder="ftbfileslocation" javascriptlocation="ExternalFile" toolbarimageslocation="ExternalFile" buttonimageslocation="ExternalFile" runat="server"/>

    This is the most fatal flaw in FreeTextBox, and it's the one that ultimately trips most people into giving up. The error lies in FreeTextBoxControls.Resources.JavaScript.FTB-Utility.js, one of the javascript files that are embedded in FreeTextBox.dll. This file exists in the aspnet_client directory (that we're not using), and oddly it's not the same file. And the embedded file has two typos in it that keep the browsers from parsing it, resulting in this error. The fix is not too difficult, honestly, but it's the pits that it has to be done. Keep in mind to, that this fix probably can't be redistributed because of copyright laws. So fix it for yourself, and anyone else who wants this fix should download the control themselves, and then come here to patch it themselves. Here's the fix:

    1. Copy your FreeTextBox.dll from your web app's Bin directory to some temporary and clean directory. For this example, I'll assume c:\temp\ftb. When you download FreeTextBox, 3 versions of the FreeTextBox.dll are included (for some reason). One is for .NET 1.0, another for 2.0, and another one that isn't labeled. Work with the one in the 2.0 directory. At least that is what I did, so I know it works.
    2. You'll need the .NET Framework SDK for this step, but that comes with Visual Studio, to access it from the command prompt, navigate through your Start menu to your Visual Studio 200x group, and then deeper into the "Visual Studio Tools" group. Launch "Visual Studio 200x Command Prompt". This opens a command prompt with the PATH variable set so you can use the SDK commands easily.
    3. Change to the temporary directory you created with FreeTextBox.dll in it.
      cd \temp\ftp
    4. Decompile the FreeTextBox.dll assembly. We need to fix the embedded .js file within it. This is how you do it:
      ildasm /out=FreeTextBox.il FreeTextBox.dll
      You should now have hundreds of files in your little temporary directory. These files all make up what you will eventually recompile into your patched version of FreeTextBox.dll.
    5. Keep your command window open. You'll use it later.
    6. Using your favorite JavaScript editor (Notepad does just fine), fix two lines in FreeTextBoxControls.Resources.JavaScript.FTB-Utility.js:
      old line 14: for(var i = 0; i < arguments.length; i++){
      new line 14: for(var i = 0; i < arguments.length; i++){
      old line 35: for(i = listEvents.length - 1; i < = 0; i = i - 1){
      new line 35: for(i = listEvents.length - 1; i <= 0; i = i - 1){
      These changes are to change an HTML representation for the less-than sign to the sign itself, and to remove the space between <= that shouldn't be there.
    7. It's a really good idea to increment the version number of the assembly you're building. Otherwise, .NET thinks that your assembly is identical to the old one, and won't trash the old one in its cache with your new one, and the bug won't go away. Modify 1 line in FreeTextBox.il to increment the version number:
      old line 2251: .ver 3:0:6600:6
      new line 2251: .ver 3:0:6601:6
    8. One optional change can be made in FreeTextBox.il while you're there. It's a shame that the SupportFolder="~/FtbWebResource.axd" attribute has to be manually added to every FreeTextBox tag you drop into a web page. Change these few lines in your .il file to fix the default value so you don't have to: 35305, 18049, 17992. Don't mess with the IL hex code--just the string. Below is an example of the change.
      old line 35305: IL_001d: ldstr "/aspnet_client/FreeTextBox/"
      new line 35305: IL_001d: ldstr "~/FtbWebResource.axd"
    9. In the command window you used to decompile, recompile the FreeTextBox.dll like this:
      ilasm /dll FreeTextBox.il /output=FreeTextBox.dll /quiet /key=yourkey.snk
      You'll need to have your own strong name key. You can generate one with sn.exe -k yourkey.snk
    10. Copy your new FreeTextBox.dll assembly to your web app's Bin directory. This change to Bin should automatically cause ASP.NET to restart the web app, so just refreshing your browser should now eliminate the error that was displayed initially. Yay!
    11. One note: if you've already been using the GAC to store FreeTextBox, you'll need to add your new assembly to the GAC and adjust your Web.config and .aspx files to point to your own version of FreeTextBox before you'll see the fix. If you didn't follow that, don't worry about it. Read my next blog when it is published.

    So that's it. That should get it working for you. Please post a comment below either way. Let me know if this has helped, or if there are other bugs/issues you've run into, including their fix, if you have it. I'm not an expert on FreeTextBox, but seeing as the author of it doesn't seem to be responding to any forum messages and isn't updating his installation wiki to be correct, let's make this blog useful for everyone!

Wednesday, September 14, 2005

Someone responded to my recent post...

Someone responded to my recent post, and made some good, and some poor comments. This is in response.

"Uhh… install it and choose KDE as the default session the next time you see a login screen. Not really hard. To install KDE is just as easy - open up a terminal and type “sudo apt-get install kde”."

Maybe that works in Debian, but I use some less-well-known *cough* distros: SuSE 9.3 Pro and Gentoo, and installing KDE after Gnome, or vice versa, has RARELY added the new screen manager to my login screen. It has occurred, but as a rule, I have to reinstall the whole distro and select both in order to get both to show up on the menu. Am I a moron after all? Hmmmm... I think the distro is misbehaving. But that's my point. It's not (always) as easy as it is for the developers. If it works for the developers and most users, that apparently doesn't mean it works for everybody.

"Press on the little update notification on your panel and have all of your apps updated (not just the OS itself). Now that’s incredibly hard, you are right."

I've seen that icon on some distros, yes. But not all recent ones make it that easy. However, I'll submit that some distros make it as easy as Windows does, and yes, having it work for (some/most) apps plus the OS rather than just the OS is a huge plus.

"About your other drivel. You are aware of sudo and acls, aren’t you?

And you are aware that you can share folders on modern linux distros by simply clicking, just like you described for windows?"

Oh please. Did you even read that paragraph, or did you just skim it? I know you can share with Linux. I mention ACLs myself in that blog. Duh. Someone's not reading. (I'm only being blunt because you take no pains to avoid it. I can hear you now "well you started it" Ha ha. You'd be half-right. Actually I point at the original article poster). Are ACLs easy in Linux? I've not seen a single distro that makes it so. Are they pervasive throughout the OS and apps? No. Can the average Linux user, with their window manager, or even at the prompt (AVERAGE user, I say) share one file with one friend, without sudo privileges? I don't know that it's even possible, but I'd love it if you could SHOW me that it's so easy your mom could do it.

"To sum it up, your blog entry is probably one of the dumbest things I have read recently. Not one good point, only senseless drivel."

You only addressed 4 or 5 of the many points I made. Are you out of breath? Some of your retorts have merit. The biggest one is the update process. But to make poor return arguments about window managers not updating the login menu properly, or ACLs that are inaccessible to most people, that just shows either your obsession of Linux or how clueless you are that not everyone knows the inner workings of Linux like you do, and to wrap up by saying my blog was "one of the dumbest things [you] have read recently" sounds pathetic.

Finally, to qualify what I mean by "the average user" or "most users". Have you ever walked into a regular business, or home, and seen the way most users work? They pull up Excel and know about 5 commands: open, save, bold, italics, and center. I'm exaggerating slightly here, but if you DON'T know what I'm talking about then you've been in your system admin den too long and need to get out into the light.

Thursday, September 08, 2005

Mono on embedded Linux

I am working with a TS-5500 embedded system for the first time, equipped with a PCMCIA slot, an Ethernet port, and a CompactFlash slot, which is used for a 64MB flash drive. We downloaded an image of embedded Linux on the card. This was part of a class to write an AI, self-navigating car in the C language to run on Linux. But being a .NET/Mono and C# fan myself, I wanted to try my hand at building Mono for embedded linux so I could write the AI code in C#.

The "hard drive" flash card only has 64MB, as I mentioned. The embedded linux system did not come with compiling tools either. So all development for this system had to be done in a development OS environment, which when chroot'd into allows one to build programs that can then be freely copied onto the embedded system that can run. Mono would have to be built on a traditional Linux system, inside that development OS area, and installed to some special location that I could then use to copy the installation directory to the embedded device. I crossed my fingers that it would be small enough to fit on the CF drive -- or I'd be buying a bigger one.

I downloaded the sources to Mono 1.1.8.3 and read the README file. I have built Mono several times before on other varieties of Linux, but because embedded linux has so many stripped out features, I was curious about the dependency list. I was pleased to see only two dependencies, both easy to get: glib and pkg-config. The other nice part about the dependencies, at least as it sounded from the README file, is that they were only required to build mono, not necessarily to run mono, which would help keep the size down on the embedded system. One other dependency was required for me, that wasn't listed, because the embedded system didn't have /dev/random, which was required to build
mono. I didn't know how to add /dev/random to this distribution of Linux, so instead I downloaded the alternative, egd. I'll discuss each of these dependencies and their gotchas next.

Each dependency's source code had to be downloaded as a tarball, moved into the development OS directory and extracted with tar xvzf some.tar.tgz, all from outside the development OS environment, meaning without chroot'ing to it. Then chroot'ing into the environment, I built each package with the standard ./configure && make install.

glib would not build because of a gettext dependency. After Googling on the text of the compile error, I found that gettext isn't actually required by glib any more, so its detection within its configure script could be safely disabled. Opening glib's configure script in vi, I searched for "You must have either have gettext support" (double "have" intended), and then modified the "if test" line above it from: if test "$gt_cv_have_gettext" != "yes" ; then to read: if test "$gt_cv_have_gettext" = "XXX" ; then, which essentially disabled the check. glib built and installed without any more trouble.

Once pkg-config and glib were installed, I found building mono still failed, due to /dev/random being missing. I had a /dev/random in my native Linux, which happens to be Gentoo, but inside my chroot'd environment from which I was building mono, no /dev/random was provided. After Googling on the compile error text, I found that last year the mono group wrote a random generator substitute that tied into egd, which I later found out was an entropy generator, good for random numbers. Google Linux helped me find the sources to egd. egd requires Perl, which fortunately
the embedded system already had. Although egd claims to not require an install, I did so anyway, which added SHA support to my system, which seemed to be necessary. Running egd.pl /tmp/entropy after that started the entropy-generating daemon, and set the socket to be at /tmp/entropy. Finally, an environment variable had to be set so that mono's install could find egd as the substitute random number generator: export MONO_EGD_SOCKET=/tmp/entropy.

Finally I could build mono. I set the prefix directory (the directory to install to) to /src/dest, which was empty at that point, so that I could copy /src/dest into / of the embedded system and effectively install mono. Time would tell if that worked.

./configure --prefix=/src/dest
make install

I ran into this error "error while loading shared libraries: libgthread-2.0.so.0" during build. The solution was to set the LD_LIBRARY_PATH environment variable so that the mono compiler could find its dependencies.

I also ran into this error "Unhandled Exception: System.Security.Cryptography.CryptographicException: Couldn't access random source.", which is how I found out that /dev/random is needed, and how I eventually came to the workaround discussed earlier in this blog.

Another error I ran into was that after chroot'ing into the development OS, the /proc filesystem was unreachable from the inside of the development OS. A /proc directory existed, but was empty. So solve this, I had to mount the /proc directory inside the development OS before chroot'ing into the it: sudo mount -t proc none /home/mech/ts5500devOS/proc

So after all these steps, make and make install succeeded. Hurray!

I quickly switched to /src/dest and ran a du -hcs to find out how much space mono wanted to take for install. 86MB. Rats. That's way too big. So I sorted through the directory, removing large libraries and executables from the mono installed directory that I didn't think I'd be using on the embedded system. I got it to 11MB, and my Hello World app still runs on it (though I removed the compiler).

All comments are welcome. Let me know if you found this useful!

Monday, August 29, 2005

Five reasons NOT to use Linux

This blog was copied from my old blog location.  Lots of comments are there, so comments are not allowed here to help them stay all in one place.


This is in response to the sarcastic and blind-sighted Five reasons NOT to use Linux.

I expect you have already read that article in each of my rebuttles below. In fact, maybe read one section there, and then the corresponding section here.

Reason number one: Linux is too complicated

Indeed!

Steven claims in his article that it's Windows GUI vs. Gnome/KDE, Registry vs. configuration files, and that's that. Oh, except that if you screw up the Windows registry you risk wrecking your computer. Let's help make that comparison more enlightening...

Linux configuration files: they are all in different formats, and follow different rules. (case sensitive? headings? comments? whitespace significance?) Very often configuration file changes do not take affect until you restart whatever program you are configuration. Take a look at Apache. A server widely acclaimed for its up-time, and yet you can't even change a single setting without restarting the server! Compare this now with Microsoft IIS. A nice GUI that lets you change almost any setting or add an entire web site with a few clicks and you're already live. No restart, no downtime. And you don't need a fat "Apache Unleashed" manual for IIS to figure out how to do this or that.

Suppose I install Gnome as default and want to install KDE and use that as the default. How easy is that? Well, every time I try, I have to search through several configuration files with 100s of lines to find the one that specifies the default GUI, and then it often doesn't even work.

Reason number two: Linux is a pain to set up

True, if you buy SuSE Linux on DVD at the store, you can drop it in and have it all set up for you. Windows XP brags about the same convenience and ease. How many patches must you apply to SuSE right after install for all the security fixes? Dozens. Windows? Dozens. Hmmm... Seems about even there. To be safe, you ought to be behind a firewall in either case. I've never found a recent Linux distro that didn't have patches ready to install as soon as I finished installing to OS.

Reason number three: Linux doesn't have enough applications

Let's compare apples to apples here. Windows is an OS, not a set of applications. You Linux fanatics get on Microsoft for bundling apps with their OS, and then here you get on their case for their lack of apps. So I won't even address the software bundled with each OS, since that is not comparing the OS but the packaging, which can easily be changed for either OS. Let's use our time wisely by looking at apps available to be installed later.

Virtually every app available for Linux has a Windows counterpart. The reverse is also true. But the fact of the matter is, you open-source Linux fanatics choose to ignore this. OpenOffice is as much available for Windows as it is for Linux. So is FireFox. So are so many other apps and games. And if you can name an open source app that isn't available on Windows, before you accuse Windows of being worse for it, ask yourself these questions: Windows as an OS isn't inferior just because your open source app doesn't run on it. If you are so big on choices and freedom, why don't you write your app to run on both? And as far as Windows' extensibility and flexibility, I've studied the Windows API enough to know you can twist and bend Windows to do almost anything, through binary means. If you think Linux is more flexible because you have access to its source code, you'd be right, but 98% of the users out there don't care. They won't recompile a thing on their own. They just want a friendly, adjustable OS. Linux doesn't provide that. Windows does.

Finally, the price you pay for Microsoft Office is worth the money, if your time is worth anything. So is a lot of other software that is "proprietary" and "closed-source". They have the money due to their customers to pour into usability testing and fine-tuning their products where open-source developers just don't care or don't see a need, leaving their users frustrated and unproductive. OpenOffice 1.1.3 was a nasty piece of work on the GUI side. Every person I suggested to switch to OO to save money ended up buying MS Office within weeks because they hated the interface. I remember a quote from openoffice.org once going something like this: "we're not trying to look like MS Office... we don't want to". Well well. I think OpenOffice 2.0 is a huge improvement in the GUI over 1.1.3, and guess what! It looks much more like MS Office than it ever did. Who's copying who? Linux-lovers keeps accusing MS of lacking innovation. Excuse me, but the open-source community wrote Apache from standards they didn't write. [Edited 8/30/05: A comment below enlightened me that the author of the original HTTP spec actually did write much of Apache] They copied Java and .NET that closed-source companies invented. They copied Unix to make Linux. They do almost nothing but copy. Who's lacking imagination here?

Reason number 4: Linux isn't secure

This is the one that makes me the most upset. I've already mentioned that Linux and Windows both have need for security patches. And frankly, applying patches in Windows is easier than in Linux. Linux is pretty easy, but Windows is still ahead, I'd say. Argue all you want. But a properly configured Windows box will successfully apply patches to itself better than a Linux one will. At least for me. And if you disagree, just know that most users don't know how to configure Linux like you do, and so your opinion doesn't matter to 98% of the computer users out there.

But here comes my big beef with Linux security: it's user accounts and permissions. First I'll talk user accounts. In all my conversations with Linux admins, I've never met one with a system configured where they didn't "su - root" to do admin stuff. All administration functions in Linux, whether they technically have to be or not, are done through "root", rather than specific, personal user accounts. Who cares? Well, logs for one thing. While Windows may currently encourage all user accounts to be administrator accounts in order to install software and such, at least those accounts are all seperate, and you can see who did what when. You don't have that when all Linux users change to "root" when they want to get something administrative done. Again, I'm not speaking of technical possibilities in Linux here, but what the trend is. With Windows, most people have their own administrator accounts. With Linux, they all use "root".

Now onto permissions. Let's say I'm common user A, without root permissions, and I want to share a file with user B, also a regular user. How can I do this? Well, I can open my file up to everyone (chmod 777), and that'll get the job done. That's stupid. I just want to share my confidential file with user B. Hmmm... My only other alternative is to share the file with the owning group. Oops, I can't do that either, because the owning group for the file is "users", which all the users in the system belong to, and that would expose my file too much. I could create a group.... err, no I can't, because I don't have root priviledges. Any other possibilities? I could move my file to a special directory that an administrator created for sharing files, but what are the odds of a directory already existing for sharing files with just this one other user? About nil. Now let's say I have root priviledges. I can create a group, make the owning group for the file the group I've created, and then share the file with the group (chmod 770). All good, right? Wrong. Suppose I want to share the file with user B for read-only access. Fine: chmod 750. But now I want to share the file with user C for read-write access too. Impossible. While I can add user C to my custom group that owns the file, I cannot give B read-only access and C read-write. I know Linux brags support recently for ACLs. My question: Where are they? They are so new (though Windows has had them since 1995) in Linux that no GUI interface I've seen supports setting/viewing them, and no command line "ls" will show those advanced permissions. All you see is rwxrwxrwx or something like that. Pitiful.

Compare to Windows.

User A, who may have nothing more than basic user priviledges, can simply right-click on a file, click Properties->Permissions, and share the file with whoever and however they like. Extremely fine-grained control over any file/directory you own. What can be more secure than that? It's so simple, and so uniform throughout NTFS that every app knows about it.

Reason number 5: Linux is more expensive

Linux is cheaper if any of the following is true:

  1. You are a Linux admin over more than one server, and licensing costs for Windows Server are prohibitive for your business.
  2. You are a Linux enthusiast who can be unusually productive in a less refined GUI environment. You types are definitely out there, but you are not the common user!
  3. You are building an embedded system.

For the common user who just wants to be productive, and just wants their computer to work the way they want, Windows is faster, and faster means cheaper! Linux is only now getting the power management capability to Hibernate, which Windows has had for 5+ years. Plug-n-Play has been around for 10+ years, and Microsoft has worked out so many bugs in it that it works almost all the time. Linux: just getting support for it, and it's very spotty. The idea is Linux is "only just getting there" in so many areas that Microsoft has mastered over time. Yes, Windows has certainly had it's problems. But the point is, Microsoft has learned, and continues to learn from their mistakes. Linux is learning from Microsoft's mistakes too. Is Linux progressing faster than Windows? Certainly. The road is always quicker for the second traveler. Is Linux better than Windows for the common computer user? Certainly not. And I daresay for most computer programmers the tools available for the Windows platform make them more productive than most Linux developers. That's because Linux die-hards are so religiously attached to C that they won't embrace newer, high-level languages that make them more productive and encourage safer code. And then you have the other extreme: those Linux developers who use Perl and Python, which are so slow that any intense computation requires you to drop into C.

Summary

Ok, so I've jumped off topic some in each of these sections. But because I suspect most of you Linux users reading this article are programmers (since you programmers make up most of the Linux user base, for reasons mentioned above), I took opportunity where I could to digress into other beefs I have with Linux.

I use Linux. I find it helpful to use in several use cases in my regular programming routine. Personally, I think IIS' FTP functionality is pathetic and embarrassing. I use a Linux SSH server for all my file transfers, and Samba to move them up to my Windows Server. I use Linux for lots of other things too. And yes, once you get Linux running exactly the way you want, I agree it has a higher probability of staying online than a Windows Server with similar configuration. But it's the getting it set up initially that takes so long. If Windows Servers are more hackable, it's because they are easier to set up, so less-educated admins do the installs and fail to configure them securely. As a non-diehard Linux user myself, you could probably hack into my Linux server too, if you wanted to.

It's about who the operator is. Linux is good for a few people. Windows is good for the masses. That's why the software distribution is the way it is. I personally like free software, because it's free. (I don't like the GPL, by the way, as it comes with huge obligations that the LGPL and X11 licenses don't impose). I think Linux definitely has a large place in the world, and I think its space is growing. I'm excited about its future. But I would most like to see the Linux enthusiasts stop looking at Linux and open source religiously and start looking at them as tools. Recognize their shortcomings and work on fixing them instead of always pointing fingers at how weak Windows is. If you don't like something about Windows, why don't you take a few hours and write software to fix Windows?? You certainly don't mind doing that for Linux! In short, take your blinders off.

Sunday, July 24, 2005

NHibernate applied to EMAR

I have completely torn out the OPF I wrote behind EMAR and replaced it
with NHibernate. I anticipate that EMAR will be much faster and stable
as a result. Already I am floored by how simplified this transition
made my business objects. They almost never consider that they are
being persisted at all, and most of my unit tests never touch the
database, but rather instantiate the classes in memory to see them
behave.



I have planned previously to make EMAR available through the LGPL open source license.
That is still planned, but with the recent transition to NHibernate, I
thought it best to delay the release for a few months while it was
revamped. This is because the new one would be, and now is, so much
simpler than the original that I was going to release, that it didn't
make sense to release the first version.



I need a new name for EMAR, I think. Any suggestions?

Thursday, June 09, 2005

NHibernate rocks

NHibernate rocks. I've
been investigating it these past few weeks as an alternative to a
custom object persistence framework I wrote before NHibernate had
matured. Well, it has matured much, and I am eagerly trashing all my
own OPF in favor of the much better NHibernate. Way to go, you open
source developers who have contributed!



It does have some
shortcomings still, and later in this blog I will discuss the best way
I have found to workaround the lack of support for generic collections
that come with .NET 2.0.

Wednesday, May 25, 2005

IASSIST conference

So I have an opportunity to attend an IASSIST conference in Edinburgh. How exciting! BYU's College of Family, Home, and Social Sciences paid my way to demonstrate a software product I wrote for them. Many, many thanks to them for giving me this opportunity, and allowing me to share with the world what they have sponsored.

I wrote several web sites to collect survey data over the web and present respondants with immediate reports of how their responses fit a norm, and acceptable levels for marriage with another respondant. After coding the same things (and debugging) over and over, I decided to write a reusable engine that does all the work, and more, and can share the code across all the web sites. This engine uses DDI as its core questionnaire schema to define a codebook that the questionnaire is rendered from using XSLT.

The code for this surveying and reporting engine can be shared with the world, and shortly will be through a customized open source license. I am not what I would call an open source freak, or even fanatic, but I see it's place, especially in the academic world, and I'm eager to share this, because I see it as very useful generally, and I don't want to take the time to market it. I'll post here again when it becomes available. Probably on Novell Forge.

I have already put up a web site where BYU professors can post surveys very quickly and easily and begin collecting data over the web immediately. Soon I hope to put up a site generally available to all universities at http://www.collegestudies.org. It's not there yet though.

Tuesday, May 10, 2005

UCNUG gets a new URL

I am vice-president of the Utah County .NET User's Group (UCNUG). Enjoying the role I play there. The UCNUG site has been revamped and replaced. So long to MSN Groups! Hooray.

Tuesday, May 03, 2005

Betas 2005 Unleashed

Microsoft has been working hard on the next generation of development tools and database technologies. Visual Studio 2005 and SQL Server 2005 are two of the most anticipated technologies to be released by Microsoft this year.  There are many changes in both Visual Studio 2005 and SQL Server 2005 that promise to make it easier to develop high quality code. Come attend this day long event where we will drill down into some of the new technologies in both Visual Studio 2005 and SQL Server 2005. We will have two tracks that will cover the major features of each product.

Date: May 18th 2005 – 8.30 am – 5pm (registration and breakfast starts at 7.30)


Venue: Miller Free Enterprise Center (http://www.slcc.edu/miller/Buildings/Building3.htm)

SLCC-Miller Campus
9750 S 300 W
Sandy, UT 84070


Registration: Please register at the following link http://msevents.microsoft.com/cui/eventdetail.aspx?culture=en-US&eventid=1032273553

Visual Studio .NET 2005 Track:

The release of Visual Studio 2005 and the .NET Framework 2.0 will make strides in all dimensions of application development. Visual Studio 2005 will set a new bar for developer productivity by tailoring the software development experience to the needs of the individual developer. This "personalized productivity" will deliver features across the development environment and .NET Framework class libraries to help developers overcome their most pressing challenges in minimal time.

We have put together a comprehensive training for free to help our customers understand the power and value of Visual Studio 2005. This session will cover the core features of

  • Web Development Platform - ASP .NET 2.0
  • Smart Client Development Platform – Windows Forms, Mobile Development
  • Visual Studio Team System

SQL Server 2005 Track:

SQL Server 2005 is the most anticipated database release in Microsoft’s history. With significant improvements in the areas of infrastructure, development, and business intelligence SQL Server 2005 represents a huge leap forward for a wide variety of applications.

As we get closer to the launch of SQL Server 2005, we want you to have a full appreciation for what this powerful platform can do for your database projects. As such, we’ve put together a free in-depth developer training event and invite you to take advantage of this opportunity.

  • SQL Server Developer Platform – SQLCLR, TSQL Enhancements
  • Business Intelligence Platform – Reporting Services, Analysis Services, Data Warehousing
  • Infrastructure Platform – Availability, Management, Database Mirroring

Thursday, January 20, 2005

VP of UCNUG

I recently became the vice-president of the Utah County .NET Users Group [10/30/05: updated link].
I've come home with the new Visual Studio 2005 Beta software, and many
new ideas for projects or implementing existing ones. Quite excited.



Some
of the projects I am currently working on I will begin to discuss on
this blog, including links to Subversion servers that host some of the
more generic but useful projects I am working on. Projects to be shared
(probably through LGPL) soon:


  • Schema Translator - Reads
    detailed database schema from SQL Server to produce a DataSet. Also
    takes a DataSet and writes the DDL to recreate the database.
  • Safari Database Tools - DataSet metadata diffgram.
    That is, it can compare two DataSet object structures and construct a
    object tree describing just the differences between the two DataSet
    objects. Finally, it can work with the Schema Translator to write DDL
    to apply the differences in the database schema to a SQL Server
    database.


These two projects actually have a very
plug-in friendly way of allowing other databases besides SQL Server to
be used as backends.



I'm excited to get these out and have people comment on, benefit from, and contribute to the projects. I'll keep you posted.