May 2005 - Posts

Not what I know now, but what I'm learning now. I recently picked up a copy of the src to FlexWikiPad. I just wanted to see how things were wired together in there: I only have a very old installation of FlexWiki sitting around that still looks like crap in FireFox.

To his credit, Craig has done an awesome job of making FlexWikiPad very testable - something I didn't think was all that easy to do in winforms. Apparently, his dialogs are very humble. He's using a pretty strict Model View Presenter (or controller, whatever) pattern throughout the application. I thought this was a lot of extra coding at first (it kinda is), but in the process Craig has made FlexWikiPad easier to maintain and update thru the use of mocks/stubs and tests with this pattern.

Currently, I've got this itch that I want to scratch with regards to PostXING that would have been so nice to be able to test my way thru. I'm just hacking thru it now, and I've done a pretty good job of messing everything up so far :) In my defense, I'm still learning unit testing and when it comes to winform applications I feel that there is a balance that I like to hit right on the line of usability and architectural beauty. Anyone who has looked at PostXING's source will soon see that my architectin' ain't so purty - it's still just a lot of different pieces from different places glued together. I don't validate everything that I should. I left fields that I intended to add functionality for disabled but visible. Even up to 1.1 versions. BUT...

...and this is a big but...

...it works. That was priority #2 for me with PostXING. Priority #1 was to make something useful that I could use to learn winforms.

Anyways, I'm hoping that I can glean some insight off of people like Craig that are way more knowledgable than me on this front. If I feel like the task for PostXING to be testable is too great, I may just try to apply this knowledge to future projects. So, thanks Craig for making FlexWikiPad follow a concise pattern that I did know about but have never seen implemented with tests in C# before.

It seems that there was a major power failure yesterday: at least a few city blocks. For those that don't know, a city block in Houston is a pretty big area.

Looks like it's fixed for now, so the two of you can go about getting that there rss feed :)

[ Currently Playing : Karma Police - Radiohead - OK Computer (4:21) ]

Not this one, my "personal blog" that lives over here. (This blog only gets technical content cross-posted from that one - the other one gets everything(except this post).)

 We had power outages all day yesterday and I'll betcha that my server has powershooted offline. Heh, hosting your site on your own hardware has its advantages, but it also means that thanks to this little brown out, I'm nowhere near the coveted 5 nines.

The bad news is that my company's website is hosted on location as well. guess I'll be going in early today :)

I.e. Both of you...I've changed the repository structure of PostXING on vaultpub to better facilitate branching.

These crazy new ideas I've been having are so different from the current architecture of PostXING that I have to branch it just in case someone comes to me with a nasty bug they found that I just overlooked (this has happened a few times already, although not for a while). I don't like having broken software with my name on it out in the wild.

Anyways, I thought I would keep tabs on my progress for this on my blog. I feel like there is something that I'm missing in the ideas that I'm having, so I'm taking this slowly, step by step. To be honest, I've always had this idea in my head for PostXING. It's why it's built the way it is - I've left extensibility points open at the expense of writing a bit more code on the onset. When I'm done, a developer that has a good handle on the API they want to post to will be able to author a plugin/provider, drop it into a subdirectory off of the application root, and be able to use PostXING as kind of a shell to post to their custom API.

[ Currently Playing : Sad Statue - System of a Down - Mezmerize (3:25) ]

Thanks to Sir Wally for the first one...it's simple really, Wally just asked if I would cache a list of the categories for each configured blog to aid with offline posting. I pretty much always use PostXING while online, so this particular feature didn't even cross my mind. As a side effect, this will let me add categories to posts off of my CS blog which gives a nice little error when I try to get the comments list currently. Good one, Wally.

The other thing is that I want to expand the abilities of where PostXING can post - not just using the Metablog API, but being able to use different services. I don't want to use the "provider model" because I don't think that particular pattern fits what I have in my head to make this work. Close, as a matter of fact, very close, but not exactly what I'm looking for.

