Precompile your Web apps

Posted in Uncategorized with tags , , , , on July 10, 2008 by eksith

This gets mentioned a dozen or so times whenever we decide on a launch date for a client site. But it never seems to sink in for some reason. I don’t know if it’s because it’s not considered to be crucial or if people are somehow uncomfortable not being able to read their .aspx files.

There are times you need to include code with your project, but sometimes, consistency and efficiency are more important. Distribute the code seperately!

I know, a lot of people don’t have access to Visual Studio, and others don’t like to use the Express editions for various reasons in certain projects. I’m not excluded in this. I sometimes use Notepad to write quick apps just to save time (or I’m lazy).

Here’s a simple solution:
Create a .bat file in your app directory.
Put this in it..

C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe -p C:\app -v / C:\cmp -u

This line compliles the app with provisions for you to modify it later (-u).

When it’s time to compile your project, just run the .bat file.

There is a detailed explanation of precompilation on MSDN. Replace “C:\app” with the destination of your app and “C:\cmp” with the output directory you want to compile to. Change the framework version first if you are not using 2.0.

A list of available versions on your computer should be under the /Framework directory. If you don’t have a particular version, it should be listed under Windows Update.

The Case Against Buddhism

Posted in Culture, Philosophy, Society with tags , , , , , , on July 7, 2008 by eksith

Warning, will contain foul language and not for the thin skinned.

I had a good chuckle at it. Obviously, he had certain points mixed up, but I thought it was a good effort at explaining some of our own shortcomings.

Note to all Buddhists :
Don’t get offended or injured when someone criticises your beliefs or attacks any of your positions regardless of severity.  Forgive them and move on. If possible, try to educate them in a calm and well collected manner. Do not respond the same way his critics did. It reflects very poorly on our character.

We should find better ways to explain our beliefs or stay silent if unable. Above all else, remember we’re imperfect as well. Before correcting others, correct yourself. You might even learn a thing or two from your critics so don’t dismiss it all out of hand.

Try not to take yourself too seriously, or you’ll pull a muscle ;)

Switchable stylesheets

Posted in Technology with tags , , , , , , on July 3, 2008 by eksith

The amount of time and effort that can be saved by using a single layout and moulding the CSS around it is immeasurable in most cases.

I wrote in detail about my motivations for doing this, but that post only contained a few small examples.

This time, I’ve updated my styles index to include a style switcher to futher demonstrate the importance of using a consistent layout. As long as your HTML scaffolding is not fiddled with, you can completely change the look and feel of a site using CSS alone.

The stylesheets were written in a very specific manner in order to accomodate ASP.NET App_Themes. It is far simpler to create one stylesheet and theme that will incorporate other devices than creating seperate stylesheets for each device and selectively loading them.

This is the most straightforward approach to reducing complexity.

To get your WebParts to accomodate this layout, read my previous post on tableless WebParts and WebPartZones.

These examples make heavy use of the jQuery library.

There are a few minor issues.
The drag n’ drop functionality is a bit shaky, but minimizing the webpart before moving it will solve this.
The minimize icon (plus/minus) will not change after the stylesheets are switched. But they will change once you click on them. This is a very minor issue and I didn’t spend any time trying to fix it. I thought getting the examples up there was more important. Feel free to use and improve.

Once again, these are only rough examples to get the ball rolling. Use them to create your own solutions.

Tableless WebParts and WebPartZones

Posted in Technology with tags , , , , , , on June 26, 2008 by eksith

I think I established why MS web developers have tables tattooed to their foreheads in my previous post on the subject.

Well, here’s my, partial, solution to this. My ultimate goal was to remove as much of the table markup as I can. It doesn’t solve all the problems associated with the bloated markup, but for the most part it cleans it up significantly. You may want to do additional cleanup afterwards, but at least, this will get you on the way.

The following is the basic rendered code for each webpart…

<div id="zoneID" class="webpartzone">
	<div id="partID" class="webpart">
		<div class="webpart_chrome">
			<div class="webpart_title">
				<img src="icon.png" /> Title
			</div>
			<div class="webpart_body">
				<div class="webpart_data">
					Webpart stuff
				</div>
			</div>
		</div>
	</div>
</div>

You may notice that it’s identical to the plain HTML markup from my previous post.
As long as you give a title to your WebPart and give a value to the TitleImageUrl attribute (optional), you should look identical to that.

Now for the WebPartZone…
This is a basic inherited WebPartZone so there is still some table markup. For my project, this was acceptable, but if you can improve it, please do. Post a comment or send me an email with your modifications if you can. This way we can share and solve this mess.

namespace MyApp.UI.Controls
{
   public class MyPartZone : WebPartZone
   {
      protected override void Render(HtmlTextWriter writer)
      {
         RenderContents(writer);
      }

      protected override void RenderContents(HtmlTextWriter writer)
      {
         // Get the current webpartzone
         WebPartZone wpz = this;
         if (wpz != null)
         {
            // Print the current zone ID and css class
            writer.AddAttribute(HtmlTextWriterAttribute.Id,
                        wpz.ID);
            writer.AddAttribute(HtmlTextWriterAttribute.Class,
                        "webpartzone");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);

            // Render the part body
            base.RenderBody(writer);

            writer.RenderEndTag();
         }
         else
         {
            base.RenderContents(writer);
         }
      }

      protected override WebPartChrome CreateWebPartChrome()
      {
         // Return a new derived class to build the chrome
         return new MyPartChrome(this, base.WebPartManager);
      }
   }
}

Now for the MyPartChrome class, which is basically inherited from WebPartChrome. This will be the part of the code that styles the actual webpart itself. If you want rounded corners etc.. on your webparts, this is the code to modify.

