Saturday, November 1, 2008

AZURE update

Greetings

I've only seen my very simple project work twice. The first time was when I first built it; the 2nd time was some random success. Typically, it just times out after 3 minutes.

I'm setting this aside from now. This has inspired me on a project I've often talked about doing but never took on. So, I'm working on that now. I tend to start a lot of stuff and never finish it. This may be such a project, but at least for the moment, I'm motivated, and I'm working hard on it.

I'm going to use SQLCE as the default data store for the project. I haven't used it before, so it'll be neat. (Of couse, you can swap it out with any data store you want, but it'll be ready to run out of the box because of CE)

Friday, October 31, 2008

Resharper: "Use implicitly typed local variable declaration"

I've been using Reshaper for a couple weeks now. I like it a lot. When I was given the option to get a license for this, I responded that I would rather Code Rush. Afterall, I write more code than I refactor.

That ended up being an over simplification, though. Resharper has lots of great goodies in it. Though I would still like Code Rush, Reshaper is great all by itself. I learn to appreciate it more any day.

Except for the "Use implicitly typed local variable declaration" hint.

As an example, I have this line of code:

ServiceDescription description = attribute as ServiceDescription;

the type, ServiceDescription, is underlined with the fore-mentioned hint. Basically, its telling me to define the type as VAR and let the compiler figure it out for me.