The basic idea that I have now is based on the fact that a lot of the functionality that PostXING uses now already sits in separate dll's in the application root. I think that I can factor out the API specific functionality into kind of a plugin - thereby expanding the end applications that can be posted to from PostXING. I haven't hashed out all of the details yet. This is still a brainstorm at this point. However it works out, it's going to be a major version change.

If this can work out the way I think it can, this could be a very cool addition to PostXING. Very cool indeed.

I've been doing just that on my blogs - way back to when this one was hosted on dotnetweblogs.com.

Geez, I was such a dork...okay, maybe I'm still a dork. But that's a maybe. I admit nothing.

The Personal Website Starter Kit is a great resource for getting up and running with asp.net 2.0 beta. I've been using it to check out some features while waiting for other projects to get to a point where I feel like I can contribute more than just criticism (sorry y'all :) That said, the default.aspx page comes with a FormsView that rotates pictures from your PSKit albums, but everything else is static content! That is, you're greeted on the front page with something like:

Welcome to my Website!

On this site you will find lorem ipsum dolor sit amet...

Earlier, I had tried using one of the new data controls in asp.net - namely the FormView. I ran into a few issues with this control, mostly having to do with having to know what ID I was using in the database to set or edit the FormView's contents - I'm sure I could have worked out a way to set the ID to use in some clever way, but then I looked at the actual content that comes stock with the PSKit and it hit me...

A DataList.

It's already separated by a horizontal rule - all I really need is to bind a good old DataList to a couple of database entries and I've got something that I can update, oh, say twice a year or whatever. heh.

I used a similar table structure to the one from before:

Content
ContentID
Heading
Content
IsVisible

I had to actually write code (gasp!) to get it working the way I wanted it to, but it was pretty stock stuff thankfully. I just set up a SqlDataSource pointing to this table's CRUD procedures:

                <asp:SqlDataSource ID="SqlDataSource1" 
runat="server"
ConnectionString="<%$ ConnectionStrings:Personal %>"
ProviderName="System.Data.SqlClient" SelectCommand="GetContents"
SelectCommandType="StoredProcedure"
DeleteCommand="RemoveContent"
DeleteCommandType="StoredProcedure"
InsertCommand="AddContent"
InsertCommandType="StoredProcedure"
UpdateCommand="EditContent"
UpdateCommandType="StoredProcedure"> <DeleteParameters> <asp:Parameter Name="Content_ID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="Content_ID" Type="Int32" /> <asp:Parameter Name="Heading" Type="String" /> <asp:Parameter Name="Content" Type="String" /> <asp:Parameter Name="IsVisible" Type="Boolean" /> </UpdateParameters> <InsertParameters> <asp:Parameter Direction="InputOutput" Name="Content_ID" Type="Int32" /> <asp:Parameter Name="Heading" Type="String" /> <asp:Parameter Name="Content" Type="String" /> <asp:Parameter Name="IsVisible" Type="Boolean" /> </InsertParameters> </asp:SqlDataSource>


Then the DataList itself:

			<asp:DataList ID="DataList1" 
