Monday, May 25, 2009

Django is awesomeness (for serious web apps)

Django is awesome.

I shouldn't say that since I haven't built anything substantial in it. But having created 3 or 4 test apps and having read half of the documentation, I'm rather (more or less) confident in that statement.

And they have ponies. Serious ponies. (but where are the pony shirts guys?)
ponybadge

Features I'm already all up in arms about:

Friday, May 15, 2009

Customizing the ASP.NET Issue Tracker

Microsoft's Issue Tracker (part of the ASP.NET Starter Kit package) is old code. But it's free, it works, it runs on IIS6, and it's open source. I probably could have gone with something fancier.

Anyways, right away I noticed that there were a number of usability tweaks that could be made to make the application quite a bit easier to use. Here's a good example...

When you create a new event, by default, the "Owned By" combo box is empty. To me, that doesn't make sense. The majority of the time the owner will also be the... creator! So why not just set the value to the current user automatically when a new event is being created?

If you look inside ~/Issues/IssueDetail.aspx you'll see that the type of control for choosing the Owner is . All of the data bound controls within Issue Tracker are regular Web Forms controls, wrapped in a custom UserControl. By default not all of the properties are exposed, so we'll need to first expose the list items collection by adding this code to ~/UserControls/PickSingleUser.aspx.cs

public ListItemCollection Items
{
get { return dropUsers.Items; }
}

Now that we can access the list items, let's write the code to actually find and select the user.

The most logical place to handle this is on the Page_Load event of ~/Issues/IssueDetail.aspx.cs There's already an if/then handler for if the item is new or not.

if (IssueId == 0)
{
BindOptions();
ctlCustomFields.DataSource = CustomField.GetCustomFieldsByProjectId(ProjectId);
}
else
{
BindValues();
ctlCustomFields.DataSource = CustomField.GetCustomFieldsByIssueId(IssueId);
}

Here's what we need to do: Get the current user's full name, find that name in the databound dropOwned list items, and then select that item.

Issue Tracker already includes a user manager type object built in, ITUser. We can pass it the current page's identity and get the user from the user database.

ITUser user = ITUser.GetUserByUsername(Page.User.Identity.Name);

From there, all we need to do is identify that user in the list item collection, and select it.
foreach (ListItem li in dropOwned.Items)
if (li.Text == user.DisplayName)
{
li.Selected = true;
break;
}
The current user should not automatically be selected as the Owner default when a new issue is created.

The complete code listing should look like this:
// Initialize for Adding or Editing
if (IssueId == 0)
{
BindOptions();
ctlCustomFields.DataSource = CustomField.GetCustomFieldsByProjectId(ProjectId);

// Choose defaults
ITUser user = ITUser.GetUserByUsername(Page.User.Identity.Name);
foreach (ListItem li in dropOwned.Items)
if (li.Text == user.DisplayName)
{
li.Selected = true;
break;
}

}
else
{
BindValues();
ctlCustomFields.DataSource = CustomField.GetCustomFieldsByIssueId(IssueId);
}

Monday, May 4, 2009

HttpModule for easier Master Pages

You know, I just don't like ASP.NET's Master Page feature. The thing is, I've always felt they create more hassle in the long run. Typically, I end up with way too many content place holders. I also really dislike looking at HTML pages which are only a series of <asp:Content> tag blocks.

So here's my workaround: a custom HttpModule that emulates the effect of Master Page without having to actually create and use a Master Page.

How It Works

  • A custom HttpModule is registered in the Web.config file
  • This module catches every request that is of Content-Type text/html (this includes aspx and such) and inserts pre-defined HTML into the outgoing HTML.
Sounds easy right? Yeah it is. I call my creation "Page Master"! (Aren't I a clever one)

Specifics of What It Makes Easier
Generally, I found the only thing I was using master pages for was...
  • Common CSS files
  • Common Javascript files
  • Page header
  • Page footer
Page Master supports all 3 of these, all user-definable in the Web.config file:
<!-- Config for PageMaster Http Module -->
<pagemaster>
<headtag file="~/PageMaster/headtag.html" />
<header file="~/PageMaster/header.html" />
<footer file="~/PageMaster/footer.html" >
</pagemaster>

So, let's say you have a basic HTML page...
<-- HTML page unmodified -->
<html>
<head>
<title>My Page</title>
<body>
<p>Body Text</p>
</body>
</html>

The contents of your "headtag.html" is...
<script src="/js/fake.js" />

With Page Master, the resulting page will be returned to the client instead as...
<-- HTML page after Page Master -->
<html>
<head>
<script src="/js/fake.js"></script>
<title>My Page</title>
<body>
<p>Body Text</p>
</body>
</html>
...without ever having to use Master Pages.

Limitations
Since this was a quick project I whipped up in a couple hours, it's rather limited.

Right now this module only supports static HTML files, but I'd like to expand it to also be able to execute ASPX files, or to fetch a file from another server with HTTP. In case you're worried about performance, the data which is inserted is cached to the whole application, so it's only loaded once, and not every page request.

Another limitation is that it will insert the values for all pages of Content-Type "text/html", and not just the ones you've specified. Perhaps a feature that allows one to configure pages to ignore or not to do that on.

Download Page Master Http Module Source + Test Project
(Hit the 'click here' link next to "Save file to your PC:")

References
Producing XHTML Compliant Pages with Response Filters
Customizing SectionGroups and Sections
configSection Element (MSDN)

  © Blogger template 'Minimalist G' by Ourblogtemplates.com 2008

Back to TOP