I finally got back to writing some WhatIWantMost code again. My new goal is to implement quite a few more of the user stories before I go off on any more tangents, though Chameleon is calling my name. For those of you keeping track at home I am updating my original User Stores post and crossing off items as I implement them.
Before getting to any coding that’s been accomplished, though, there are is some architectural housekeeping that I should mention. I decided to implement a BasePage class that all the site’s pages will inherit from. That class will implement some basic site-wide functionality so the pages themselves will not have to worry about doing so. I probably should have done this before creating a dozen pages, but it’s nothing that a little refactoring couldn’t fix. Currently the base page does nothing more than provide local instances of some domain “services” - things like WishListService and WishListItemService for brokering domain objects. It also contains a CurrentUser property that abstracts the ASP.NET Membership stuff and additionally the instantiation of the WebProfile class (to replace the ProfileCommon class) that I wrote about recently.
I’ve also added a few more database fields here and there and some custom stored procs to create some needed methods in my .netTiers framework. Because .netTiers makes it very simple to regenerate the code and get quickly back to work I don’t really consider this very interesting any more (at least not for the reader). I will suppress these details unless there is some extraordinay modification that is made to the site’s functionality.
Tonight’s session was fairly short, I chose to implement a couple of easier items and set about getting my nose to the grind stone. The two new items I chose to implement were “Search/Browse users wishlists” and “copy an item from someone else’s wishlist to your own”. These are paraphrased a bit from my original list, but if you compare the two I’m sure you can figure it out - you’re smart people after all!
Because of the .netTiers framework neither of these tasks was very difficult. Searching/Browsing didn’t involve much more than adding a couple of text boxes and doing something like this:
protected void btnUsername_Click(object sender, EventArgs e) {
SqlDataReader wl = (SqlDataReader)WishlistService.FindByUserName(txtUsername.Text);
if (wl.HasRows)
{
dg.DataSource = wl;
dg.DataBind();
dg.Visible = true;
}
else dg.Visible = false;
}
You’ll notice that I’m using a lot of datagrid controls in my UI right now. That’s not necessarily because I love datagrids, but because they make it easy to auto-discover data fields that an item makes available by setting AutoGenerateColumns to true. Later I will do some refactoring and change those to something more appropriate, if necessary.
Search is now working. Once this was done I realized that it would be really nice to re-use my existing “My Wishlist” page as the same page that you can view other people’s wishlist with. This required a little bit of refactoring and hiding some things (like “edit this item” and “delete this item” links) when not appropriate to show them, but it was nothing too difficult. I did decide to invite another “product” to the party to aid in this page re-use, but more on that in a bit. The below shot shows the wishlist page when viewing someone else’s wishlist. Notice the green ”+” icon at the bottom right of each item. It is not very self-evident at the moment, but that is how we will copy items from someone else’s wishlist to our own.
To make the URL’s a little cleaner, especially for the wishlist page, I decided to employ a url rewriting tool, UrlRewritingNet.UrlRewrite. I’m so used to Community Server’s url rewriting functionality that I would miss it in an application that doesn’t make use of it. To tell you the truth I don’t know what CS uses for url rewriting - I’d have to look to find out. It works so well that I never worried about the implementation details. UrlRewritingNet.UrlRewrite has some great documenation and was a snap to implement, especially if you have experience using such things. Now links to the wishlist page look like this: http://www.whatiwantmost.com/bobby/Wishlist.aspx rather than the real link, http://www.whatiwantmost.com/Wishlist.aspx?id=AEIOUandSomtimesY#$123.
Implementing the “copy this thing to my wishlist” was even easier than the search. I added the image button that I pointed out above and then added something similar to the following:
WishlistItem wli = WishlistItemService.GetByID(itemid);
WishlistItem wli2Add = wli.Copy();
wli2Add.WishlistID = WishlistService.GetByUserid(CurrentUser.ID).ID;
WishlistItemService.Insert(wli2Add);
Response.Redirect("~/Wishlist.aspx");
As an aside, I hope the variable names that I have chosen are evident enough to make the code samples throughout understandable. I haven’t gone out of my way to do so, but everyone thinks their code is understandable :)
Here’s what it looks like after you click the “Add” button and have been redirected to your own wishlist page:
You can see that Rico decided to copy the USB Rocket Launcher from Bobby’s list to his own. Good choice, Rico!
I am pleased with my success so far. If I were allowed to voice one concern at this point (and I am because I am the author!) it would be that I’m uncomfortable with the amount of logic that I currently have in the UI - on the pages themselves. This concern has mostly to do with the Wishlist page as it stands. I believe that the reason it is in its current state is based on the architecture that I have chosen to implement. Because I chose to use the built-in ASP.NET membership provider I did not implement any specific user classes in my .netTiers framework - I did not include the membership tables in the tables I chose for generating code. This makes my domain model a little oblivious to any user state. The upside to this is separation of concerns - I let the ASP.NET membership worry about user stuff and I let my domain model worry about wishlist stuff. The downside is that in the UI I am currently checking to see if the user is logged in, if the currently logged in user is the owner of the current wishlist, if the current user is not logged in, etc. and performing different actions based on those states.
This condition was compounded by my choice to use the existing “My Wishlist” page as the same page for viewing another person’s wishlist. Because of this I have to suppress different functionality for each user state. Had I chose to use a different page the code would have been a bit cleaner, but I would have had a lot of duplicated functionality. I could however correct this refactoring the like functionality into a control.
Though I am a bit worried at this point I believe the situation is fixable. I should be able to move some of the existing logic out of the UI layer eventually. At some point in the future when the site’s functionality is further built out I can perform some of the refactoring mentioned above, creating controls or classes to group some of that like functionality. I can also extend some of the .netTiers domain objects through the use of custom code in partial classes to bend them a little more to my needs and make them a little more aware of user state and the different actions they should perform based on that state.
All things considered, I think we’re in a good place.