runat="server"
DataSourceID="SqlDataSource1"
Width="100%"
OnCancelCommand="DataList1_CancelCommand"
OnEditCommand="DataList1_EditCommand"
OnUpdateCommand="DataList1_UpdateCommand"
OnDeleteCommand="DataList1_DeleteCommand"
OnItemCommand="DataList1_ItemCommand"
RepeatLayout="Flow" > <ItemTemplate> <asp:Panel ID="contentPanel"
runat="server"
Visible='<%# Eval("IsVisible") %>'> <h3><asp:Label ID="HeadingLabel"
runat="server"
Text='<%# Eval("Heading") %>'></asp:Label></h3> <asp:Label ID="ContentLabel"
runat="server"
Text='<%# Eval("Content") %>'></asp:Label>
<asp:HiddenField ID="hdnContentID"
runat="server"
Value='<%# Eval("Content_ID") %>' /> </asp:Panel> <asp:Panel ID="Panel1"
Visible='<%# User.IsInRole("Administrators") %>'
runat=
"server" Height="50px" Width="125px"> <asp:LinkButton ID="LinkButton3"
runat="server"
CommandName="edit">Edit</asp:LinkButton>&nbsp;&nbsp;
<asp:LinkButton ID="LinkButton4"
runat="server"
CommandName="delete">Delete</asp:LinkButton></asp:Panel> </ItemTemplate> <SeparatorTemplate> <hr /> </SeparatorTemplate> <EditItemTemplate> <asp:TextBox ID="txtHeading"
runat="server"
Text='<%# Bind("Heading") %>'></asp:TextBox> <asp:CheckBox ID="chkVisible"
runat="server"
Checked='<%# Bind("IsVisible") %>'
Text=
"Visible" />
ContentID:
<asp:Label ID="lblContentID"
runat="server"
Text='<%# Eval("Content_ID") %>'></asp:Label> <asp:TextBox ID="txtContent"
runat="server"
Columns="40" Rows="20"
Text='<%# Bind("Content") %>' TextMode="MultiLine"></asp:TextBox>
<br /> <br /> <asp:LinkButton ID="LinkButton1"
runat="server"
CommandName="update">Update</asp:LinkButton>&nbsp;&nbsp; <asp:LinkButton ID="LinkButton2"
runat="server"
CausesValidation="False"
CommandName="cancel">Cancel</asp:LinkButton>&nbsp;&nbsp; <asp:LinkButton ID="LinkButton5"
runat="server"
CommandName="add">Create as New</asp:LinkButton> </EditItemTemplate> </asp:DataList>

Several points of interest in the DataList declaration:

  • No more pesky DataBinder.Eval(Container.DataItem, "field") syntax - much leaner and meaner Eval() syntax for one-way binding.
  • Two-way binding happens via the Bind() syntax - notice that Bind() only happens in the EditItemTemplate, since the ItemTemplate is readonly.
  • I'm only showing the edit/delete buttons based on what role the current user is in. I wasn't sure if this (# User.IsInRole("Administrators")) would work at first because it's deceptively simple. But yeah, it does work. Works great!
  • I did most of this visually - there is no longer a reason to fear the designer in asp.net (thanks Venus team!)
  • I had to disable Page input validation because I want the Content to contain html, and by default, it don't like that.

As for the codebehind, I guess I could have refactored it a little bit, but since this is not a mission-critical application (it is just a personal site, after all!) I just went the easy route and duplicated a lot of code. Probably the best thing to do would be to handle just the ItemCommand because there is no default handler for add and use a clever mix of a switch statement and defaulting the value of EditItemIndex to -1. But this isn't about best practices, it's about getting the stuff to work, ya know? Anyway, here's the code:

  1 	protected void DataList1_CancelCommand(object source, DataListCommandEventArgs e)
  2 	{
  3 		this.DataList1.EditItemIndex = -1;
  4 		this.DataList1.DataBind();
  5 	}
  6 	protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
  7 	{
  8 		string heading = ((TextBox)e.Item.FindControl("txtHeading")).Text;
  9 		string content = ((TextBox)e.Item.FindControl("txtContent")).Text;
 10 		string isvisible = ((CheckBox)e.Item.FindControl("chkVisible")).Checked.ToString();
 11 		string id = ((Label)e.Item.FindControl("lblContentID")).Text;
 12 
 13 		this.SqlDataSource1.UpdateParameters["Content_ID"].DefaultValue = id;
 14 		this.SqlDataSource1.UpdateParameters["Heading"].DefaultValue = heading;
 15 		this.SqlDataSource1.UpdateParameters["Content"].DefaultValue = content;
 16 		this.SqlDataSource1.UpdateParameters["IsVisible"].DefaultValue = isvisible;
 17 
 18 		this.SqlDataSource1.Update();
 19 
 20 		this.DataList1.EditItemIndex = -1;
 21 		this.DataList1.DataBind();
 22 	}
 23 	protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e)
 24 	{
 25 		string id = ((HiddenField)e.Item.FindControl("hdnContentID")).Value;
 26 		this.SqlDataSource1.DeleteParameters["Content_ID"].DefaultValue = id;
 27 
 28 		this.SqlDataSource1.Delete();
 29 
 30 		this.DataList1.EditItemIndex = -1;
 31 		this.DataList1.DataBind();
 32 	}
 33 	protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e)
 34 	{
 35 		switch (e.CommandName)
 36 		{
 37 			case "add":
 38 				string heading = ((TextBox)e.Item.FindControl("txtHeading")).Text;
 39 				string content = ((TextBox)e.Item.FindControl("txtContent")).Text;
 40 				string isvisible = ((CheckBox)e.Item.FindControl("chkVisible")).Checked.ToString();
 41 
 42 				this.SqlDataSource1.InsertParameters["Heading"].DefaultValue = heading;
 43 				this.SqlDataSource1.InsertParameters["Content"].DefaultValue = content;
 44 				this.SqlDataSource1.InsertParameters["IsVisible"].DefaultValue = isvisible;
 45 
 46 				this.SqlDataSource1.Insert();
 47 
 48 				this.DataList1.EditItemIndex = -1;
 49 				this.DataList1.DataBind();
 50 				break;
 51 		}
 52 	}