I'm not a fan of that suggestion at all. If I know what type it is, then I want to specify the type. I don't need the compiler to figure it out for me. If I end up specifying a less than optimistic type (ie: should've used XmlReader instead of XmlTextReader), then Resharper or FxCop will let me know, and I'll learn from my mistake rather than just let the compiler do its voodoo for me.

However, I don't want to be irrational and just blindly shut off the hint. I wanted to find the justification for that hint, so I started poking around. It seems that there are 2 prevailing schools of though on this: Those that think you should use it for everything, and those that think you should only use it for anonymous types.

After reading a few different things, I have committed to my opinion expressed above: If you don't know what type it will be (because its anonymous), the use var. Otherwise, specify the type.

A guy from resharper justifies it here:

http://resharper.blogspot.com/2008/03/varification-using-implicitly-typed.html

While interesting, it doesn't sell me. Some comments on some bullets:
- Its is required to expres variables of anonymous type - no kidding. that's why it was invented.
- It induces better naming for local variables - that's putting a square peg in a circle hole. Its handholding at best. If you name you're variable CURRENT then its scope should be so small as to always remain obvious what it is. If it isn't obvious, then you named it wrong, and declaring it of type var isn't going to make you name it any better.
- It induces variable initialization. - Again, I don't need VAR to force me to do that.
- It removes code noise. - Maybe. I'd like to see some samples before I buy it.
- It doesn't require a using directive - so what? Are using directives troublesome to anyone? Heck, Resharper puts it in for you. If you don't have resharper, then CONTROL+. will put it in for you.

That's my story.

Thursday, October 30, 2008

Windows Azure - Cool

Greetings

By recommendation of a co-worker who is at PDC, I immediately signed up for AZURE and download all of the associated files. I also had to update this machine to 3.5 SP1 and VS2008 SP1.

The following is just running commentary on what I'm doing as I do it.

Once everything was in, I opened up VS2008 and found the new CLOUD SERVICE project options. I can only guess what a worker is, so kept it simple and started with just a simple WEB CLOUD SERVICE.

This creates 2 projects: The service itself and a webrole. Again, I can only speculate on how we'll use WEB ROLE based on the name. The service project has a ROLES folder with a refernece to the ROLE project. Swell.

The role project looks like a website. It has a web.config, Default.aspx, Default.aspx.cs, and Default.aspx.designer.cs. (I think that last file is new too. If its been in 2008, then I never noticed it. Don't know if its an AZURE thing or a SP1 thing.) The service file has two configuration files: a csdef and a cscfg. One defines the service, the other configures it. The cscfg defines the endpoint name, port and protocol. It notes that the port must be 80 in the actual cloud environment, though you can use whatever you want in the dev environment.

I didn't make any changes since I really have no idea what I'm doing yet. I hit the RUN button to see what happened.

The status bar reports "Initializaing Local Development Service", or something like that. VS seems to hang for a while, then reports that it can't find .\SQLEXPRESS. That's fine. I don't have SQLEXPRESS. Then it hangs some more, and eventually says that the service timed out.

For kicks, I started downloading sqlexpress 2008. I haven't used 2008 yet, so now's as good a time as any. In the meantime, though, there must be a way to switch the database info.

I found the answer in C:\Program Files\Windows Azure SDK\v1.0\bin\DevelopmentStorage.exe.config. I changed the setting, then hit run in VS2008 again. It reports that DEVELOPMENT STORAGE IS ALREADY RUNNING. ONLY ONE INSTANCE OF THE APPLICATION CAN BE RUN AT THE SAME TIME. Then it hangs again, and eventually comes back the SERVICE TIME OUT ERROR.

I looked in Task Manager/Processes, and services.msc for any sign of this thing. No luck. That's not to say its not there, but I didn't see it short of looking at each process individually. I checked for things like AZURE and DEVELOPMENT, etc. (In retrospect, I should have looked through the vs2008 menus and icons. There's probably something there)

Oh well. Time to restart vs2008. This time, when clicking run, it asks me if its ok to do some initialization as an administrator. Fine with me; go for it.

It reports this:
Added reservation for 'http://127.0.0.1:10000/' for user account 'jayavst690\jaya'
Added reservation for 'http://127.0.0.1:10001/' for user account 'jayavst690\jaya'
Added reservation for 'http://127.0.0.1:10002/' for user account 'jayavst690\jaya'

Checking if database 'DevelopmentStorageDb' exists on server '.\personal'
Creating database DevelopmentStorageDb

Granting database access to user 'jayavst690\jaya'
The login already has an account under a different user name.
Changed database context to 'DevelopmentStorageDb'.
Adding database role for user jayavst690\jaya
User or role 'jaya' does not exist in this database.
Changed database context to 'DevelopmentStorageDb'.

Initialization successful. The development storage is now ready for use.

Now, there's a DEVELOPMENT STORAGE icon in my system tray. Was that there before? Didn't notice. This time, it gave me a baloon to let me know it was up and running. There wasn't one when it failed.

The development storage app shows that there are 3 services: Blob, Queue, Table. Table is stopped, the other 2 are running. The menu bar doesn't gives us a whole lot to do.

I closed it and ran it again. This time, vs2008 hung. It gave me the "vs2008 is waiting for an internal process" message. Swell. I see that in sql server management studio 2005 all the time (usually when working with diagrams), but this is the first time for vs2008.

I got tired of waiting, so killed it from the task manager. While in there, guess what I noticed: DevelopmentStorage.exe. That definitely wasn't there when I checked earlier.

I restarted vs2008, and ran the project again. Development Storage started, but vs2008 is hanging again.

So far: Lots of hanging.

Now I'm just trying to get it to do something. I read a blog entry that tells me WEB ROLE isn't what I thought it would be (I was guessing just based on the word role). My goal is to get a silly DvdFriend service going. I'll keep you posted.

Thursday, July 31, 2008

Related Products

I added some support for "Related Products". If you select Dark Knight, for example, the product page will also show you Batman Begins.

This involved three new tables:
- ProductGroupType
- ProductGroup
- ProductGroupMembers

Two new views:
- vwProductGroups
- vwProductGroupMembers

Stored Procedure:
- GetRelatedProducts

I added a new object data source to the page, and a gridview. The ODS calls a method that calls the stored procedure and returns a datatable (keep it simple).

Currently, it just lists them with links. That will improve. Also, a product may be associated to multiple groups. The page will have to improve to show the different groups. For now, they're all just merged into one distinct list.

I'm not going to make an effort to backfill groups. But, as new movies come up, I'll create new groups as appropriate. So far, there are groups for Stargate, Lost Boys, Hellboy, and Batman.

Wednesday, July 30, 2008

MVC Preview 4

Preview 4 came out yesterdayish (at least, that's when I first heard of it). I haven't updated my test site yet, but will. Tonight I got hung up writing some queries for my side-venture. I have another task to do for them, then I'll be back for MVC Preview 4, and new work on the DvdFriend site. (Next up, I think, is product level comments. Lets rants and speculate about movies and DVDs without actually seeing them!)

Monday, July 28, 2008

Added News and Feed

I added a NEWS section to the top of the main page. It will really be more than news, though... more like notices, perhaps.

The News support was already in there. It was displayed on the page somewhere about a year ago, but it didn't look good or wasn't useful, so I got rid of it.

Fortunately, the method to retrieve it is still there. Basically, I just call GetRecentEntries(5, "news", true).
Last 5 entries; news zone; get the entire text rather than just the title.

There's a news feed too, but its going to need work. The title of a blog entry may contain HTML (ie: the link to dark city), but a syndication title may not. I have to change the entry page to distinguish between the title and what the title links to (if anything). In the meantime, it tears the html out of the title if there is any. Then, for the permalink, it extracts the link. If the link it exists, it uses it. Otherwise, it just links to the main page.

Sunday, July 27, 2008

Web delay fixed

The production site, since moving to GoDaddy, has always taken a few seconds to load on the first hit. The problem is that the first hits are very frequent. Almost every time I go to the site, its a first hit.

It never really bothered me much because there are only a few visitors a day, but now that the embedding is enabled, its more intrusive. The hamletcode blog would pause as it waited for the dvdfriend site to fire up to serve the demo embedded review.

I poked around in the pool settings and found that the worker process was set to shut down after 5 minutes of being idle. I disabled that. I also saw that it was set to recycle ever 29 hours, so got rid of that. There's really no reason for the worker process to need to be recycled, but this will be a good test to make sure.

Since I was in there anyway, I changed the session timeout from 20 to 60 minutes. Effectively, the timeout was 5 minutes anyway since there's rarely more than one person writing a review at any given time.

This should resolve all the timing issues. Also, it will help coverup a bug with the review page; If session times out while you're writing the review, you lose it. That's definitely very bogus and I have no reason to avoid fixing it other than a complete lack of interest. In fact, that's the last thing that's stopping me from removing the "under construction" label.


In conclusion

Reviews can now be embedded

I was going to make this feature available to only people that are logged in, but then realized that it probably doesn't make sense to limit my exposure. Embed away!




The code goodies follow. ReviewHtml.GetReview() simply builds a bunch of javacript document.write() methods.

[ServiceContract]
public interface IContentService
{
[OperationContract]
[WebGet(UriTemplate = "review/{reviewId}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat=WebMessageFormat.Xml)]
Stream GetReview(string reviewId);
}

public class ContentService : IContentService
{
public Stream GetReview(string reviewId)
{
return new MemoryStream(Encoding.UTF8.GetBytes(ReviewHtml.GetReview(new Guid(reviewId))));
}
}

Here are some interesting things I learned:
- I had to return the text as a stream rather than as text. If you return it as just a string, then there's always sometype of serialization wrapper around it. Additionaly, the generated html tags get encoded. So, we get <td> instead .

- In the UriTemplate, you specify the parameters.

UriTemplate = "review/{reviewId}"

Its maps the value in {reviewId} to the reviewId parameter of the method. That's cool; very MVCish. Unlike MVC, however, it must be a string. In this case, the ID is a guid, but the mthod must accept a string.

I find this dissapointing and, if I had to guess, I'd say that will change. The framework is certainly capable of converting known types for us.


I really just sort of tripped through the WCF stuff in this case. I have to read up on the new REST capabilities.

Wednesday, July 23, 2008

Good bye faithful printer.... Good bye!

I have mixed feelings about the passing of my printer.

Well, see... there. I've lied already. In the very first sentence I'm lying like a president. The printer isn't so much "passing" as it being put down.

I have a Lexmark X125 all in one printer. It is AT LEAST 5 years old; possibly even more than 6, but I have definite milestones to peg it at least 5.

Its a cool little printer that I got for cheap and has lasted, to some extent, all this time. It still works. In fact, shortly after I bought it, I bought one for my parents too. (Coincidentally, last night I received a call about a new printer they bought. I believe that they too were still using their X125 until recently, but unconfirmed.)

So why the mixed feelings? On one hand, I bought a cheap printer and used it for 5 years. On the other hand, it annoyed me every time.

Here's the thing: the drivers suck. They always have. Lexmark support was 0 help... I gave up years ago. The printer will work for a while, then you have to kill some processes in order to get it to print again. I exchanged many emails with them just trying to get them to come clean and say "sorry, we suck", but they wouldn't.

The next logical question may be, "How did you put up with that for 5 years, you poor poor soul!?". The answer is simple: I don't do a heck of a lot of printing. I bought a box of paper years ago and I still have most of the reems (spelling?). I just don't have a need or a desire to print. If I want to read something from the computer, I just read it on the computer. It doesn't have to be paper. I keep all our digital images as digital images... I don't print them.

Lately, I've had a need to print some stuff, for expense reports, on a monthly basis. My luck has been limited. I occasionaly go to the office with the intent of printing the stuff, but then it slips my mind and I leave empty handed. Ick. I also have to fax my receipts, an the X125 was being difficult. It would often say "replace cartridge" even though it was a new cartridge. After multiple attempts, I thought it was dead. Then, it finally worked.

So now, at long last, we're at the point where it is essentially unusable. I want to be one of the cool kids that simply clicks "print" and the thing prints. Is that too much to ask? Am I being a snob by not wanting to fight to print for 5 minutes a page? I don't think so, but I value your opinion, so let me know.

Due to the fact that I work from home, my esteemed employer found it in its heart (and wallet) to equip me with a brand new HP5610. I plugged it in and clicked print. Guess what... it printed! Now I feel like a king. Rejoice!

I'll cart the ole X125 up to the recycling center on my next trip. When I dump it in the box, perhaps I will pause for just a moment and reflect on the times gone by, both good and bad, but I make no promises.

Coming Soon - Embedded Reviews

Chris has stated his desire to be able to embed his DvdFriend reviews elsewhere in the internet galaxy. Interesting idea. I haven't done that before. (For those of you just joining us, I'm not real big on building web pages. There are a lot of things I haven't done.)

Anyway, I started looking into this. The first thing that jumped to mind was left over from 1995: Add an iframe. The second thing to jump to mind was: don't be ridiculous.

I started searching on the current swell ways to do this. The goal, per normal, is keep it simple. I just want the user to drop a little piece of something on their page and have it work. I came across XSS pretty quick, then avoided it since XSS is often associated with bad mojo due to attacks. I looked at the object
tag... Couldn't get it to work with external web pages.

Eventually, I ended up back to XSS.



Created A Page called ReviewScript.aspx
I wiped out everything from the ASPX except for the server tags at the top.

The PageLoad calls Response.Clear(). It then builds a big piece of javascript that, basically, generates some html then writes it to the document.



Add a script tag to the page that references ReviewScript.aspx
Every time I paste any type of tag into this stupid thing, it loses it. And I'm currently too lazy to deal with a screen shot. So, mentally fill in angle brackets.


script language='javascript' type='text/javascript' src='http://www.dvdfriend.us/ReviewScript.aspx?id=xxx'
/script


Sweet. I started by including that on the dvdfriend main page (dev version) so that I can compare whats generated to what shows up on the page.


Templates / Make it look as it does on the main page

The generated html is based on a template. The default template is going to look exactly like a rewiew does on the main page. I started by embedding the script on the main page so that I could look at them next to each other. Once it was close, I moved it to another site altogether.



Create a new CSS

As soon as I imported the dvdfriend.css to the other site, it messed up the entire page. That was expected. I created a new css called external.css and copied over only the styles i needed. I renamed them all with a prefix of DF, just to keep them separated.


Incidentally, the css is included by document.writing a link tag.


That pretty much did it.

Template - So Far

The template has these tokens so far:
DvdFriendCss
Rating
Title
ProductTypeImage
ProductName
ProductId
CreateDate
Author - pending. Have to populate this
RatingClass
AuthorLink
ProductLink
ReadLink



The list will grow. Most of them are just pieces of data so that you can build it anyway you want. Some of them are more generic to give you something to start with. the LINK tokens, for example, automatically create the links as you see them on the home page now.



TODO

- See if there is a better way to include the CSS. If there are multiple embeds on the same page, it will import the css multiple times. Would rather do it through javascript.


- Retrieve the author. The page is built from a datatable. The script is built from a blog object which, mysteriously, doesn't already have an AUTHOR property exposed.


- Work out some additional css issues. It almost looks like it does on the site, but I still have some font issues to resolve.


- Test in production environment. I've only used it on my local machine. Lets see if it actually works out there. Furthermore, lets see what types of things, if any, prevent the xss from firing.


- LATER: Allow for users to create their own templates using the available tokens. I think that every template will be available to every user, but it can only be editted by the person who created it. We'll see.

- Brush my teeth and go to bed

- Server it as a WCF service rather than an aspx page. The aspx is a quick and dirty just to get it going. I will convert it to a WCF service much like the RSS feed. The one missing piece of info there is how to pass parameters. It shouldn't be a big deal; I just have to look into it.

Screenshot

Here's what it looks like embedded on the now neglected Clan Friend site.

The background of the review is always white. Its not inheriting it from the parent element.

Sunday, July 20, 2008

First RSS Feed is live

I deployed the first DvdFriend RSS feed. I kept it as a WCF service afterall. I'll keep it that way until i come up with a reason not to.

The deployment wasn't painless. It didn't work in production as it did in development. It was because there are multiple sites on the server that are distinguished by host headers. Ilearned in 3.0, you had to code around it. 3.5 makes it a little easier. I found this link:

http://blogs.msdn.com/rampo/archive/2008/02/11/how-can-wcf-support-multiple-iis-binding-specified-per-site.aspx

I added http://www.dvdfriend.us as a prefix. I attempted to add http://dvdfriend.us as a second prefix, but it went back to the orignal error. Go figure. I don't havea good grasp on this stuff yet, but its working, so we're ok for now

I think COMMENTS will be the next feed. I have to create a page for that anyway, so they'll have the same data source.

RSS 2 / Atom 1 Feeds

.NET 3.5 adds a WebHttp WCF binding and Synidication support. I haven't tried anything with syndication yet. Now seemed like a good time.

The DvdFriend home page shows the most recent 50 ratings/reviews. I've received more than one request to make that, and comments, available as feeds. I started with the recent activity.


Setting it up as a WCF service was pretty easy, though I'll probably end up dropping it. I'll probably just expose it as SYNDICATION.aspx or something. We'll see. Regardless, doing it as a WCF service was a good experience.

Once I had a test feed going, it was time to populate it with the actual data. I thought LINQ would be the way to go. I already have a static method that returns a list of the recent reviews as a data table. I thought I'd just write a linq query against that data table. No dice. LINQ doesn't work on data tables. Swell. (Well, not really).

I wrote a generic wrapper class to make things enumerable for linq. (Is this the best solution? I don't know. But it works.)



NOTE: Changed this code. See notes at the bottom. (Changed GetEnumerator to return _items.GetEnumerator rather than yield through it itself)

Next, I had to write a Linq query that would return a List. In the process, I had to explore some of the properties and methods to see what was what. I set the basic stuff, but there were 2 things that I wanted to set, but couldn't during initialization:

- The author. SyndicationItem.Authors is a List(), so you don't initialize it. You have to add to the existing list.

- The item link. At first, I figured this would be BASEURI, but it wasn't. You have to call item.AddPermaLink(new Uri("...")). Its a method; can't call it during initialization.

For author, I could loop through all the items after the initial query and update the individual items from the datatable. But, not interested. That didn't sound like a very good solution. I only want to hit the datatable once and be done with it. PermLink would require a loop too, but that's based on ID which is already a property of SyndicationItem, so no problem there.

I solved the author issue by creating a subclass of SynidcationItem called AllardWorksSyndicationItem. I added a property called AUTHOR, so that I can save the information during load. Then, I can loop through and update the AUTHORS collection without having to bother the data table.



The Linq query now returns a List. After the query, I loop through the items and create the permalink (based on the ID, which I already have), and I add the value of the new AUTHOR property to the existing AUTHORS property.




But wait. There's more. The SyndicationFeed object has a property called Items. You set it to a IEnumerable of SyndicationObject, not IEnumerable of AllardWorksSyndicationItem. The list needs to be converted. I achieved this by another Linq query which does the cast


Then, you return a formatter for the type of feed (I chose atom), and that's a wrap for tonight.

Final Code


Rendered in IE


Coming soon!
UPDATES
I revisited some of this.
I realized that LinqWrapper.GetEnumerator was silly, because DataRowCollection is already IEnumerable. All you have to do it
return (IEnumerator)_items.GetEnumerator();
rather than yield through it yourself.
Then I was bothered by the fact that DataRowCollection is already IEnumerable, so why do I need this stupid wrapper class?
The reason is that DataRowCollection is IEnumerable. Linq requires IEnumerable, so the wrapper converts it. I tried finding other

Monday, July 14, 2008

Email Problems

Greetings

People on my mail server haven't received any email since 7/10/2008. That's a problem. I took a look at the server, and as far as I can see, its ok. I put in a request with support.

If you'd like, you can contact me at hamletcode@gmail.com in the meantime.

Monday, July 7, 2008

Prologue Complete

The final tally for the prologue draft is just over 9 pages. Chapter 1, so far, is about a third of a page. I expect that to get larger, even if I have to resort to increasing the font size.

Sunday, July 6, 2008

Lack of direction

I'm spinning my wheels trying to find something good to do. I watched a web cast on Dynamic Data, which was great. I'm going to start reading up on Ado.Net entitites. But, I really can't come up with a project that I'm interested enough in to really pursue.

I keep thinking about a pubsub project, but haven't been able to comit. I've worked on the DVD site here and there, but nothing ground breaking. I'm lacking a sense of purpose.

Lacking anything useful to do, I've spent some time trying to write a sci-fi story. I used to write a lot more when I was younger. Now, I usually find it more rewarding to code. Since that hasn't been working out lately, I'll give writing another shot.

I've been thinking about this story for quite a while. So far, its called Savior, but I just made that up a minute ago and it probably won't stick. The prologue is mostly complete, and I should start on Chapter 1 tomorrow. It'll end up being a pretty short story; A lot of stories take 5 pages to say hello. In mine, I just say "hello". I don't know enough words to drag it out much longer than that. It certainly won't be novel length.

Wednesday, June 18, 2008

Indecision results in Netflix

For the last couple weeks, I've been torn about what to work on.

I got bored with the clan site. Once I worked through all of the MVC.NET stuff, I lost interest.

Last week, I went to a SOA / ESB conference. For several days, I thought about writing a .NET pubsub system.

I've also been thinking about writing a validation component. Every one I've seen (not many) requires tight coupling between the validator and the object being validated.

I've also been thinking about JTS, which is a pretty big piece of software that I wrote. (Muvico uses it). I started rewriting part of it in .net 3.5 with the intention of, perhaps, renting it out to other theater chains. I still might do that.

Then, I came back to DvdFriend. When all else fails, work on DvdFriend.

I added NETFLIX to the list of vendors. Unfortunately, it didn't play nicely with the existing vendor framework. Netflix requires you to be logged in in order to see the full product page. I had to put in a piece of custom code to handle that.

- changed the scraper to use httpwebrequest instead of webclient

- added a netflix hack to handle the netflix specific stuff. (The next time this happens, I'll have to refactor to an OOP friendly solution. This is just one, though, so no pattern yet. My goal was to implement netflix, not write tons of new code.

- Added a RentalOnly bit field to the vendor table.

- Changed the user control to show RENT when its a rental product.

- Much code is ignoring prices where the price <= 0. Rather than deal with that, set netflix to set the price to 999.00 (which never shows up anyway). Added a FIXED method to the parser to support this.

- Changed the save price stored procedure, for admin convenience. Normally, you would select a product type of RENTAL, then search for the product. Since DVD and BluRay is already there, the new check will make it a rental regardless of the selected product type.

I don't plan on backfilling all of the products, though I did go through most of products in the left and center columns. I'll probably do the right as well. Going forward, I'll keep up with it, and maybe do a few others here and there, but it won't be a big effort.

Now that the netflix product id is collected, the next logical step is "ADD TO QUEUE", and related.

After that... who knows. Amazon Unboxed? (Unlike netflix, I think Amazon Unboxed probably has a commission.

As always, if you would like to support the site, please consider using it for your product purchases.

Tuesday, June 10, 2008

DOOM 4

It takes a while for me to get to the point. Hang in there.

Chris mentioned that "Hitman is the best video game movie to date" on the DVDFriend website. I countered by suggesting that Doom, Mortal Kombat, and all 3 Resident Evil movies, and possibly the first Tomb Raider movie were all better. He agreed with a lot of that, but disagreed on doom. (It seems that he was zoning in on a particular director rather than cover the full spectrum of video game movies).

I liked the first Doom movie. It's in the "crappy but good" category. I love how they didn't bother with a PG13... they just went for the R, and did anything they want.

Anyway, that got me thinking about the Doom games. I never beat Doom 3. I suppose I should play it again, but I didn't have fun with it. Doom 1 and 2 were in big open areas with lots of monsters. You could kill a lot of the monsters with a single shot.

I didn't get very far in Doom 3. It seemed that you had to shoot everything 50 times, and you were always in these tightly enclosed areas. I think I read that there could only be 3 baddies on the screen at a time. And, the infamous flashlight.... apparently your first-person self can't hold a flashlight and a gun at the same time. (There was change for that after... don't know if it was a 3rd party mod or a IDSoftware change). Half Life 2 came out about the same time. Its a FAR superior game. I later update to Doom 3 ripped off the Half Life 2 gravity gun.

Great... right. But what does this have to do with a tech'ish blog? I'm getting there.

After pondering the failure of Doom 3 for a bit, I jumped on google to find Doom 4. I learned that, at the beginning of May, IDSoftware announced that production on Doom 4 has begun.

"Swell", I thought (in first person). "it'd be great if I could post a link to that on the website".

The development project name for DVDFriend is "DVDBlog". So is the database. I approached the new design (which really isn't new anymore) in a completely different way. Everything is "blog" entries, which is to day, just a bunch of text. There's no real hierarch of data. There are other tables to bring the data together in meaningful ways, with more to come eventually.)

The DVDFriend site is broken up into zones. I can specify different things go into different zones, though I have never actually done that. Its functionality that I have to revisit, because the database and API both support my wish to show a list of NEWS links in the right margin. However, the admin site does not. Rather than jump in and manually insert the data, I'd rather write about not doing it, as I am now.

Actually, though, it would require a new zone. The right zone is currently occupied by the DVD list. I'll have to put it outside the margin. It'll give it a certain symmetry.

When will I actually get to this? I feel that simply acknowledging it is sufficient. I don't know when I'll actually end up doing it. The way this usually works is that, as I type this, I'm really not in the mood. But, it will fester, then I'll finally commit to it while watching tv one night. Will the patter repeat? We'll see.

In the meantime, I'm thinking about other things. In particular, I'm thinking about SOA, ESB, and the possibility of writing a .NET pubsub. Stay tuned.

Sunday, June 8, 2008

Cardspace, Rounds 1 and 2

ROUND 1
One day last week, I figured it was time to learn some stuff about CardSpace. I read some articles and found some good startup guides. I learned about EV certificates.

I installed a test EV certificate on my local development machine, and created a secondary login page for DVDFriend. I put the cardspace object tag on the new page.

Everything went pretty smooth until that point. Then, I hit the button, and dissapointment ensued. The applet popped up and asked me for a card. Then there was flash, and it and the IE instance both froze. I went into process manager and killed ICARDAGT.exe and INFOCARD.EXE that freed it up. That happened a bunch of times.

The event log revealed that it was a WS TRUST failure. I didn't look into it anymore at the time, but it was dissapointing that it kept crashing rather than handle it gracefully. It was a bad first impression, but oh well, things go wrong. I put it off for another day.

ROUND 2

I didn't change anything. I just came back to it a few days later, and everything worked as advertised. I wonder if that WS error was due to a remote service being down somewhere. Its probably still in the event log, so maybe I'll revisit.

I'm going to be in a conference for the next 3 days, so I should have plenty of down time at night. Time permitting, I'll implement CardSpace as an alternative login to DvdFriend. Once in place, I can check CardSpace off my "things to do" list.

Saturday, May 31, 2008

Python Strings

Oh yea... i forgot to mention a Python string feature that I liked.

You can have a string with quotes without having to escape the quotes. You start and end the string with triple quotes, and quotes in the middle are fine.

IE:

""""I like to be quoted!". swell, right?"""

That should make life easier as long as you don't frequently include """ as part of your string literals.

Did some work on DvdFriend

It's been a long time, but I finally did some work on DvdFriend.

There are now LISTS in the left column, one for Dvd and one for In Theaters. This is to bring attention to particular movies of interest. These are managed on a per-product basis in the product editor.

The product editor now has 3 checkboxes
- Show on COMING SOON - the right margin. Without this, movies would only show up if they're have a rating. But, since I want to show some Direct to DVD movies (ie: stargate continuum), they need to show up even if they're not rated yet.

- Also in the product editor, I added a text box so that image urls can be manually entered. This is for cases where the image doesn't exist on amazon yet, usually theatrical releases. I have to find other image sources that I can safely use. (The "Set Image" link opens a browser that allows you to search amazon images. That's been there all along.)



The new lists on the left aren't very manageable yet. It'd be nice to be able to order them how I want, but I'm not that ambitious today.

Now for the bad news. In order to get that list on the left, I had to modify the CSS. Previously, everything was centered. I used absolute positioning for the list, so if you resized the window there was a very good chance the list would overlap the main page. So, I attempted to fix it, but didn't do so 100%. The header and body aren't lining up exactly right.

On the bright side, though, it looks MUCH better in firefox than it did before.

I changes JAY'S BLOG from a link to a navigation button so that it would render better in fire fox.

Google App Engine

I just went through the GOOGLE APP ENGINE "Getting Started" guide. Neat stuff.

http://code.google.com/appengine/docs/gettingstarted/

The runtime is Python, which I haven't used before. I installed python, then just used notepad to write the code.

The fun thing about python is that spacing counts. You block code by tabbing them out the same distance.

Google currently allows everyone to have 3 applications online, while they're still in preview mode. Througout the guide, it mentions how you can use any python library for doing different types of things, but it comes with "Django" stuff already bundled. IE: Templates. (In asp.net world, a template is a master page)

The benefit of using the google app engine is that it has a bunch of stuff built in, such as a datastore. The data store is not a relational database, though they expose a GQL language, which is very sql like.

greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")

You can also do it programtically.

greetings = Greeting.all()
greetings.filter("author =", users.get_current_user())
greetings.order("-date")

You never actually have to create any data store objects to hold your data. That happens automatically when you save stuff. It looks to be an object database. Once you save an object of type GREETING, then you use GQL to query for types of GREETING. (I wonder what will happen as you modify GREETING)

I'm definitely not a python guy, but it was fun to play with the language a little bit. Google App Engine is trying to make development/hosting a lot faster. The SDK gives you everything you need to get started (local web server and data store), and deploying the application to production is a snap... you just execute a python script that takes care of it for you. The setup is minimal. Everything pretty much works right out of the box.

Tuesday, May 27, 2008

Membership Update

When you create a new profile, it sends you an email.
The details of the email are recorded in the EmailHistory table.
The activation codes and userid are stored in the Activation table.

I changed the approach slightly. The actual activation part isn't done yet, but the plan is:
When activate via the website, you must specify Email Address, Password, and Activation code.
If you just click the link in the email (which is the easier way to go), it will pass two activation codes.

http://localhost/clanfriend/membership/activate/code1/code2

That results in an ugly url, which is swell.

The email is sent and recorded, and the activation codes are recorded. Next, I have to implement the actual activation.

Getting closer, but there are still a lot of loose ends before I can put it up.

Mvc.Net mapping / Preview 3

I said in an earlier post that I would like to have a mapping feature so that you can indicate actions via configuration rather than code. My tenative plan was to create a new subclass of Controller called MapController. It would have a method like

MapAction(string actionName)

In my login example, I'd change my action to:

MapAction("Membership.LoginSuccess");
which would redirect to the Home

MapAction.("Membership.LoginFailed")
which would render the LoginFailed view.

MapAction would do a lookup from the configuration store then do a render or RedirectToAction.

Preview 3 actually makes this a lot easier, because the acton methods now return an ActionResult object.

The subclasses of ActionResult (that I can find) are:
- ContentResult
- EmptyResult ?? (do nothing?)
- JSonResult
- RedirectResult
- RedirectToRouteResult
- ViewResult

So far, I've used implicitly used RedirectToRouteResult and ViewResult. (Controller has a RedirectToAction method and a View method which genereates the appropriate result object automatically).

This means that all I'd really need to do is create the appropriate type of ActionResult object and populate it from configuration. The saving is that the objects already exist; in Preview2, I would've had to create my own objects. (I'm glad I didn't waste time on it, then).

Now, I'd do:
return MapAction("LoginMembership.Success")

It'd be neat, but I'm not in a huge rush to do it. We'll see if it magically appears.

Preview 3

Woo hoo!

http://weblogs.asp.net/scottgu/archive/2008/05/27/asp-net-mvc-preview-3-release.aspx

I just updated the test site to use it. Other than 1 case of me not following instructions, it went smooth.

The HTML helpers have been changed. I was using an Html.Textbox signature that's no longer valid. Apparently, they'd rather you build the htmlAttributes collection and pass that in. For now, I merely simplified the call losing the SIZE and MAXLENGTH properties.

There's a major change to the ACTIONS, which I like a lot. Previously, the methods were of type VOID, and you'd do things like:

RenderView("Index")
or
RedirectToAction("Logout")

Now, you change the VOID to ActionResult, and change the actions to:

return View("Index")
or
return RedirectToAction("Logout")

Now, rather than instructing it to do something, you're returning an object that tells it what to do. So, now its more testable. You can write a test for the action and make sure that it returns the ActionResult that it should. Sweet.

Also, the ViewData object has changed. It used to be ViewData<T> where T is the type of the object passed to the view. That has changed to ViewData.Model<T>. This allows ViewData to provide other types of things such as...ummmm... Hang on a sec. I was really excited about that until just now. I pulled up the intellisense and didn't get what I expected. I'll have to look into that more, though I like the approach in intent. It is a place where a lot more things can be exposed other than just your view data object. As the framework grows, they can keep adding new things to ViewData.

Back to the grind.

Activation Codes

I'm starting to test the site pretending to be a brand new user. I want to make sure someone can sign up, get verified via an email activation code, then function. There will be two types of new users: those who aren't associated to any families, and those who are.

You'll be able to activate your account either by clicking the link in the email, or by typing in Email Address, Password and Activation code on the activation page. I'm pretty sure that will bet two different actions.

Sunday, May 25, 2008

MVC.Net update

Greetings


Just an update to let you know that I am still very active with the MVC.NET and LINQ SQL stuff, its just that there hasn't been anything terribly new to report. I continue to use LINQ SQL for everything, even where it feels incorrect.


I added a bunch of permissions. They are represented as, basically, name value pairs. There isn't a table storing these permissions yet; there's just a view that infers the permissions.


Whoever creates a clan becomes the clan owner.

Whoever creates a family becomes the family owner.

Clan owners can edit their clans, the family in their clans, and the people in their family.

Family owners can edit their family, and the people in their family.

People can edit themselves.


Those rules are all brought together in a view. I have a permissions class with three properties: People, Clan, Family. Each of those subclasses has a property or method to represent the permission from the database. The properties/methods are really for convenience. If there isn't a property for a particular permission, there's a method that you call to pass the parameters.


The permissions are setup as



ObjectType - People, Clan, Family
ObjectId - PeopleId or ClanId or FamilyId
Objectname - Clan Name, Family Name, or People Id
User Name
Permission Name


IE:

Clan, 33, 'Jay and Gina', 'Jay', 'CanAddPeopleToFamily'



I have a static reference to an instance of the permissions class. It uses a ReaderWriterLockSlim to wrap up the reader methods and the load method. Each time a family or clan is created, the permissions cache is reloaded.


That's really a brute force approach, and its definitely temporary. The permissions should be lazy loaded per-object-per-user.


I built it so that families can belong to multiple clans. When you create a new clan, it gives you the option of bringing existing families to the new clan. That's going to need an approval process... maybe the family doesn't want to be copied. At the very least, they need the flexibility to decide for themselves.

The more I use MVC.NET, the more I think that it really needs a mapping layer. That may be an ill-informed opinion, but so far, that's what I've come up with. I have the MEMBERSHIP controller redirecting the the HOME controller after logging in. That should be configurable at some other level. I'm thinking about writing that level to test it out. We'll see.

Thursday, May 15, 2008

Logging in with MVC.net

The test site has been coming along pretty well, though not a lot of new stuff to speak of recently. I learned some new LINQ stuff, but nothing revolutionary.

At last, its time to add login capabilities. I installed the aspnet membership tables into the database, and setup the web.config. Then I created a new controller called LOGIN, and changed the LOGIN button (previously a dummy) to use it.




ShowLoginPage - I originally had a condition on the page that indicated which action to use depending on the current user's authenticated state. But, the point of this is to not do that kind of logic on the page, so I moved it to the ShowLoginPage action. If the user is authenticated, it redirects to the Logout action. Otherwise, it shows the login page.

Logout - Easy enough... Logout, then redirect to the home page. This shows that the controllers are aware of each other. I'm not sure if that's correct, but I don't know of another way to do it, so there you go.

Login - Users will login by email address. They'll have a username too, but that'll be for display purposes. The membership provider supports login by username, so I have to find the username by searching on the email address. The Find returns a collection of users. You can retrieve from the collection by username, but we don't have a username, so we have to enumerate to the first one. That was inconvenient. users[0] would've been swell.

I haven't handled a failed login yet. Essentially, I want it to load the same view but pass it an error message. That'll be new.

Sunday, May 11, 2008

So much for that idea

The whole "swappable dal" thing didn't work out. It could've, but it would've been too much work, so I dropped it. I can play with SubSonic and the entity framework some other times.

Selecting into a new object
I created a couple view in the database and added them to the dbml. Reading is not a problem, but I'm curious how it handles attempted updates. (It is a view, afterall).

I ran into a new LINQ situation. So far, all queries have been like:

from p in this.TableName
select p




But, I only wanted a few fields from the view. How do you do that? It can't return a known object because you're specifying the fields on fly. I determined that I have to create a new object that has properties for just the fields I want, and return a list<> of those. So, I created a FamilyMember object.

I don't know if that's the right way to do it, but it works. I read a LINQ book several months ago. I'll have to get back to it. I'll absorb a lot more on the second pass due to the rudimentary hands on.

Extend the View Object

I added a new method to the vwClanFamily class.





Its used on the page in the inner loop.

Wednesday, May 7, 2008

MVC / LINQ / SubSonic / Entity Framework

When I first started goofing around with MVC.NET a few days ago, I considered looking at the entity framework at the same time. Then I figured that LINQ and MVC.NET would be enough to keep me busy

Tonight, while looking around to find answers to some mvc questions, I came across this:
http://subsonicproject.com/

I watched one of the videos, and its pretty neat. SubSonic generates the DAL layer for you. It can also be setup to regenerate the DAL every time the web site starts. (You wouldn't want to do that in production, but convenient for development). I haven't played with at all; I just watched the video, but its interesting. It looks like PRE-LINQ LINQ. I wonder if LINQ is going to be problem for them.

One nice feature of SubSonic is scripting. It creates an external tool that will script the entire db, including data, so that you can check it in. Cool.

I thought about using SubSonic for some portion of the demo site, but that'd be a pain. Rather than mentally battle over LINQ, Entities, and SubSonic, I'm going to refactor the stuff so it can use any of the three. If it works (it should), it'll allow me to play with all three. (Honestly, though, I don't plan on digging into the entity framework just yet).

I noticed one thing in SubSonic that I wasn't able to do in LINQ (at least not on the first attempt. I only spent 3 seconds on it): Partial classes. In LINQ, as shown in a previous post, I can create a partial class for the dataContext object.

I did this:

List people = _db.GetAllPeople(); //or something like that

I wanted to do:

List people _db.People.GetAllPeople();

As shown, it would have to be a static method, which isn't what I want. So, obviously, its not going to work as intended. But, the subsonic api works differently, and you can create a partial class at the table level.

So, my next task is to create an interface, a factory, and multiple implementations of the interface so that I can play with multiple DAL technologies. Stay tuned.

Monday, May 5, 2008

Tonight's MVC progress

Yesterday's post didn't go so well. The code and HTML isn't rendering correctly. Lets try screenshots.

I have the edit functionality working. I ran into one glitch along the way. The edit page is a form. I set the action attribute using Url.ActionLink, but it didn't do anything. It kept posting back to the view page. "View Source" revealed that there are 2 form tags: 1 for the master page, plus the one I added. I removed the one from the master page, and it started working. (If I wasn't able to remove the parent form tag, what would I have to do? Maybe change the parent's action instead?)



Here's the main page. Its using the master page and css provided by the template. Its nicer than anything I could've done, so I'll keep it.





The MVC links are:
Clan Admin - http://localhost:1653/ClanAdmin/Index
Home - http://localhost:1653/Home/Index
About - http://localhost:1653/Home/About
Login - http://localhost:1653/Home/Login

When you click Clan Admin, you get the really ugly list of people.




The Edit page url is http://localhost:1653/ClanAdmin/EditPerson/3. The last segment is the people id.


When you click save, it submits to /ClanAdmin/UpdatePerson/3.


Here's the UpdatePerson action.

BindingHelperExtensions.UpdateFrom is neat. It looks at the posted form and maps the element names to the object property names. So, name your controls the same as the properties, and you can do the update in one swoop. It also provides measures to prevent certain properties form being updated, but I'm not using that here.

Yesterday I mentioned that I would need to create a partial class to add more specific functionality to ClanContextData. I was going to add a class to APP_CODE, but that doesn't exist in ASP.NET. Its been removed from the ADD ASP.NET FOLDER menu. So, I put it in the controller folder, which I now think is the correct place. (The REAL right place would be a separate assembly that contains all of the business logic. But, I don't have that piece. It's all in Controllers).


Load / Modify / Reload / Save

I just read through part 4 of one of tutorials I've been using to go through the MVC stuff.

http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx

Unfortunately, it suggests that to do an update, you need to reload the object, update it, then save it. So, if the values have changed since you populated the page, then you'll just overwrite them.

Sunday, May 4, 2008

MVC.Net and Linq to SQL

I was up until 4:30am Friday night working on a database thing for work. I spent most of the day Saturday, on and off, doing the same thing. The good news is I learned all that I needed to learn, solved the problem, and built a pretty thorough test harness and MbUnit tests for it. Swell. It violated my "don't work on weekends" rule, but it was for a good cause. I had to learn new stuff, so it was to my benefit.

Anyhoo, that's a different story for another day.

When Sunday evening rolled around, we sat down to watch an Indiana Jones movie or 2 (or 3). I'm mentally unable to simply sit there and watch a movie that I've already seen, unless I'm tired or uncharacteristically mentally lazy. Typically, I need something to work on at the same time. (Well, it depends on the movie too, I suppose).

Furthermore, I've been slacking for a long time. Over the last few months, I've played A LOT of Burnout Paradise. For a while, I was feeling guilty about gaming instead of something productive, but I quickly came to terms with it. If I want to take a break, I can take a break. This one just happened to be longer than usual. Oh well.

So, now that i've thoroughly beat Burnout Paradise, and I've done enough "work" work, its time for something new. I decided to jump on this MVC.NET thing that I've been hearing so much about. And, at the same time, I might as well start using LINQ for SQL. (I dabbled with LING for collections a bit, but nothing serious).

The MVC.NET web template gets you going pretty good. It creates the MODELS, VIEWS, and CONTROLLERS folders.

Create Database
I have a vague about the website I'm going to build from this stuff, but its not real important. I started with an empty database and created a single table: PEOPLE. It has the following fields;
- PeopleId (PK int identity)
- FirstName
- LastName
- EmailAddress (nullable)
- BirthDate (nullable)
Simple... no big deal.

Create DBML
I ended up using VS2008 to crate the DBML file. Before that, I used SQLMetal just for kicks. It worked swell.

I then ran a couple quick tests on the DBML file just to get a feel for ole betsy.

ClanDataContext db = new ClanDataContext();
People people = new People();
people.FirstName = "first";
people.LastName = "last";
people.EmailAddress = "jay@allardworks.com";
people.Birthday = new DateTime(1972, 7, 2);
//PeopleId deafults to 0
db.Peoples.InsertOnSubmit(people);
db.SubmitChanges();
//PeopleId is now the new identity value

Sweet. LINQ is cool.

Modify the MasterPage
The MVC site template comes with a master page. I added an admin link to the left margin.


  • <%= Html.ActionLink("Clan Admin", "Index", "ClanAdmin") %>

  • Parameter 1 is the text that appears in the link.
    Parameter 2 is the name of the action.
    Parameter 3 is the controller.

    The existing links on the page did not specify the controller, because there was only one to start with. Once I added my ClanController, I had to change the existing links to specify the third parameter.

    The link renders as: http://localhost:1653/ClanAdmin/Index (Controller/Action)

    Controller Class
    Next, create a controller class. The controller specified is ClanAdmin. The name of the specified action was Index, so create a method called Index.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using MvcTest1.Models;
    namespace MvcTest1.Controllers
    {
    public class ClanAdminController : Controller
    {
    public void Index()
    {
    ClanDataContext db = new ClanDataContext();List people = (from p in db.Peoples select p).ToList();
    RenderView("Index", people);}

    public void EditPerson(int peopleId)
    {
    RenderView("EditPerson", peopleId);
    }
    }
    }

    That's the full Controller class. Index is the action we've already mentioned. It uses the linq entity class to get a list of all of the people. It passes it to the view via the second parameter of the RenderView method.

    The first parameter is the name of the view. So far, it seems that view names may commonly match action names, at least for navigation purposes. We have an action called index that loads a view called index.

    The second action, EditPerson, comes into play later.

    Index View
    Thew view page goes into VIEWS/CLANADMIN. VIEWS is a fixed name. CLANADMIN is the name of the controller. (What if you want multiple controllers to share the same view? Is that practical and/or possible?)

    By default, a view is just an ASPX page. However, you can change that behavior somewhere. (I'm not there yet).

    Here comes an inconvenience: When you add the MVC view page, it doesn't give you the option to select a master page. You have to create the page, assign the master page, and lop off the junk you no longer need.

    If you look back to the controller code, you'll see that the second parameter of RenderView is a List. That parameter is called ViewData, and it may be anything type you desire. In order to make the view page aware of it, you must make it a generic of that type.

    Controller / Action Method

    ClanDataContext db = new ClanDataContext();List people = (from p in db.Peoples select p).ToList();
    RenderView("Index", people);}

    NOTE: Will create a partial class to add a new method to ClanDataContext: GetPeople();

    View Page

    public partial class Index : ViewPage>
    {
    }

    Now, the ViewData property is a List.

    Lets recap. The controller retrieves the list of people and passes it to the view. Now, to keep the name VIEW honest, we must display the data.

    It looks like that while the use of ServerControls is allowed, its not encouraged. Instinct is to drop a DataGrid on the page and bind it to the list. But, all examples so far just use inline code. We end up with smaller more precise html, but we lose the flexibility of the grid control. I'm eager to see how that pans out. (I tried creating a Table object manually in code behind, but the namespace isn't included by default. I took that as a hint to not use it. For now, I'm keeping it simple. Its my first night.)

    I went with the flow and added inline code to the ASPX page.


    <% foreach (var p in ViewData) { %>
    <% } %>
    <%= p.PeopleId %><%= p.LastName %>, <%= p.FirstName %><%= p.EmailAddress %><%= Html.ActionLink("test", "EditPerson", new { controller = "ClanAdmin", peopleId = p.PeopleId }) %>



    I really don't like that. It brings me back to ASP. The difference, though, is that it'll all be compiled so you don't have context switching like ASP, but its still ugly. Not very OOPish, is it?

    I had a problem with Html.ActionLink. The second parameter is the action. Nothing I've found via google shows that parameter being specified. The anonymous third parameter becomes a RouteValueCollection. All samples I've seen specify the action there. But, when I do it, I get a method overload exception. Its trying to use the (string, string) signature, which is invalid. (This may be due to the fact that I'm using Preview 2. Most samples are Preview 1).



    Edit View
    Now that we have a list of people from the database, I'd like to edit a person. Notice the Html.ActionLink in the last cell. It creates a link with text of "test". It'd be better to use p.LastName or something, but its junk code. The second parameter is the name of the action. Earlier, we saw the action defined in the controller class as shown:


    public void EditPerson(int peopleId)
    {
    RenderView("EditPerson", peopleId);
    }

    That's not how it will end up looking. The second parameter should be a PEOPLE object, but for now, I'm just passing the PEOPLEID to show that it works.

    To support this, I created a second view called Edit, then simply print the ID (stored in ViewData)

    Class: public partial class EditPerson : ViewPage
    ASPX Code:

    ID: <%= ViewData %>



    Super. But, as I expected, it didn't work. The existing routes all treat ID as string, so there was a data type problem. I added a new route.


    routes.Add(new Route("{controller}/{action}/{peopleId}", new MvcRouteHandler())
    {
    Defaults = new RouteValueDictionary(new { peopleId = -1 })
    });

    I thought that would work, but it didn't. Then I remembered that the first matching route found wins. So, I moved that route to the top of the list, and now it wins. (I'm not 100% convinced this is all correct yet. This new route may be getting picked up in other scenarios when it shouldn't be. We'll see.)

    Now, when you click the TEST link, it goes to the EDIT page and displays the PeopleId.

    The URL to the edit page is:
    http://localhost:1653/ClanAdmin/EditPerson/3
    The page then shows the #3.
    Because nothing is implemented yet, you can change 3 to any integer that you want, and it will display.

    That's it for Tonight
    The next steps are:
    - Use Linq to retrieve the people object. (Create the partial class mentioned earlier, and add a GetPerson(int peopleId)
    - Create the edit page. MVC.NET has some stuff to make this easier. I need to learn the details.
    - Figure out how to save. When saving, do I have to load the People object, change values, then save? Does MVC have a standard approach to this? (The People object will most likely be persisted somewhere. I don't know if that's my task, or something MVC helps with. If we do the reload/modify/save, then we lose Linq's conflict resolution capabilities. We want to keep that.)

    Wednesday, April 16, 2008

    Email Decision

    Greetings

    I love IMAP. Its great.. I can use the webclient when I'm away, and any other client when I'm at home. Everything stays in sync. No hassel. With POP, each client is only aware of the messages it created. If one downloads a message without saving a copy on the server, then the other doesn't get it. Its a pain.

    IMAP good.

    Here's my setup: I have a hosted mail server for AllardWorks.com. I've been using Spam Arrest for years to filter out the spam. (Incidentally, SPAM ARREST is the best spam product I've ever seen). SPAM ARREST downloads the messages from allardworks.com and does its thing. I used to use the SPAM ARREST web page and use Outlook Express as my at-home client. They both connect to SPAM ARRESTS servers rather than the allardworks servers.

    Here's the problem with Spam Arrest: The spam arrest web client is minimal at best. It really hasn't improved much in the years I've been using it. Its really simplistic and ugly. Seriously guys, update the CSS once in a while! I jest. But really! No, I'm kidding. Or am I?

    GMAIL, on the other hand, is a lot nicer. I don't think it looks great, but its a lot more functional. The label feature is neat. (Its the equivalent of putting the same message in multiple folders). Several months ago I changed to the GMAIL client. GMAIL -> SPAM ARREST -> ALLARDWORKS.COM. That's a roundabout way of getting there, but it works well.

    Here's the problem with GMail: My gmail address is HamletCode@gmail.com. When I send a message from GMAIL, I don't want anyone to know it. I want the message to appear as FROM JAY@ALLARDWORKS.COM. But, there's no way to do that. You can set the reply to address, and the from address, but underneath it all, it still sends a hamletcode header. Its received as "from hamletcode@gmail.com on behalf of jay@allardworks.com". That might be backards, but either way, its not what I want. People keep asking me what hamletcode is when, really, that's just my account name. I've been using jay@allardorks.com for probably 12 years. I'm not interested in changing it.

    I put up with that for a few months, then decided against it. Last night, I moved all of my messages from GMAIL back to SPAMARREST via OUTLOOK EXPRESS. Spam Arrest offers 1 gig of storage, which should last a while. Gmail offers 6 gigs.

    Points
    - The SPAM ARREST web mail interface is crappy, but the spam service is unmatched.
    - SPAM ARREST offers only a gig of disk space. I suggested a feature to allow users to buy more space. We'll see if that happens when the time comes. (I'm now of the mindset that I'd like my email stored on a server, not just locally)
    - GMAIL has a better interface, but I wouldn't call it top-notch.
    - GMAIL is very generous with its drive space allotments.
    - GMAIL messes everything up by revealing that the message is coming from a gmail address.
    - YAHOO MAIL has the best interface I've seen, but they don't offer IMAP (I haven't seen many interface though)
    - I put in a feature request to ask SPAM ARREST to offer increased disk space
    - I put in a feature request to ask SPAM ARREST to show how much space is in use
    - Hotmail is a pain... I couldn't get into it with my existing windows live ID. It kept throwing exceptions. It looks like a pretty serious bug, which surprises me. It would be nice to actually see it to determine if it helps me at all.

    In the interest of full disclosure, I must fully disclose that my track record with Spam Arrest hasn't been perfect. One time I asked them how to delete a contact (or something like that). They directed me to the "delete contact" button. That was embarassing, though anyone who knows me would probably find it suprising that I couldn't find it on my own. Last night I asked them if they had plans to offer IMAP. They said "yes, we already do". That was embarassing too. I don't fully blame myself, though. I'm computer saavy. Clearly its not working the way I'm accustomed to, though I'm not spending enough time researching stuff. Also, the search engine (or the content) leaves a lot to be desired.

    Example 1: Search for DISK, then QUOTA on spam arrest. It doesn't come up with anything. Then search for SPACE, and you finally find what I was looking for: The disk limit.

    Example 2: Search for IMAP. The three results are:
    1 - Multiple Protected Mailboxes - accessing other mailboxes outside of spam arrest
    2 - What is a pop server? - If you open that, it gives you some IMAP information, but if the name of the article is POP, why would I open it if I'm looking for IMAP?
    3 - Options page - does that answer my question? I didn't ask about options, I asked about IMAP.

    Search #2 is what prompted me to ask them if/when they were going to going to offer IMAP, so I don't feel guilty about it. I searched. The results were dissapointing.

    One may ask why I don't just use my own mail server rather than jump through all these hoops
    - First of all, I'm not really an email administrator. I've had to fight through some issues for other clients of the server, but its not my cup of tea. I learned a lot, but that doesn't make me qualified.
    - I have space restrictions. Its not very generous, either. I don't want to waste space when other services offer more space for free or for fee. (I pay for spam arrest).
    - I'm responsible for backing up the mail server, which I don't do. None of the clients (other domains, same server) use the server to persist their messages; they download them and delete them from the server. I make no claims for redundancy, etc. Since I want redundancy for my own email, I clearly can't count on my own server.

    Then, you may ask why not host allardworks.com elsewhere where responsible people can take care of all the details for me?
    Mainly, I don't want to incur the cost of the non-jay users. I have a few friends and family at allardworks.com. To relocate, I'd have to pick a plan that allows for multiple mailboxes, which I'm not prepared to do. Nor am I willing to tell them that they can't use AllardWorks.com anymore. I spoke to TUFFMAIL.COM, which has potential if the spam arrest approach doesn't work. They assured me that even if I leave allardworks.com right where it is and use them just for storage/web client, TUFFMAIL will never show up in the headers. Also, there's a 30 day free trial, so I can check it out first. (The disk limits aren't generous, though, which is why I'm not going to do it until I need to.)

    Fun, right?

    Tuesday, April 1, 2008

    Static variables and singletons

    I planned on putting this online Saturday night, but I got lazy. The laziness lasted longer than expected, but at long last, here we go.

    This is just a paste of a word document. If you want a copy of the doc, let me know and I'll email it to you.

    Next task: Figure out how to more effectively use blogger to post this sort of thing.



    Jay’s Current Stance on Singletons and Static Variables
    3/29/2008

    "I hate being quoted" - Jay Allard



    Overview
    Singletons are really convenient. I’ve used them for many things over the years. As I’ve evolved, I’ve changed my stance on them several times. The changes range from minor tweaks to “why in god’s name did I ever think that was a good idea?”

    This rant describes where I currently stand with singletons, static variables, and how I came to my current opinion.

    Mixing Static and Instance State
    Just a quick blurb based on some object I’ve seen. An object should not, in most circumstances, have any static data.

    I ran into a situation on a side project a while back. I had to add new functionality to an existing object. I created unit tests for the object to define the new functionality.

    In each test, I instantiated the object and tested whatever I wanted to test. The tests were working apparently randomly, but not really. Sometimes things passed, sometimes they failed.

    It turns out that even though I was instantiating the object, it was driven by a lot of static data. So, instantiating a new instance gave you a new instance, but everything driving the object was static. Once the first instance was created, the static data was populated, so the subsequent tests didn’t behave as expected. Instantiating the object didn’t actually do anything. The instance was just exposing static data.

    If you instantiate an object, you should get a fresh new object. If that object loads a bunch of stuff and you only want to load it once, then use another pattern. Either use a singleton so that it’s clear that it’s shared data. Or, don’t bother giving it a constructor at all. Make it a static object.

    I only advise the creation of a static object, or singleton, as a better alternative to an insignificant instance. The better solution follows.

    What is a Singleton?
    A singleton is an instance of an object that is shared in the app domain. Rather than recreating the same type of object multiple times, just create it once, and allow everyone to use it.

    Lets use a new cache object as an example. We’re going to ignore the fact that there are plenty of caches available, and build our own.

    Cache cache = new Cache();
    cache.Add("test", new object());
    cache.Add("test 2", new object());

    Now, you can retrieve things from the cache by key.

    string hello = cache["test"];
    string world = cache["test 2"];

    Simple, right? Realistically, though, you only want to create the cache once then make it globally available. If you converted the cache object to a singleton, in its simplest form you would get:

    Cache.GetCache().Add("test 3", new object());
    Cache.GetCache().Add("test 4", new object());

    You could alternatively change GetCache() to be a property name. Technically, that would work, but I disapprove. The method approach is, logistically, more accurate. You’re telling the object to do something. (It can be argued either way, but I’ll always use a method)

    You may also see that we can achieve the same thing by exposing a public static variable. That’s smarts. Statics are the basis of the singletons, and a lot of times that may be the way you go, though I won’t.

    By the time you get to the end of this document, you’ll learn that I no longer do singletons as described above. I do it with a slight design driven variation. But, the concepts are the same, so lets work through it.

    Candidates for a Singleton
    No State
    A singleton is basically a server object. It can’t maintain state between calls because its getting hit by multiple threads at once, all with their own agenda.

    Pay pay = new Pay();
    pay.Hours = 3;
    pay.PayPerHours = 375.00;
    decimal myMoney = pay.Pay;

    The Pay object cannot be a singleton. Multiple threads would overwrite the properties. By the time you got to “pay.Pay”, the state is completely unpredictable.

    If you converted Pay to be method driven, you could then make a singleton of it.

    int myMoney = pay.CalculatePay(3, 375.00);

    Thread Safety
    Thread safety becomes very important. If your object supports read and writes, then you have to manage the threads to make sure they don’t step all over each other.
    For example, suppose the object checks a cache for a value. If the value is there, it returns it. Otherwise, it does a db lookup, populates the cache, then returns it. What if that happens twice simultaneously? Does the object end up on the cache twice?
    Creating a Singleton
    A singleton is an instance of an object assigned to a static variable.

    Initialization
    Option 1 – Inline Initialization – Jay’s Preference

    In most cases, this is how I go about it.

    public class Cache
    {
    private static Cache _cache = new Cache();

    That will get compiled into to the constructor anyway, so its not much different from #1. I just like the syntax better.

    In option #1, you saw that I added some initialization statements. How would you do that here?

    public class Cache
    {
    private static Cache _cache = CreateCache();
    private static Cache CreateCache()
    {
    Cache cache = new Cache();
    cache.GetCache().Add("test 7", new object());
    cache.GetCache().Add("test 8", new object());
    return cache;
    }

    Note: This is only prudent when the object doesn’t have anything else to do. It’s just a cache; it doesn’t have any other functionality. That should usually be the case, but if you have a helper class with lots of stuff in it, then you may inadvertently create the cache when you do something irrelevant.

    The static constructor is thread safe, so you don’t have to worry about thread management. It will only get hit once.
    Option 2 - Static constructor
    For some reason, I used to like using the static constructor. For some reason, I don’t like it anymore.

    static Cache()
    {
    _cache = new Cache();
    }

    This gives you the opportunity to do some initialization right after you create it.

    _cache = new Cache();
    _cache.Add("test 5", new object());
    _cache.Add("test 6", new object());

    When an object has a static constructor, a flag is checked each time the object is hit to make sure that it has already been called. Regardless of how we do this, something is going to have to be checked on each visit anyway, so don’t get hung up on that.

    Repeat Note: This is only prudent when the object doesn’t have anything else to do. It’s just a cache; it doesn’t have any other functionality. That should usually be the case, but if you have a helper class with lots of stuff in it, then you may inadvertently create the cache when you do something irrelevant.

    The static constructor is thread safe, so you don’t have to worry about thread management. It will only get hit once.
    Option 3 – Lazy Load
    Back when I was a boy, this was my preferred approach. I did it this way to make sure that it only got created as needed, not when the class was used for any other reason. Since objects should only do one thing, that shouldn’t be a concern, so I don’t do this anymore. But, here you go.

    private static object _singletonLock = new object();
    public static Cache GetCache()
    {
    if (_cache != null)
    {
    return _cache;
    }
    lock (_singletonLock)
    {
    if (_cache != null)
    {
    return _cache;
    }
    _cache = new Cache();
    return _cache;
    }
    }
    Since this is a method, we’re responsible for the thread safety.
    First, check to see if _cache already exists. If so, return it.
    If not, lock the next chunk of code. We want to make sure only one thread hits this at any given time.

    Check _cache again. It may have been created, by another thread, since the last time we checked. If it exists, then return it. Otherwise, create it then return it.

    This Lock/Check/Lock approach doesn’t work in java. I read a bunch of stuff a few years ago. It was a hot topic, and it was proven that regardless of how logical the code is, it didn’t compile as you’d expect, so it wouldn’t work.

    I only know it works in .Net based on experience. I should compile it and look at the IL to make sure its doing what I think its doing. It would be a great exercise. But, thus far, I have no reason to suspect that its not working.

    A lesser approach is to lock the entire method. I don’t like that at all, though, because it only needs to be locked once, yet you’re locking it every time. Crazy, right?

    Constructors
    Once you’ve created an instance of your singleton object and assigned it to a static variable, are you done?

    Possible Answers:
    A: No
    B: No

    The correct answer is B: No. You are not done; at least, not if you want to enforce the SINGLE INSTANCE ONLY part of the singleton.

    public class Cache
    {
    private static Cache _cache = CreateCache();
    private static Cache GetCache()
    {
    return _cache;
    }

    Now, you can quite easily use the singleton.

    Cache.GetCache().Add("Test 9", new object());
    Cache.GetCache().Add("Test 10", new object());

    Smashing. But, what’s to stop you from doing this?

    Cache myLocalCache = new Cache();
    myLocalCache.Add("Test 11", new object());
    myLocalCache.Add("Test 12", new object());

    Nothing is stopping you. By the definition of Singleton, you should stop it. You stop it by adding a private constructor. The private constructor will prevent any other object from instantiating cache


    Final Product
    public class Cache
    {
    private static Cache _cache = CreateCache();
    public static Cache GetCache()
    {
    return _cache;
    }
    private static Cache CreateCache()
    {
    return new Cache();
    }
    private Cache()
    {
    }
    public void Add(string key, object value)
    {
    //do someting
    }
    public object this[string key]
    {
    get
    {
    // do lookup
    return null;
    }
    }
    }

    Now we’re sitting pretty. The only way anyone can use your cache object is by calling Cache.GetCache(). In order for this to work properly, your implementation must be thread safe. Your methods may get hit multiple times simultaneously.

    That’s All Great, But Don’t Do It!
    Did I just waste 5 pages? No, its all valid information. And I’m being over dramatic when I say “don’t do it”. That’s your choice go for it.

    None of my business
    I’ve come to the determination that it should be up to the application to decide what is a singleton and what is not. Who am I to say that there should be one and exactly one Cache object? Maybe the application would like to create 5 cache objects for different things. (Please keep in mind that this cache object is an ambiguous example. The question applies to anything that you want to make a singleton.)

    If you come to the conclusion that you, as an object developer, have specific reasons to make sure that there is only one instance in any app domain, then it is your prerogative to make it a singleton yourself. What are some examples?
    Maybe your object opens up a specific TCP port and listens on it. You can’t do that more than once. (Though, if the port was a parameter, then you could).
    The Windows Workflow engine can only be started once per app domain. Somethine like that is a good candidate. (For the record, I don’t think WF should be a singleton for the reasons described in this section. But, it could be.)
    I’m out of examples, but just 2 bullets is a waste of bullets. A list needs at least 3 bullets to be respectable.

    I’m sure there are plenty of other examples, but in my experience, I’ve used singletons for convenience rather than necessity. I wanted my application to share one cache in an easily accessible way.

    It comes down to this: Build objects. Let the consumer of the objects decide what they want to do with them. Its none of your business.

    Testing
    TDD is one of the primary forces that drove me to stop doing singletons.
    In practicality, if you decided that you wanted something to be a singleton, then for most purposes its fine as a singleton. But, when you add testing to the equation, it becomes more problematic.

    For example: As I develop my cache object, I’m going to write a ton of unit tests. Each of those tests should be stand alone (ie: not victim of anything that happened before it; won’t influence anything that happens after it?) How do you do that with a singleton?

    For example, the test may be to add three items to the cache, then make sure the cache has three items.

    The next test may be to make sure the cache initializes to empty. If the cache exposes a Clear() or Remove() method, then you can do it. If it doesn’t, then you’re stuck. The singleton instance is already populated. Test #2 will fail.

    That’s only one minor example. We can invent plenty more.
    Evolution Step 1: Default Singleton and Instantiate a Class

    The previous conclusions were formed over time. Along the way, I took an incremental step towards supporting them. This worked out well since we already had existing singletons, but I wouldn’t do it for anything new.

    One of the key parts of the singleton is the private constructor. The private constructor prevents anyone from instantiating the object. It remains entirely in your control, not the consumer’s.

    Step 1 of the evolution was to eliminate that contructor, and change the getter to GetDefaultInstance.

    public class Cache
    {
    private static Cache _cache = CreateCache();
    public static Cache GetDefaultInstance()
    {
    return _cache;
    }
    private static Cache CreateCache()
    {
    return new Cache();
    }
    //private Cache()
    //{
    //}
    public void Add(string key, object value)
    {
    //do someting
    }
    public object this[string key]
    {
    get
    {
    // do lookup
    return null;
    }
    }
    }

    Now, you can either use the default instance (the singleton), or create your own. Technically, though, this is no longer a singleton. A problem with this approach is that the singleton is created even if you never use it. This could be a good place to use the Lazy Loading approach

    Evolution Step 2: Have your application do it.
    You have created a cache object and made it available to your applications. Its up to your application how to use it. If your application decides that there should be one and only one instance of the cache object for the entire application, then it can manage it.

    public static class ApplicationCache
    {
    private static Cache _cache = new Cache();
    public static Cache GetCache()
    {
    return _cache;
    }
    }

    Now you can use ApplicationCache.GetCache() to get to your single instance of the cache object. (Of course, that doesn’t stop anyone from creating their own Cache if they’d like to).

    If you have a few things like that, you could have one static class to expose them all to your application.
    Conclusion
    Going forward, I don’t see myself creating any objects that are automatically singletons. If I need a singleton, it will be at the application level.

    The singleton is a very basic pattern that’s probably not worth 9 pages of information. But I did it anyway. I hope you find it useful.

    Monday, March 10, 2008

    MAC and no cheese

    For some unexplainable reason, I was wondering how I would go about manually changing the MAC address of my wireless network card. I was just curious if it could be done incase I ever happened to go to a hotel that charges $13/day/laptop, and I didn't want to spend $26/day in addition to the hundreds of dollars already being spent.

    My research revealed that you could theoretically signup for the internet service with one laptop, then change the macaddress on the second laptop so that the hosting service doesn't know the difference. The one problem that I might someday theoretically run into is that perhaps the hypothetical service always issues the same IP address to the laptop with the recognized mac address. That would mean that while both computers could both connect to isp, only one can do it at a time. That would be ok, right? Better than $26/day, should the situation ever arise.

    If this were to ever come up, I would search google for a means of changing the mac address when the NIC properties doesn't allow for it. Maybe I'd find a program called MACSHIFT to help out. We may never know.

    I believe the moral of the story is: pack a router.