namespace MyApp.UI.Controls
{
   public class MyPartChrome : WebPartChrome
   {
      public MyPartChrome(MyPartZone zone, WebPartManager manager)
         : base(zone, manager) { }

      // In case you are rewriting URLs, you need to find the base URL
      private string BaseUrl
      {
         get
         {
            string url = HttpContext.Current.Request.ApplicationPath;
            if (url.EndsWith("/"))
               return url;
            else
               return url + "/";
         }
      }

      public override void RenderWebPart(HtmlTextWriter writer, WebPart webPart)
      {
         // Begin wrapper
         writer.AddAttribute(HtmlTextWriterAttribute.Id,
                  webPart.ID);
         writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         // Begin outer border or chrome
         writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart_chrome");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         // Begin title
         writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart_title");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         //If there's an image url, print that
         if (!String.IsNullOrEmpty(webPart.TitleIconImageUrl))
         {
            writer.AddAttribute(HtmlTextWriterAttribute.Src,
               BaseUrl + webPart.TitleIconImageUrl);
            writer.RenderBeginTag(HtmlTextWriterTag.Img);
            writer.RenderEndTag();
         }

         //Print the title
         if (!String.IsNullOrEmpty(webPart.Title))
         {
            writer.Write(webPart.Title);
         }
         else
         {
            // If your app is localized, use a definition instead
            writer.Write("Untitled");
         }

         // Close title
         writer.RenderEndTag();

         // Begin body
         writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart_body");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         //Write the subtitle if there is one
         if (!String.IsNullOrEmpty(webPart.Subtitle))
         {
            writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart_subtitle");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.Write(webPart.Subtitle);
            writer.RenderEndTag();
         }

         // Begin data (I'm using this because some users may want to
         // have fancy double borders or other custom styles)
         writer.AddAttribute(HtmlTextWriterAttribute.Class,
                  "webpart_data");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         // Print the contents
         RenderPartContents(writer, webPart);

         // Close data
         writer.RenderEndTag();

         // Close body
         writer.RenderEndTag();

         // Close chrome
         writer.RenderEndTag();

         // Close wrapper
         writer.RenderEndTag();
      }
   }
}

You may see that part of the code is cut off toward the ends of some lines, but if you highlight the whole thing, you should still be able to copy the whole code. Don’t worry, the cutoff is in the stylesheet for this blog theme, not the HTML itself.

How to use it

Create two class files in your App_Code folder and drop these in. Be sure to include the following headers at a minimum on top of each class :

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

Now you have two choices on how to integrate it into your pages…
Either add the following to your web.config file :

<pages>
   <controls>
      <add tagPrefix="MyApp" namespace="MyApp.UI.Controls" assembly="__code"/>
   </controls>
</pages>

And be sure to change “MyApp.UI.Controls” to reflect what program structure you have (be sure to change it in the code files as well).
This will allow you to call these classes on all pages.

Or

You can add the following to each page :

<%@ Register TagPrefix="MyApp" Namespace="MyApp.UI.Controls" Assembly="__code" %>

And then call the webpartzone on your aspx page :

<MyApp:MyPartZone id="MyWebPartZone1" runat="server">
<ZoneTemplate>
<%-- Insert web part here --%>
</ZoneTemplate>
</MyApp:MyPartZone>

—————-

Hope you will find this helpful.
I will post code at a future date showing how to use jQuery for drag n’ drop functionality and personalization options instead of the native ASP.NET code.

The code I used on my app runs just fine (with the described limitations). I had to modify it a bit before posting here.
Please let me know if there are any errors.

Update 07/02/08

Finally! No more tables!
The fix to the above code was so simple, I hit myself on the head.
Change the following line in the MyPartZone class :

base.RenderBody(writer);

To this:

this.RenderBody(writer);

Anyone else feel relieved? ;)

ASP.NET WebParts are bloated and stupid!

Posted in Technology with tags , , , , on June 24, 2008 by eksith

Is it just me, or do Microsoft developers have a chronic inability to understand web semantics? I.E. Use markup that makes sense and not abuse it for layout purposes?

Or why else would they insist on baking in tables into every WebPart and WebPartZone? And when I say baked in, I really mean it. It’s so far ingrained that it’s near impossible to strip it bare and still have some meaningful functionality before a deadline.

If you’re starting from scratch using an MS best practices set, forget it!

Even MS’ own semi-thought out mess to fix it, the “CSS Friendly Control Adapters”, are of no help, since they are limited to mucking other controls. If you want to know why I feel this way about the adapters, take a read at one of my earlier ramblings on the topic.

Suffice it to say, if you intend to make your layouts table-free, you may want to overlook WebPart functionality. Unless of course, you want create your own WebParts.

So I have a choice between stripping out everything and implementing my own inherited WebPart controls or simply creating a set of custom UserControls that mimic the functionality. Oh goody!

I may just go ahead and do that and post my code here. Meanwhile, if someone at Microsoft happens to come across this post, I created a demo of how I would like WebParts to behave. And yes, you can make it do what you want without using tables. I’m using my “Nova” theme that I created for my previous, ”Recycle your layouts!“, post.

In keeping with my trend of not double checking any of my code I post here ;) … I put this up within an hour of setting aside a project after I ran into the table issue. There are probably a million different, and better, ways of doing this, but I just wanted to show how WebParts should behave.

Yes, there are glitches. And yes, you may want WebParts to behave differently, but you get the rough idea. I would recommend minimizing the content before moving.

Icons courtesy of Mark James and the Tango Desktop Project.

Now, it’s 1:09am (or 21359.1.9.14 according to the scientific datestamp) and I’m going to bed!