This is the quickest way I could figure out to make things work, and yeah, it does work. So, there you have it - even though there are only two items currently in the table, it's very easy to add content via in-place editing and change what is currently there as well. You can view it live over at www.bluefenix.net.

[ Currently Playing : Voices - Godsmack - Other Side (3:44) ]

I use Azureus as my bittorrent client. It has this nifty feature that is similar to the Updater Application Block that will automatically check for and download updates on startup of the application. The only downside for me is that since I was running JRE 1.4, and after a little battle with my wireless router, I could contact trackers okay, but not peers.

Balls.

So I look around the program to see what I can see. Oh look! There's an irc client that is loaded as a plugin! I haven't been on an irc channel since like '98 or '99, but it can't have changed that much, right? /join, /msg, yeah, I think I'm good to go.

So I hop on the channel, fully expecting some random bs to be flying around like it used to be. How wrong I was. Myself along with about 4 or 5 others having issues with azureus got coached thru getting azureus running like a champ. In particular, two people helped me not only get az up and running correctly again, but also coached me on getting it set to its optimal settings for my cable internet link at home.

I'd like to thank martouf5 (no link given) and PhilKC for being such a big help with my n00b azureus hurdles. A couple of things that I learned thru this:

  • The channel has a very helpful, friendly tone - this was even true when I returned later to ask permission to use these guys' nicks on my blog, so it wasn't a fluke afaict.
  • You can test your connection speed on www.dslreports.com or www.testmy.net You gotta dig a little bit for the one on dslreports, but they both give you pretty much the same information.
  • Installing the JRE v1.5 does not uninstall previous versions. It's been a while since I've done any kind of Java development, but I wonder if this is because they have a SxS story like there is with the .NETfx? If so, there must be a way to tell a program which runtime to use...
  • There is a bot (AzBot) on the channel (irc.freenode.net, #azureus-users) that will tell you the optimal settings to use with azureus by typing a command like /msg AzBot upspeed 5008. I find that simply incredible. And incredibly useful.

I was told by martouf5 that the motto of bittorrent is "give and you shall receive" - he said that was pretty much the attitude of this particular channel, and they all volunteer and help out people as they can. Judging from the conversations that I saw briefly, they get pretty much the same questions over and over, so I guess that helps in its way. He also humbly claimed that he was not one of the channel's "heavyweights" - that there were others there that helped a lot more than he does - but he helped me darnit, so he gets the credit he deserves here. PhilKC is actually what martouf5 would call a "heavyweight" and they both helped me when I needed it...so thanks, y'all.

[ Currently Playing : Right Here, Right Now - Fatboy Slim - You've Come a Long Way, Baby (6:27) ]

Awesome. I had a feeling I was going to see something like this sooner or later.
More Posts