in

Telligenti

Serving up fresh ideas every day, Telligent style

Dan Hounshell

  • Lan and Deon #3

    Lan and Deon go to their local .NET User Group meeting...

    Those who live in glass houses...

     

  • I like VisualSVN

    VisualSVN I'm not a big fan of Source Code Management integration with Visual Studio. I don't know, maybe VSS soured me years ago. When using Vault in the past I installed the Visual Studio integration tools once and uninstalled them a few days later. While using Subversion almost exclusively over the last three years I've been more than happy using TortoiseSVN in an explorer window. The separation of SCM and programming IDE has been refreshing and actually lends itself well to the way Subversion works by default, not requiring a checkout or lock when editing a file.

    A few months ago, however, I won a license for VisualSVN at the Indy Code Camp. The license sat on a table beside my desk for about a month before I finally decided to give it a spin. I have to admit that I'm growing fond of it. I still don't run updates and commits inside VS using VisualSVN (even though it just defaults to TortoiseSVN), but I really like the visual indicators that it provides. Showing me which files I've added or modified with the yellow icon greatly reduces any chance of me forgetting files when I make a commit. Or it helps me quickly find any files that I may have forgotten to commit.

    The other cool thing is that when I add any new files to a project via Visual Studio, VisualSVN automatically adds the file to SVN. I don't have to remember to browse to the file in Windows Explorer, right click the file, choose TortoiseSVN and then click Add. That may not seem like much of a time saver, but I always forget to manually add the files until after I've done commit (and maybe broken the build).

    Even it you don't like mixing your chocolate and peanut butter, um... I mean SCM tools with your IDE, you may like some of the features that VisualSVN provides. Give it a try, they offer a 30-day trial and the licenses start at $49 per seat.

    Okay, that probably came off sounding like a commercial for VisualSVN. I am in no way affilated with the product or company and I stand to make no money from a couple more licenses being sold. I simply like the product and I thought I'd pass on my experiences with it. Besides, "if I can change and you can change, we all can change!" :)

  • Adding OpenID to your web site in conjunction with ASP.NET Membership

    AspDotNetMVC_OpenIdLoginI recently added membership, accounts, login, etc. to the AspDotNetMVC site. While doing so I decided I wanted to support OpenID, too. However, I didn't want to go with only OpenID because I needed ASP.NET Membership in place to work in conjunction with another application, a Kigg site used as a service for rating content on the AspDotNetMVC site. I could have probably converted the Kigg code base to use OpenID but I also wanted to allow people who may not have OpenID to create traditional accounts on the site without signing up for OpenID. Following are the steps I took to implement an OpenID login and integrate it with "traditional ASP.NET" membership. Follow these six steps and you can do the same.

    1. Download the awesome C# OpenID library, DotNetOpenId from Google Code, and add it as a reference in your project. This is a great open source library developed by Andrew Arnott, Jason Alexander, Scott Watermasysk, Scott Hanselman, Joe Brinkman and others. It seriously does all the heavy lifting, comes with some good examples, and Andrew Arnott is doing a great job of making posts about fringe cases on his blog.

    2. Add some nice usability features to your OpenID login. Go to ID Selector, create an account and grab the couple of lines of JavaScript to create the cool OpenID service selector shown in the image at right.

    Did I mention that this is so easy that I don't know why everyone isn't supporting OpenID? Going forward I will be doing so in every new site that I create and I'll retrofit existing sites when I get the chance.AspDotNetMVC_OpenIdLogin2

    3. Read the following articles:

    After reading each of the above you will have a pretty good understanding of how ot add OpenID to your site. Some of the code examples in the earlier 3 posts by Andrew are a little out of date. As of the writing of this post the code provided in Hanselman's blog post are the most up to date. Go ahead and read the two "MVC" posts by Andrew even if you are not interested in ASP.NET MVC. The concepts displayed in those posts can be used anywhere. In fact, it was in of those posts where I found my inspiration for overcoming my next hurdle.

    The only thing that was missing for me was integration with ASP.NET membership. I actually found very little information for accomplishing this. I found quite a lot of questions asking how to do it, but most of the answers were just more questions asking why you would want to do it.

    4. Create your login form (or user control or composite server control or whatever you prefer). In my case I created a user control that holds just the fields for OpenID login to my user control. Doing so allows me to drop that control into my existing login page (shown in image above) or my existing create account page or anywhere else I want to use it. Make sure you add the javascript for the ID Selector.

    For allowing traditional ASP.NET membership login and user account creation I just dropped the basic out of the box controls on the page.

    5. Wire up the login submit button. I did something like below, which is very similar to examples that Andrew and Scott Hanselman provided. Basically I'm just telling the OpenID provider that I need the user's email and nickname (for use in the next step):

    protected void loginButton_Click(object sender, EventArgs e) { if (!openidValidator.IsValid) return; // don't login if custom validation failed. OpenIdRelyingParty openid = new OpenIdRelyingParty(); try { IAuthenticationRequest request = openid.CreateRequest(openid_identifier.Text); ClaimsRequest fetch = new ClaimsRequest(); fetch.Nickname = DemandLevel.Require; fetch.Email = DemandLevel.Require; request.AddExtension(fetch); request.RedirectToProvider(); } catch (OpenIdException ex) { // The user probably entered an Identifier that // was not a valid OpenID endpoint. openidValidator.Text = ex.Message; openidValidator.IsValid = false; }}

    6. Handle the response from the OpenID provider. This snippet of code is part of the login process and expands upon examples from Andrew Arnott's and Scott Hanselman's posts linked to previously.

    Here I'm pulling the alias and email address that I requested in the previous step. With that information I check to see if the user already exists in the ASP.NET membership datastore. If not I will create a Membership account for them using their OpenID URI as their username. When I create the account you can see that I'm generating a random string for the user's password field and password answer field. You'll also see that I'm adding "This is an OpenID account. You should log in with your OpenID." as the password question. That way if a user forgets they used OpenID and tries to login through the traditional username/password login form and selects that they forgot their password when the login doesn't work, he or she will get a reminder about their OpenID in the form of the password question. I know it's a hack, but it works for now for my modest needs and I'm happy with it.

    Next you'll see that after I create the Membership User I then set the user's "comment" field to their Nickname. This is because the "Hello, Username. Welcome back to the site." message at the top of the page would normally display the user's "username". In the case of OpenID users their username would be their OpenID URI - something like: http://danhounshell.openidprovidername.com/. That's a bit ugly and I'd rather use the Nickname that I asked from then when they logged in with OpenID. By shoving the Nickname into the comments field I can check to see if that is filled in first and use it in the display rather than their username and if it is not then default to the username. So now using my previous example it will say "Hello, DanHounshell. Welcome back to the site." This same thing could be accomplished in a couple of other ways. Throwing the nickname into the session object or putting in a cookie are other reasonable alternatives. In my case I don't use the comments field for anything else so once again - I know it's a hack, but it works for now for my modest needs and I'm happy with it. Plus it's easy to get to my just writing "user.Comment". Thinking about it, it might be nice to write an extension method for MembershipUser called DisplayName that determines whether to use the user.Comment property or the user.Username property.

    Finally, I just call FormsAuthentication.RedirectFromLoginPage() passing in their OpenID URI that they provided, logging them into the site.

    case AuthenticationStatus.Authenticated: ClaimsResponse fetch = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse; string alias = fetch.Nickname; string email = fetch.Email;   if (string.IsNullOrEmpty(alias)) alias = openid.Response.ClaimedIdentifier; if (string.IsNullOrEmpty(email)) email = openid.Response.ClaimedIdentifier;  //Now see if the user already exists, if not create them if (Membership.GetUser(openid.Response.ClaimedIdentifier) == null) { MembershipCreateStatus membershipCreateStatus; MembershipUser user = Membership.CreateUser(openid.Response.ClaimedIdentifier, Common.GetRandomString(5,7), email, "This is an OpenID account. You should log in with your OpenID.", Common.GetRandomString(5,7), true, out membershipCreateStatus); if (membershipCreateStatus != MembershipCreateStatus.Success) { loginFailedLabel.Text += ": Unsuccessful creation of Account: " + membershipCreateStatus.ToString(); loginFailedLabel.Visible = true; break; } user.Comment = alias; Membership.UpdateUser(user); } // Use FormsAuthentication to tell ASP.NET that the user is now logged in, // with the OpenID Claimed Identifier as their username. FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, chkRememberMe.Checked); break;

    That's all there is to it. Now you can allow your user's to choose whether they'd like to create an account on your site by creating a new username and password or by using their new or existing OpenID. The bonus with this method is that it allows you to add OpenID support to an existing site that already has traditional membership without breaking anything.

    Enjoy and let me know if you have any questions or comments.

  • How to use Kigg as a service from other sites

    AspDotNetMVCGetsKigg

    In yesterday's post I started providing some detail about my use of Kigg to add rating functionality to the AspDotNetMVC site. Because I wanted to integrate the ASP.NET Membership store between the two sites into an external database I started by decoupling the membership data from the Kigg database, model and code.

    My end goal was to allow visitors to the AspDotNetMVC site to view the number of existing votes for each article (blog post, buzz, news, or video) and to vote for an article if they were logged in without having to jump over to the Kigg site to do so. Because each of the items listed on the AspDotNetMVC are basically just pointers to some content on the Internet at a unique URL I needed a way to request the rating count from Kigg by URL. I also needed a way to vote for an article by passing some (url, title, description, category, tags and user) from the main site to Kigg. Of course as a web developer my first thought was to create a web service in Kigg with two methods, GetVoteCount(url) and SubmitOrVote(url, title, desc...). Since I had never previously created a WCF web service I chose to go that route rather than the asmx approach.

    YMMV, but the first thing I needed was a new method in my Kigg data model to allow for retrieving the "story details" by url rather than id. In Kigg, like Digg, a story is an item submitted to the site. Since I'd be using an external site I wouldn't know the ID of a story (or care what the id was) I wanted to be able to perform lookups by the story's URL. I added the following to the KiggDataContext model (and the signature to the IDataContext interface):

    public StoryDetailItem GetStoryDetailByUrl(Guid userId, string url) { return Stories     .Where(s => s.Url.ToLower() == url.ToLower()) .Select(s =>     new StoryDetailItem {     ID = s.ID, Title = s.Title, Description = s.Description, Url = s.Url, Category = s.Category.Name, Tags = s.StoryTags.Select(st => st.Tag.Name).ToArray(), PostedBy = new UserItem(s.PostedBy), PostedOn = s.PostedOn, PublishedOn = s.PublishedOn, VoteCount = s.Votes.Count(), HasVoted = (s.Votes.Count(v => v.UserID == userId) > 0), VotedBy = s.Votes     .OrderBy(v => v.Timestamp) .Select(v => new UserItem(v.UserID)) .ToArray(), Comments = s.Comments .OrderBy(c => c.PostedOn) .Select(c =>     new CommentItem {     PostedBy = new UserItem(c.PostedBy), PostedOn = c.PostedOn, Content = c.Content }     ).ToArray() } ) .FirstOrDefault(); }
     

    This is very much just a copy and paste of the existing GetStoryDetailById method, just querying by URL rather than ID.

    Next I needed to create the web service and two new methods in it. I created the service at /services/KiggService.svc and the two methods look like the following:

    [WebGet(ResponseFormat = WebMessageFormat.Xml)][OperationContract]public string GetVoteCount(string url) { //MembershipID doesn't matter because we're just getting the vote count. Guid _currentUserID = new Guid(); IDataContext db = new KiggDataContext(); var story = db.GetStoryDetailByUrl(_currentUserID, url); if (story != null) return story.VoteCount.ToString(); return "0";}
    [WebGet(ResponseFormat = WebMessageFormat.Xml)][OperationContract]public string SubmitOrVote(string userid, string url, string title, string desc, string categoryName, string tag){ if (string.IsNullOrEmpty(userid)) return("You must be authenticated prior hitting this url"); Guid _currentUserID = new Guid(userid); Category[] _categories; IDataContext db = new KiggDataContext(); _categories = db.GetCategories(); try { Category cat = _categories.First(c => c.Name == "General"); if (!string.IsNullOrEmpty(categoryName)) { cat = _categories.First(c => c.Name.ToLower() == categoryName.ToLower()); } var categoryId = cat.ID; var story = db.GetStoryDetailByUrl(_currentUserID, url); if (story == null) { db.SubmitStory(url, title, categoryId, desc, tag, _currentUserID); return "1"; } else { db.KiggStory(story.ID, _currentUserID, 3); var story2 = db.GetStoryDetailById(_currentUserID, story.ID); return story2.VoteCount.ToString(); } } catch (Exception e) { return "error" + e.Message; } }

    There's not much to the GetVoteCount method, it just checks to see if a story already exists in Kigg for the given URL, if it does then it returns the vote count, otherwise it returns 0.

    The second method SubmitOrVote probably needs a little more explanation. It allows for a user to click a vote button on the AspDotNetMVC site and if the story already exists then it adds an additional vote. If the story does not already exist in Kigg then it submits it. Sounds simple enough. Since the category the story belongs in is passed in by a string I need to check the categories that exist in Kigg to find a match for that passed in categoryName string. First I set "cat" to the default category, "General", and then try to find the match. If there is a match then I use the Kigg category that I found, otherwise I stick with General. Next I just lookup the story and then give it the additional vote or create it if it doesn't exist and then return the appropriate new vote count.

    You'll notice that I'm passing the userId across the wire. In my case it's not a big deal because my calls to the service are done server side in my client application and the Kigg site is not publicly accessible. Since the Kigg site is only accessible by the AspDotNetMVC site I also don't have to worry about authentication or authorization either. Again YMMV. Also you may not want to expose your exception like I have to callers of your Kigg service. In my case it's fine because I'm the only one calling it and I wanted to be able to log any exceptions in the client application for later review.

    You'll have to add appropriate error handling around the calls to these web service service and it would be a good idea to cache the votes for each article/url/story in your consuming application so you aren't calling that method every time you need to show the votecount.

    That's all the adjustments that you need to make to Kigg to allow it act as a service for other applications. I'll admit that it did take me a while to get the web.config setup properly to allow for the WCF services, but that has more to do with my first time doing doing anything with WCF than it does with the Kigg updates. If you have any WCF experience at all I'm sure it will take you much less time than the 30 minutes I spent doing so (mostly spent searching for answers on Google).

    Hopefully these last two posts will provide you with a jumpstart for integrating Digg-style ratings (um... I mean Kigg-style) into your existing or new web applications. Have fun with those new mashups.

  • How I got started in Software Development

    I've finally gotten around to answering Michael Eaton's question: How did you get started in software development?

     

    How old were you when you started programming? How did you get started in programming?

    I think that the first time that I got the concept of writing instructions for computers to execute was probably somewhere around 7th or 8th grade - 12 years old I guess. A couple of classmates were playing around on the one Apple IIc (?) in our math classroom and wrote one of the all time classic computer programs, something similar to:

    10 print "Danny Hounshell shops at goodwill"20 goto 10

    A couple of years later I was finally able to get a Commodore64 and typed in every program from every magazine I could get my hands and tweaked them as much as I could.  Later in high school I took Computer Programming I and Computer Programming II, both BASIC on an old Apple II - we had one Macintosh, that had just come out, but we didn't get to work with it much.

    What was your first language?

    BASIC was my first language. I was exposed to several different flavors: the Commodore BASIC that I had at home, whatever the BASIC was for the Apple II's that I used at school, and then I had a friend who had an Atari and another who later had an Amiga.

    What was the first real program you wrote?

    The first real program that I wrote was the culmination of Computer Programming II class in high school. At the time text based games like Zork were at their peak in popularity. I wrote a text-based baseball simulation that was based on the current (at the time) lineup of the Cincinnati Reds. If you threw heat at Dave Parker low and inside he would knock it out of the park! And when you batted you faced Jose Rijo on the mound, the Red's once-upon-a-time unhitable ace.

    The next real program that I wrote was probably 10 years later using VB3. It was a Roulette game and was my final project for the Intro to Programming (Visual Basic) class at Miami University.

    In the time in between I spent 6 years in the Army and had a couple of short stints working with training software and building ammunition and meal forecasting spreadsheets, which I found I was pretty good at, but never any "real" programming. They usually don't let grunts touch computers.

    Later, while working at a paper company as an intern just before starting my programming classes, I found something wrong with some queries (a couple of years later I realized in was SQL) in some reports for our inventory system that were causing duplicate counts to be reported for some parts. By fixing the query I "reduced" our inventory by about a million dollars (about 15%) in about 30 minutes of work.

    What languages have you used since you started programming?

    Miami did a good job of exposing us to different languages. In my classes I worked with Visual Basic (3 & 4), Visual C++, Assembler, JCL, COBOL, VBScript (ASP), some SmallTalk, and more VC++ (in that order) and SQL of course. Miami has since moved to JAVA rather than the Microsoft stack, so if I ever decide to go back for more I may have to learn something new.  Since joining the ranks of the employed I've mostly used VB, VBScript (ASP), VB.NET and C# along with SQL and the normal web stuff (HTML, CSS, JavaScript). 

    After my first experience with ASP I knew I was hooked on web development. I took the ball and ran and I haven't looked back since.

    What was your first professional programming gig?

    Before leaving the previously mentioned paper company I wrote some intranet type applications in ASP (pages for departments and a conference room reservation system) but since I was actually paid to be an intern for the maintenance department so those really don't count.

    My first real job in the biz was for a web agency in Cincinnati that was quickly getting a good reputation in the region, SharkBytes. Sadly the company is no longer around - it couldn't handle the slow period after the dotcom crash in 2000/2001. I really have to thank Ryan and Clark for giving me a shot because looking back I had no experience and no skills at all the day I walked in their door for the interview. They must have seen passion and a willingness to learn and hoped it would be worth something. I spent about 6 years with SharkBytes and sibling/parent companies - at the peak I was the Technical Director for the company with about a 10-12 person team.

    If you knew then what you know now, would you have started programming?

    Shortest answer of the bunch: Definitely.

    If there is one thing that you learned along the way that you would tell new developers, what would it be?

    I like the comment Mike made, "Don't get stuck in a cube farm." I do see some benefit from doing it for a while, but mostly from experiencing and observing how larger organizations work. I also like Steve Smith's advice, "I would suggest that new grads strongly consider doing some consulting work... to be able to see how things worked at a variety of companies and work on a variety of technologies". I think that both say the same thing in different ways. I've always believed that no experience is a bad experience because at worst you've learned about something that you don't like or like to do. Having your eyes opened to as many things as possible will help you decide what it is that you like to do. The same can be said for classes in college. I tried a little bit of everything: accounting, political science, statistics, lots of history and I took a programming class on a whim. I re-discovered that I loved it. My plans to be an accountant were foiled.

    My best advice is to not let yourself get stuck in a rut. If you've worked at a place too long that you've learned everything you can from the people that you work with, you're not doing anything new, and you've become the "go to" person then it's time to move on to a more difficult challenge. That doesn't necessarily mean that you need to look for another job, though it may. Finding an open source project to get involved in might be a good alternative. Seeking out experts or others with differing techniques at local or regional user groups and events can be another alternative. Just looking and and experimenting with new(er) or different technologies might fill that need for you, too. Just make sure that you continually keep expanding your horizons.   

    What's the most fun you've ever had... programming?

    I can define "fun" in a lot of different ways - even learning something new or the occasions when something just clicks and the light bulb comes on I consider fun. Digging through some difficult code and finally figuring out how it works is fun. Figuring out how to write a unit test for something I thought untesable is fun. I even find something to laugh about every day in our daily stand ups. Nearly everything about being a software developer is fun for me. It's all about solving puzzles and there's nothing more fun than that.

    That being said the most day-to-day enjoyable job I've ever had was working with two of my best friends in a small office each and every day. We were always playing practical jokes on each other, bouncing ideas off each other, complaining about something or another, and we always went out to lunch together. Best of all we'd laugh about 100 times or more a day.

  • How to decouple the ASP.NET Membership database from Kigg

    AspDotNetMVCGetsKigg

    This evening I posted an update to the AspDotNetMVC site that includes allowing voting on the ASP.NET MVC blog posts, buzz, articles and news that the site collects. You can see a page that uses it here: http://aspdotnetmvc.com/blogs. Rather than create my own rating system I decided to leverage Kigg instead. I mentioned in a previous post that I had been looking at Kigg and that I had upgraded it from ASP.NET MVC Preview 2 to Preview 3. Why not use Kigg? It has nearly everything that I need, it is open source, and it's built on ASP.NET MVC. It seems appropriate to use it for a site that's all about ASP.NET MVC. Additionally, my mucking around in the project is helping me learn ASP.NET MVC a little so I can convert the AspDotNetMVC site to it at some point.

    This is the first of a couple of articles where I will describe some of the changes that I had to make to Kigg to allow it to support the way that I wanted to use it on AspDotNetMVC. My goal was to allow voting on items on the AspDotNetMVC site without requiring visitors to bounce over to a Kigg site to do so. Because Kigg only allows members to vote once on an article and I wanted the same for the main site I had to hook up ASP.NET Membership to the AspDotNetMVC site and have both sites use the same membership database. Yes, I probably could have just used cookies, session, IP address or something else to accomplish the same thing, but I will have site "members" in the future (for forums, etc) so I didn't want to invent something now just to end up rewriting it in the future when membership was really needed. I hear some of you mumbling "YAGNI" already, and I don't disagree, but in reality the path of least resistance was to go ahead and wire up membership now on the main site rather than rewrite Kigg to use something other than ASP.NET membership.

    Today I'll talk about decoupling the ASP.NET membership database from the Kigg database and codebase (why will be explained below). The follow-up post will be about writing two WCF web services for Kigg to allow other sites to retrieve the count of votes for "articles" and to vote on articles. The final post of the three will show how easy it is to setup support for OpenID and integrate it with your ASP.NET Membership system to allow users the option of using OpenID or creating a traditional account on the site. 

    I wrote a paragraph or two above that I needed to create one ASP.NET membership store and let both the AspDotNetMVC site and the Kigg site use it. The Kigg site database already comes with the asp.net membership stuff baked into it. I didn't want the main site's membership to depend on the Kigg database, though. In fact I wanted to use a different database for membership, one that is solely for membership, that I use for several sites. Upon trying to use an external membership database for Kigg I found a couple of "issues". There are a couple of foreign key relationships setup between the Kigg tables and the aspnet_Users table and the Kigg data model actually includes the aspnet_Membership and aspnet_Users tables. I can't really lay too much blame on the original authors because I know I've done similar before: expect the membership tables to be local (as part of the primary database) but over the years I've learned better so I set about removing those dependencies. Following are the steps required to break the ASP.NET membership stuff away from Kigg to allow you to use an external data store for membership.

    1. Remove foreign key constraints between Kigg tables and asp.net membership tables. If I remember correctly there are three: Story -> aspnet_Users, Comment - > aspnet_Users, Vote -> aspnet_Users.

    2. [Optional] Remove asp.net membership tables, view, sprocs from the Kigg database. I did it manually, but you probably should use aspnet_regsql if you're going to remove them.

    3. Remove the User and Membership tables from the model, Kigg.dbml. Just open up the designer, click on them and hit the delete key then save.

    4. Update the UserItem model, adding the following public constructor. Rather than use the "else anonymous" branch you may want to throw a "user does not exist" exception or something like that, but setting it to a "generic" user was what I wanted for my situation.

    public UserItem(Guid membershipId){ MembershipUser user = Membership.GetUser(membershipId); if (user != null) { this.Name = user.UserName; this.Email = user.Email; } else { this.Name = "Anonymous"; this.Email = "anonymous@somedomain.com"; }}

    5. Update the KiggDataContext model, replace any instance of:

    PostedBy = new UserItem { Name = s.User.UserName, Email = s.User.UserDetail.Email }

    with this: PostedBy = new UserItem(s.PostedBy)

    6. Add a new connectionstring to your web.config, probably named something like "Membership" :), to point to your membership database.

    7. Update the Membership, RoleManager, and Profiles providers sections of your web.config to use the new connection string. Remember to change the "ApplicationName" property if appropriate.

     

    That's all you need to do. Now you can use Kigg in conjunction with any other existing applications and/or membership store you already have.

  • Now with a picture

    I finally got around to adding a picture of me to this blog, thanks to some prodding (you know who you are!). After doing so I realized that this theme is getting a little bit crowded and dated. I hate to add to my to-do list but I'm now in search of something else.

    1. Move my personal blog to Graffiti.
    2. Choose one of the existing out of the box Graffiti themes, choose one of Rich's themes - I really like the PointSpace one, or create a new one. I want something much simpler than this one whatever way I choose to go.
    3. Convert the rest of this site (families blogs) to Community Server 2008 or Graffiti - I haven't decided which yet - probably Graffiti. I hate to give up running a copy of our flagship product day-to-day, but I really only use it for blogs and photos and Graffiti will handle what I need. Maybe I'll find somewhere else to run Community Server :)

     

  • Lan & Deon #1

    Hopefully the first of many...

    Not that there is anything wrong with tramp stamps. Just not on Deon.

     

  • AspDotNetMVC.com

    I know what you're thinking, "Three posts in one day? This can't be the same blog I've been following for the last month or so. What is wrong with my RSS reader?" As far as I know there is nothing wrong with your RSS reader. This is my third post today.

    My recent lack of regular blog posts and my sadly unnoticed disappearance from Twitter and the rest of the microblogging universe can simply be explained by the following:

    • Doing some recovering and catching up on delinquent household maintenance after speaking at four regional Days of .NET and over a five week period a couple of months ago.
    • Some family time
    • A couple of deep dives into some new(er) technologies, specifically LINQ to SQL and a peek at ASP.NET MVC
    • The transition to the new job that I mentioned in my previous post
    • My newest baby, ASPDotNetMVC.com

    The first couple of items are nothing worth writing about. The third item has caused me to create a couple of blog posts about LINQ and ASP.NET MVC. I covered the new job in my previous post. What I really want to tell you about is my newest site, ASPDotNetMVC.com, which I believe Keith Elder called "YADHS" - Yet Another Dan Hounshell Site.

    Mike Eaton beat me to the punch and attributed the site to me early last week, but let me catch you up anyway. I won't go into too much detail about the why's and how's here because I think I did a pretty good job of covering the why on the About page of the site itself. Briefly, I started diving into ASP.NET MVC and found lots of information (great blog posts, articles, lots of stuff on Twitter, etc) but no one place served as the hub for all that information. There was no official Microsoft site, like with Silverlight.net, to serve as a starting point and launch point. I said to myself that there should be a portal for everything ASP.NET MVC, asked myself why I shouldn't be the one to build it, decided to take the plunge, found a good domain name and went about doing that voodoo that I do.

    The site is really pretty simple, it's just made up of a bunch of little pieces that do just the one thing and do it well. And each of the little pieces work pretty well together. I was explaining how simple it was to Mike last week and when I finished he said, "Wow, that sounds awesome... I don't know how to do any of those things. You should make this an open source application." I'm not sure that I'm quite ready to do that just yet because I have plans for a similar site on a similar topic. But there are a couple of pieces that I do plan on sharing - one of them being a very simple Pingback library.

    On the plus side for me the site basically runs itself. Now that I have all of the basic parts in place and I've finished all the features planned for Iteration 1* (and some of Iteration 2) it doesn't require much day-to-day from me. There are some other things that I'd like to add to the site over time, as I have time, to build in more "Community". One of those is building voting for blog posts, articles, etc, that are listed on the site by integrating with Kigg, an open source MVC starter kit application on CodePlex. I'm about 60% finished with this, I just need to add some final touches and some polish. Additionally I'd like to definitely add forums (not much of a surprise there, huh? :) ) and then depending on how that goes taking a look at adding blogs and other Community Server community features.

    * Side Note - RE: Iteration #1 - I treated this as a real project with a lot of help from Unfuddle, which I discovered a couple of months ago based on the recommendation from a buddy to look into it for free SVN hosting. Unfuddle can do that and oh so much more. More posts on Unfuddle are queued up in Windows Live Writer and should be coming soon.

  • Hello Community Server Team

    The last couple of weeks have been very busy and very different for me. Two weeks ago today I relinquished my hold on the ASP.NET Sites' Team, where for nearly the last two years I have been working on www.asp.net, forums.asp.net, weblogs.asp.net and wiki.asp.net. I transitioned to the Telligent Product Team, specifically the Community Server Team. Joining the CS team was actually a goal of mine since I joined Telligent in September 2006. Since I started in the business (early '99) I've always been part of a services-based team, building and maintaining sites for clients. For a few years I've wanted to take a peek at the greener grass on the other side of the fence to see what working as part of a product-based team was like. I am not disappointed - it has been great. And the team that I work with is made up of unbelievably talented and hard-working individuals. They are really amazing and I am really amazed to be part of such a team.

    While I've worked with Community Server nearly every day for the past two years (and some before that, and .Text and ASP.NET Forums before that) there has still been quite a learning curve for me. There is a big difference between working with Community Server and working on Community Server. I imagine the same can be said for nearly any product. I hope my never-ending barrage of email questions to the rest of the team isn't growing tiring. But I think I see light at the end of the tunnel and I think I'm starting to get warmed up.

    Leon Gersing's Facebook profileMy petty personal feelings of inadequacy aside, I'm really pumped about the direction we are taking Community Server, the new features we are adding, and the glut of just really cool stuff that I am seeing showing up in the build each and every day. Josh just today posted a really good overview of what to expect from the Community Server 2008.1 release this fall. 

    BTW, yes we're still hiring. If you are a good SharePoint dev you could work hand-in-hand with this guy (pictured at right), who is inarguably the best SharePoint developer in the country - at least that's what he tells me. Finally, if you live and breath Community Server then consider joining us for our 2nd Annual Conference, in.Telligent 2008, in Dallas in October.

  • A Cheap and Green Windows Home Server

    imageA couple of months ago I wrote two posts with some specs that I had been considering for building an inexpensive Windows Home Server ("In Search of an eco-friendly economical Home Server" and "In Search of an eco-friendly economical Home Server 2"). Unfortunately I have yet to pull the trigger on buying the hardware to build a little WHS box, but I am getting closer (and smaller and more energy efficient) to buying and building. I will post a list of parts once I've made my decision and completed my order.

    In the meantime I found an article a few weeks ago on Home Server Hacks about building a WHS server on a Shuttle KPC Barebone setup for around $400 ($409 including the price of WHS!). That is tough to beat and I think you can actually do better now as the cost of the Shuttle KPC Barebone has dropped $10, the cost of hard drive used in the example has dropped $15, and you can now get a little bit more processor for less money than when the article was originally published. I think you can easily come in under $400, including shipping.

    http://www.homeserverhacks.com/2008/04/build-green-400-windows-home-server_2871.html

    Taking that idea and running with it - what if you started with this Intel Atom 945GC Mini ITX Motherboard/CPU Combo as a base. Check out the Combo deal that includes the board/cpu with the tiny little APEX case for $118! Add a stick of RAM and a WD Green Power drive or two and that would be slick, small, and energy efficient package!

  • Upgrading Kigg Unit Tests to MVC ASP.NET Preview 3

    Yesterday I posted about updating Kigg to Preview 3. Immediately after publishing that post I realized that other than doing a find-and-replace of some of the code in the unit tests I had not tried running them, I assumed they would work. Bad assumption, lesson learned.

    While upgrading the code for the Kigg web site was fairly simple, upgrading the unit tests to get all passing green lights was not as easy. The biggest issue was that in Preview 2 the return type of the Contoller methods were void, whereas in Preview 3 they are ActionResult. The unit tests had to be refactored to use that ActionResult. Below is an example of before and after:

    Before - based on Preview 2

    controller.Category(null, null); Assert.AreEqual(viewEngine.ViewContext.ViewName, "Category");Assert.IsInstanceOfType(typeof(StoryListByCategoryData), viewEngine.ViewContext.ViewData);Assert.AreEqual(((StoryListByCategoryData)viewEngine.ViewContext.ViewData.Model).Category, "All");Assert.AreEqual(((StoryListByCategoryData)viewEngine.ViewContext.ViewData.Model).PageCount, 200);Assert.AreEqual(((StoryListByCategoryData)viewEngine.ViewContext.ViewData.Model).CurrentPage, 1);

    After - based on Preview 3

    ViewResult viewResult = (ViewResult)controller.Category(null, null); Assert.AreEqual(viewResult.ViewName, "Category");Assert.IsInstanceOfType(typeof(StoryListByCategoryData), viewResult.ViewData.Model);Assert.AreEqual(((StoryListByCategoryData)viewResult.ViewData.Model).Category, "All");Assert.AreEqual(((StoryListByCategoryData)viewResult.ViewData.Model).PageCount, 200);Assert.AreEqual(((StoryListByCategoryData)viewResult.ViewData.Model).CurrentPage, 1);

    You'll see that I cast the return type as ViewResult in this case, in three cases (discussed more below) it should be RedirectToRouteResult.

    The other major change, which took me a while to figure out, is in the three tests that previously expected a redirect. Those three tests need to be changed from expecting the redirect to expecting a RedirectToRouteResult with the proper values. Below is an example of before and after:

    Before - based on Preview 2

    using (mocks.Record()){ mocks.MockControllerContext(controller); Expect.Call(delegate { controller.HttpContext.Response.Redirect(string.Empty); }).IgnoreArguments();}using (mocks.Playback()){ Assert.IsNull(viewEngine.ViewContext);}

    After - based on Preview 3

    using (mocks.Record()){ mocks.MockControllerContext(controller); //Expect.Call(delegate { controller.HttpContext.Response.Redirect(string.Empty); }).IgnoreArguments();}using (mocks.Playback()){ RedirectToRouteResult actionResult = (RedirectToRouteResult)controller.Tag(null, null); Assert.IsNotNull(actionResult); Assert.AreEqual("category", actionResult.Values["action"].ToString().ToLower());}

    For now I just commented out the call to expect the HTTP Redirect in the mock setup. The change is that the return value is now checked for NotNull rather than the context being checked for IsNull before and then the "action" value is checked to make sure it is "category". All three unit tests about redirects are expecting a redirect to the category action so the code is basically the same for all three.

    BTW, I used the NUnit tests project, but I'm sure updates to the VSTest project would be similar if not the same.

    Hopefully, I've now corrected my foul. I know I'm a lot happier now that I see all green when I run my tests. :)

  • Upgrading Kigg to ASP.NET MVC Preview 3

    I downloaded Kigg from CodePlex, a Digg like application written with ASP.NET MVC, a few weeks ago and began playing around with it this evening. The current source code is setup for the MIX08 Preview 2 version not the current version, Preview 3. I have Preview 3 installed and did not want to go back so I set about updating it. The process went pretty well considering this was my first time really doing anything with the MVC framework.

    I plan on submitting a patch of the needed updates once I can actually connect to the source code repo (I'm able to do so with other projects on CodePlex, like SVNBridge, but I am having trouble specifically with Kigg). But in the meantime if you'd like to upgrade Kigg to Preview 3 simply follow the steps in the Preview 3 Readme Release Notes in the section "Upgrading an Existing Preview2 Application to Preview 3" and it will work fine. Those instructions along with some help from Intellisense and the C# compiler are all that you'll need to do so.

  • LINQ to SQL - How to "Where in (value1,value2, ... valueN)"

    According to FeedBurner the count of my blog subscribers has been steadily decreasing the last couple of weeks. I can't blame those quitters because my posts have been few and far between. But for those of you beautiful and intelligent people with enough patience to wait for something worthwhile - you're in luck today.

    Several days ago I was working with a LINQ to SQL statement where I wanted to get an item if it's name existed in a string array of passed in values. I needed a LINQ translation for the SQL " where in (value1, value2, ... , valueN)" syntax. Intellisense provided little value. I had to turn to Google for answers. Do you realize how difficult it is to search for the keyword "in" on Google?!? It was nigh