Thursday, September 30, 2010

Dev Bandwagon – Part 1



So in my quest to find a new project to blog about, my brother, Dane, and I stumbled across one. I don’t know of anything that currently exists, but the idea is to have one place to go and download all the different tools used for specific languages. I know for the past couple years, a LOT of developers have complained that they don’t know what, when, or how to use most the tools because they’re coming out too fast and they don’t have time to learn them.

What Dane and I would like to create to solve the problem is a resource for developers to find all tools and tutorials to help them learn. We’ve started writing up some of the user stories using Agile Zen, which is a terrific tool! Here’s what we’ve come up with so far:

image

We’ll probably start out with only .Net tools and then grow it into some of the other languages. We’re pretty confident that the hardest part will be the categorization of the tools. We’re thinking we’ll have categories and sub-categories, something like this:

image

I think the categorization is what we’ll have to lean on the community for as well as the tools themselves. Please let me know what you think and whether or not you know of anything in existence of if you think this is a good/bad idea.

Thanks for reading!

kick it on DotNetKicks.com

Tuesday, August 31, 2010

Comma-delimited Column with SQL 2005




Long time no blog. The month of August is ridiculously busy at my job, so I haven’t really had a chance to post. Since this month is about over, I should be able to start posting regularly again. Luckily this past month I had the opportunity to learn quite a bit, particularly about fluent NHibernate. Most likely I will be posting about that topic in the near future…mainly to praise nhprof, which is a necessity if transitioning to NHibernate.

Okay, so let’s get started. I seem to always find myself needing a script that will create a comma-delimited column. Well, I found a nice post on the topic, but I didn’t like a hard-coded number he has in his script. So, I think I have a solution to the issue, but I’m curious to see what others think. So…here’s the SQL:

DECLARE @ENDIDENTIFIER CHAR
SET
@ENDIDENTIFIER=';'

SELECT
REPLACE((SELECT many.Items + ','
FROM many WHERE many.foreignKey = one.primaryKey
FOR xml path('')) + @ENDIDENTIFIER, ',' + @ENDIDENTIFIER, '') AS csv
FROM one

Here’s the same script without the @ENDIDENTIFIER:

SELECT
REPLACE((SELECT many.Items + ','
FROM many WHERE many.foreignKey = one.primaryKey
FOR xml path('')) + ';', ',;', '') AS csv
FROM one

The @ENDIDENTIFER is just there so I don’t have to remember where to put my identifier to replace. This way it’s easy if I have a column that might have a ;, I can easily use another identifier.

This seems to perform well, but haven’t used it on anything with more than 50,000 records. If any of you decide to use it, I’d be curious to know if you improve it or if it performs well. Thanks for reading!

kick it on DotNetKicks.com

Friday, July 16, 2010

Authenticating Against Multiple Domains with C# & StructureMap




In my place of work, we had a vendor come in and try to sell us a product that couldn’t authenticate to multiple domains. Well, we have multiple domains. Their suggestion was to consolidate into one…obviously we’re not using their product. So, in an effort to help out, I thought I’d share a method of authenticating to multiple domains.

As always, we start out with our interface…

  public interface IAuthenticationService
{
bool Validate(string username, string password);
string DefaultRedirectUrl { get; }
}

Pretty straightforward so far…I added in a DefaultRedirectUrl in case you want to route to different places depending on which domain you authenticated against.

Okay, let’s implement our interface…

    public class AuthenticationService : IAuthenticationService
{
private readonly IAuthenticationService[] _authenticators;
private string _redirecturl;

public AuthenticationService(IAuthenticationService[] authenticators)
{
_authenticators = authenticators;
}

public bool Validate(string username, string password)
{
var isValid = false;
foreach (var authenticator in _authenticators)
{
if (authenticator.Validate(username, password))
{
isValid =
true;
_redirecturl = authenticator.DefaultRedirectURL;
break;
}
}
return isValid;
}

public string DefaultRedirectUrl
{
get { return _redirecturl; }
}
}

Alrighty…so all this does is takes in an array of authentication services and then loops through them checking if they’re valid and if they are, sets isvalid to true, the redirect url, and returns.

Basically this is our master authentication service. Now, we just need one for each one of our domains. Since they’re both authenticating to AD, we’ll create a base class like this:

    public abstract class ActiveDirectoryAuthenticator : IAuthenticationService
{
private readonly ILDAP _ldap;

protected ActiveDirectoryAuthenticator(ILDAP ldap)
{
_ldap = ldap;
}

public bool Validate(string username, string password)
{
var authenticated = false;
try
{
var entry = new DirectoryEntry(_ldap.URL, username + "@" + _ldap.HostName, password);
object nativeObject = entry.NativeObject;
authenticated =
true;
}
catch (DirectoryServicesCOMException)
{
}
return authenticated;
}

public virtual string DefaultRedirectUrl
{
get { return "/"; }
}
}

So, my ILDAP interface is the same one I blogged about here. The DefaultRedirectUrl here is virtual and meant to be overridden, otherwise it’ll just redirect to the root. Okay so now we need to inherit this authenticator in our domain authentication service classes like this…

Domain #1

public class Domain1AuthenticationService : ActiveDirectoryAuthenticator
{
public Domain1AuthenticationService() : base(DependencyRegistrar.Resolve<ILDAP>(DependencyNames.Domain1LDAP))
{ }

public override string DefaultRedirectUrl
{
get
{
return "/domain1/default.aspx";
}
}
}

Domain #2

public class Domain2AuthenticationService : ActiveDirectoryAuthenticator
{
public Domain2AuthenticationService() : base(DependencyRegistrar.Resolve<ILDAP>(DependencyNames.Domain2LDAP))
{ }

public override string DefaultRedirectUrl
{
get
{
return "/domain2/default.aspx";
}
}
}

Pretty simple right? Basically we’re setting our RedirectUrl and calling our ILDAP from StructureMap. You can read more about how I implement StructureMap here. Now for the good ole StructureMap code that goes in the Registry…

ForRequestedType<ILDAP>()
.AddInstances(x =>
{
x.OfConcreteType<
LDAP>()
.WithName(
DependencyNames.Domain1LDAP)
.SetProperty(y => y.WithBaseDN(ou =>
"Users", dc => "dc1", dc => "domain", dc => "com")
.WithHost(
"dc1.domain.com"));

x.OfConcreteType<
LDAP>()
.WithName(
DependencyNames.Domain2LDAP)
.SetProperty(y => y.WithBaseDN(ou =>
"Users", dc => "dc2", dc => "domain", dc => "com")
.WithHost(
"dc2.domain.com"));
});

ForRequestedType<
IAuthenticationService>()
.TheDefault.Is.OfConcreteType<
AuthenticationService>()
.TheArrayOf<
IAuthenticationService>().Contains(x =>
{
x.OfConcreteType<
Domain1AuthenticationService>();
x.OfConcreteType<
Domain2AuthenticationService>();
});

So, how to use this in your code? Like this…

 var adService = DependencyRegistrar.Resolve<IAuthenticationService>();

if (adService.Validate(tbUsername.Text, tbPassword.Text))
{
FormsAuthentication.SetAuthCookie(tbUsername.Text, true /*persist cookie*/);

if (Request.QueryString["ReturnUrl"] == null)
Response.Redirect(adService.DefaultRedirectUrl);
else
Response.Redirect(Request.QueryString["ReturnUrl"]);
}
else
//Display Error

There it is…authenticating against multiple domains. Please let me know if you know of better ways or you see ways to improve. Thanks for reading!

Shout it

kick it on DotNetKicks.com

Wednesday, July 14, 2010

Slow Down Filter for Throttling Requests with ASP.NET MVC




I’ve been looking for a good filter to play with and finally found one today. Basically, I want to slow down requests to prevent people and/or other mechanisms from submitting a form.

I saw a post by the guy’s at stackoverflow.com and ended up using a couple of their ideas in my filter attribute. Stackoverflow’s stops the execution of a request and I only want to slow it down. Generally speaking, I want to deter people/things from attempting to submit multiple times in a row after a specified amount of requests.

So…here’s the filter attribute:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class SlowDownAfterAttribute : ActionFilterAttribute
{
public const string AttemptsExceeded = "AttemptsExceeded";
private readonly int _numberOfAttemptsAllowed;
public string Name { get; set; }

public SlowDownAfterAttribute(int numberOfAttemptsAllowed)
{
_numberOfAttemptsAllowed = numberOfAttemptsAllowed;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData[AttemptsExceeded] =
false;

var key = string.Concat(Name, "-", filterContext.HttpContext.Request.UserHostAddress);
var numberofattempts = Convert.ToInt32(HttpRuntime.Cache[key]);
numberofattempts++;

HttpRuntime.Cache.Insert(key,
numberofattempts,
null,
DateTime.Now.AddMinutes(2),
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);

if (numberofattempts <= _numberOfAttemptsAllowed)
return;

filterContext.Controller.ViewData[AttemptsExceeded] =
true;
System.Threading.
Thread.Sleep(numberofattempts * 1000);
}
}

Here’s how you could use it:

[HttpPost, ValidateModel(typeof(Form)), ValidateAntiForgeryToken, SlowDownAfter(5 /*attempts*/)]
public ActionResult Validate(Form form)
{
if (!ModelState.IsValid)
//Display Error

if ((bool)ViewData[SlowDownAfterAttribute.AttemptsExceeded])
//Display Message or something

return View(form);
}

If you want to use the SlowDownAfter() attribute on multiple methods, you’d want to name it like this:

SlowDownAfter(5 /*attempts*/, Name="ValidateForm")

So basically the way this thing works is like this:

  • Sets the AttemptsExceeded flag on the ViewData to false
  • Sets the key (I got the naming convention from the StackOverflow response on stackoverflow.com)
  • Gets the number of attempts from cache
  • Incremements by 1
  • Adds the value to cache with an absolute expiration of now + 2 minutes
  • Checks if number of attempts is less than or equal to the number of attempts allowed
  • If number of attempts allowed was exceeded, it writes the ViewData AttemptsExceeded flag to true and sleeps for the number of attempts in seconds

Let me know what you think. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Monday, June 14, 2010

jQuery AJAX with ASP.NET Web Forms & Sitefinity



My team and I are working with Sitefinity to create our new portal. Well, since Sitefinity doesn’t currently support MVC, we’re having to use the “good” ole web forms. Sitefinity is a really nice CMS and allows for full customization and we’re still learning how to handle the custom user controls. So…this is how we’re doing it right now.

Download Source

We wanted to allow our users to add quick links to their home screen, so that’s the sample I’m going to use. First, I created two projects, one called UserControlSample.Core (class library) and the other called UserControlSample.UI (a blank Web project).

I started with the domain model, which looks like this:

public class QuickLink
{
public Guid Id { get; set; }
public string DisplayName { get; set; }
public string URL { get; set; }
public string UserId { get; set; }

public string BuildHyperlink()
{
return string.Format("<a href=\"{0}\" title=\"{1}\">{1}</a>", URL, DisplayName);
}
}

Generally, I wouldn’t put the UserId in this class, but for this example it just made it easier.

After the domain model, I added the repository interface, which is this:

    public interface IQuickLinkRepository
{
QuickLink[] GetAllBy(string userId);
void Add(QuickLink quickLink);
void Delete(Guid quickLinkId);
}

You can download the project to see the implementation of the interface. I used L2S and again, you can download the project to see the implementation. Alrighty, so let’s get to the real code that you can use.

I added a user control, which looks like this:

<div id="quicklinks">
<
div>
<
div class="loader" id="loading" style="display: none"></div>
<
asp:Repeater ID="rQuickLinks" runat="server">
<
HeaderTemplate><h3>Quick Links</h3><ul></HeaderTemplate>
<
ItemTemplate><li id="li<%# ((QuickLink)Container.DataItem).Id %>"><img src="/_a/i/ico-delete.png" width="16" height="16" alt="Delete <%# ((QuickLink)Container.DataItem).DisplayName %>" id="<%# ((QuickLink)Container.DataItem).Id %>" /><%#((QuickLink)Container.DataItem).BuildHyperlink() %></li></ItemTemplate>
<
FooterTemplate></ul></FooterTemplate>
</
asp:Repeater>
<
a href="#" id="addQuickLink" title="Add Quick Link">Add Quick Link</a>
</
div>
<
div style="display: none">
<
fieldset>
<
legend>Add Quick Link</legend>
<
p><label for="<%=tbDisplayName.ClientID %>" title="Display Name:">Display Name:</label><br />
<
asp:TextBox ID="tbDisplayName" runat="server" /> <asp:RequiredFieldValidator ValidationGroup="addQuickLink" ControlToValidate="tbDisplayName" Display="Dynamic" ID="rv1" SetFocusOnError="true" runat="server">*</asp:RequiredFieldValidator></p>
<
p><label for="<%=tbURL.ClientID %>" title="Website Address:">Website Address:</label><br />
<
asp:TextBox ID="tbURL" runat="server" /> <asp:RequiredFieldValidator ValidationGroup="addQuickLink" ControlToValidate="tbURL" Display="Dynamic" ID="rv2" SetFocusOnError="true" runat="server">*</asp:RequiredFieldValidator> <asp:RegularExpressionValidator ControlToValidate="tbURL" Display="Dynamic" ID="re1" runat="server" SetFocusOnError="true" ValidationGroup="addQuickLink" ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)?">*</asp:RegularExpressionValidator></p>
</
fieldset>
<
asp:Button ID="bSubmit" runat="server" CausesValidation="true" Text="Add Quick Link" ValidationGroup="addQuickLink" OnClick="AddQuickLink" /> <a href="#" title="Cancel Quick Link Addition" id="cancelAddQuickLink">Cancel</a>
</
div>
</
div>

That looks really messy, but that’s web forms for ya :D

Here’s the interesting part, instead of having a code-behind and inheriting from a partial, we added a class to the Core.UI.Controls called QuickLinksControl. Here’s the code:

 

public class QuickLinksControl : BaseControl
{
private IQuickLinkRepository _repository;

protected void Page_Load(object sender, EventArgs e)
{
_repository = DependencyResolution.
DependencyRegistrar.Resolve<IQuickLinkRepository>();

if (Request.Form["QLID"] != null)
DeleteQuickLink(
new Guid(Request.Form["QLID"]));

if(!Page.IsPostBack)
LoadQuickLinks();
}

private void DeleteQuickLink(Guid quickLinkId)
{
_repository.Delete(quickLinkId);
Response.Write(quickLinkId);
Response.End();
}

protected void AddQuickLink(object sender, EventArgs e)
{
if (!Page.IsValid)
return;

var tbDisplayName = (TextBox)Page.FindControl("tbDisplayName");
var tbURL = (TextBox)Page.FindControl("tbURL");
var button = (Button) sender;
var quickLink = new QuickLink {DisplayName = tbDisplayName.Text, URL = tbURL.Text, UserId = button.CommandArgument};
_repository.Add(quickLink);

tbDisplayName.Text =
"";
tbURL.Text =
"";

LoadQuickLinks();
}

private void LoadQuickLinks()
{
var rQuickLinks = (Repeater) FindControl("rQuickLinks");
rQuickLinks.DataSource = _repository.GetAllBy(Page.User.Identity.Name);
rQuickLinks.DataBind();
}
}

The interesting parts…

  1. DeleteQuickLink() is checked in the Page_Load. We’re doing this here for an AJAX call from the ascx file. We’re probably going to add some type of validation token to the if statement as well. We also might create some type of AJAX call handler instead of throwing them in the page_load, but it works for now.
  2. In the DeleteQuickLink method, we’re calling Response.Write(quickLinkId) and Response.End(). This is used for the AJAX call too to return the guid sent. There’s probably a better way, but so far this is working.
  3. In the AddQuickLink, you’ll notice that we’re having to find the controls because it’s not a partial and doesn’t know anything about the ascx page. This part kinda stinks, but it’s not too bad.

Here are the AJAX calls from the ascx page:

<script language="javascript" type="text/javascript">
$(document).ready(
function() {
$(
"#addQuickLink,#cancelAddQuickLink").click(function() {
$(
"div#quicklinks div").toggle();
});

$(
"#loading").ajaxStart(function() {
$(
this).show().text("Deleting...");
}).ajaxStop(
function() {
$(
this).hide().text("");
});

$(
'#quicklinks ul li img').click(function() {
if (!confirm('Are you sure you want to delete?'))
return;

$.post(window.location.href, { QLID: $(
this).attr('id') }, function(data) {
$(
"#li" + data).remove();
});
});
});
</
script>

I’ve never used the ajaxStart or ajaxStop before, but they’re pretty cool features. I also wanted to note that I started using StructureMap 2.6.1 and I’m liking it. It’s a pretty big difference from the last blog post on StructureMap. Now the ForRequestedType<> in the registry looks like this:

For<IQuickLinkRepository>()
.Use<
QuickLinkRepository>()
.Ctor<
string>("connstring")
.Is(
@"Data Source=.\SQLEXPRESS;AttachDbFilename=""..\LearnerSample.mdf"";Integrated Security=True;User Instance=True");

 

Here’s the finished product:

image

image 

So, any thoughts or ideas on what we’re doing? I’d appreciate any advice or comments. It’s probably easier to understand by downloading the sample code.

Thanks for reading!

Download Source

Shout it

kick it on DotNetKicks.com

Sunday, May 30, 2010

Big Design Conference 2010 Recap



Okay, at the start of the Big Design Conference, Susan Weinschenk (@thebrainlady), mentioned that we’ll hear different perspectives throughout the conference on UX and ideas in general. Well, I thought I would share my experience from a developer’s perspective. This is all from memory because I wrote very few notes, so hopefully I remembered the right things…although I know I didn’t on some of them. Plus I found out in the keynote on day one that my memory is not great. I couldn’t even remember CIAI BMF BIIP ODHP…of course I do now because she showed us this: CIA IBM FBI IPOD HP, which makes it a little easier.

Day 1:

  • Keynote by Susan Weinschenk, @thebrainlady
    What I took away…
    • Brain has three parts – new, mid, and old
      • new = language processing, speech, thinking thoughts, planning, etc
      • mid = emotions
      • old = danger, sex, and food
    • Our 5 senses take in about 11 million pieces of information every second and ONLY 40 of those are processing consciously.
    • Use usertesting.com - $39/person
    • We were asked to draw which way we would turn two knobs to get warm water. The results were all over the place on how people would turn the knobs. The idea behind the activity was to show that people have different models in their heads of how things should/do work. In this instance, I was curious as to how many people know the saying, “lefty loosy, righty tighty”. My guess is that the majority of people that said turn both to the left have heard that saying.
    • We were also asked to divide a circle into quadrants and label them A, B, C, D. I started in the top left and did A, B and then on the next “line”, C, D. After seeing the results of how people arranged the letters, it seemed to me that culture mattered more on how one would arrange them. My guess is that you’d arrange them in the manner you learned to read. I read from left to right and line by line, therefore, my result was A, B new line C, D.
    • I can’t draw a coffee cup with a saucer…At least not nearly as good as Dave, the marker artist sitting next to me.
  • The Age of the Brandividual: How to Build your Company and Personal Brand Leveraging Social Media by Mike D. Merrill, @mikedmerrill
    Download Slide Deck
    What I took away…
    • Update your LinkedIn account because it’s a great tool to manage connections.
    • Go ahead and reserve the username you want to use for your online activities on all the different sites, even if you don’t intend to use them. Especially places like Google, Facebook, and LinkedIn.
    • @aol.com email accounts means you’re over 40. Either buy yourself a domain or go with gmail.com.
    • Blog.
  • The How to Conduct Global UX Benchmarking by Alfonso de la Nuez
    What I took away…
    • I ended up leaving this one early because I thought it was going to be “More Than a Blue Button” by Ryan Merket. I did however spend the first 10 minutes trying to figure out if Alfonso had a ponytail because it looked like he did. I didn’t actually see that he does not have a ponytail until a later that day.
    • I didn’t make it to the Ryan’s session, I just walked around and waited for lunch.
    • My apologies Alfonso for leaving early.
  • Agile or Irrelevant? by Tom McCracken
    What I took away…
    • Tom likes talking about this stuff.
    • Tom likes Drupal.
    • NASA kinda formed the way we do projects today (waterfall).
    • Tom provided some visuals on waterfall vs agile methods, which were interesting.
    • Tom also mentioned the http://agilemanifesto.org/.
  • 10 Commandments of Social Interaction Design by Chris Pitre & Laura Verble
    What I took away…
    • Chris likes Beyonce and he’s going to buy a TV from VIZIO because they showed him a picture of one with Beyonce on it. (this was an example they provided)
    • Vagisil has a “Share with others” feature. (I hope this doesn’t become part of my Google search results)
    • Respect privacy.
  • Extreme Douchebaggery, formerly known as Extreme Social Marketing by Giovanni Gallucci, @gallucci
    What I took away…
    • It’s all about the money. Hence the douchebaggery :)
    • Use YouTube for marketing.
    • Fake Genuine.
    • Funny guy and to the point.

Day 2:

  • Keynote by Chris Bernard (only heard from lobby, sadly)
    • Heard some Ferris Bueller’s Day Off coming from the room and I wish I would’ve seen it.
  • When Data Gets Up Close & Personal by Stephen Anderson, @stephenanderson
    What I took away…
    • All about the Feedback Loop
    • Creator of the Mental Cards, which were handed out at the conference to help make it more social and connected. Of course, being shy it did not help me. Although I did trade with whoever asked me, but I didn’t approach anyone. I need to get over that probably especially if I want to try to start speaking at some of these events…
    • This was one of my favorite sessions. He made me think a lot about how my end-users are going to interact with my applications and how I can make it fun and enjoyable for them.
    • He provided a ton of examples and I’m hoping he releases his slide deck soon.
    • He mentioned dopplr.com, which I just signed up for and really like. In particular he mentioned the “Your Carbon” section, which shows you your carbon footprint in a kg CO2 number. He goes into detail on how they could improve that number. he suggests…
      • Make it visual…maybe tree icons
      • Make it relatable…show how I compare on average
      • Show me how I can improve…take a train, etc
      • Show me how I can help…link to places that plant trees
    • He also gave a small exercise to write down a project that we’re currently working on and list some of the business goals. Then he went into a section on his problem of not responding to email quick enough and some of the things that an email system could do to help him stay motivated. The idea was for us to think about our project while he was showing how he thought through his…I enjoyed the exercise
  • Designing with Lenses: Lessons from Other Design Crafts by Bill Scott, @billwscott
    What I took away…
    • This guy seemed really smart. Worked for Yahoo! & Netflix on the UX teams I believe.
    • His presentation was how to use “lenses” to design. He gave an example of simple/complex…as in playing Tic Tac Toe is too simple, but chess has simple rules, but is a very complex game.
    • I don’t really know how to explain this stuff…he basically went through some practices that were used to develop a board game called Pandemic. The game looked fun and the examples were great.
    • He also talked about working on certain UIs with Yahoo! & Netflix. Some worked really well, others not so much. I’m hoping he publishes his slide deck as well because I think that would help explain some of this stuff.
    • My favorite part of his presentation was probably the example of detecting what changed on an image after a page refresh and then seeing the difference without the page refresh. I think only 5 people saw the change with the page refresh and everyone saw it without the page refresh. Extremely enlightening when it comes to UX. He also gave a URL for samples of this, but since I didn’t write anything down, I don’t have it. Like I said before, hopefully he publishes the slide deck.
  • Effective Dashboard Design: Why Your Baby is Ugly by Aaron Hursman, @hursman
    Download Slide Deck
    What I took away…
    • Aaron’s presentation was basically a bunch of examples of what not to do and what to do when it comes to building a dashboard.
    • Luckily, he published his slide deck. I wouldn’t want to have to re-create all those samples.
  • Can Helen Keller Learn in the 21st Century by Sharron Rush
    What I took away…
    • There is a definite need for knowbility in K12 environment
    • Knowbility offers several training events throughout the year
      • John Slatin AccessU
      • AccessU West
      • ATSTAR (Assistive Technology Strategies, Tools, Accommodations, & Resources)
    • Knowbility is also involved with the community via the Accessibility Internet Rally (AIR), which raise public awareness about barrier-free technology.
    • iPhone is a universally designed product.
    • Advocate universal design over accessible design
    • 1 in 10 men are color blind
  • Behind the Kimono: A Peak Behind the Design Process by Russ Unger, @russu
    Download Slide Deck
    What I took away…
    • Russ was angry.
    • Russ wrote a book. A book that I tried to buy today at BN and they did not have it in stock. I’ll have to buy it on Amazon later.
    • Russ and a few of his friends are helping a non-profit called lend4health.
    • Russ likes wireframes.
    • Russ is extremely entertaining.
    • Russ is showing his work and not hiding it. He asked the question, why don’t we share our work. I immediately thought, “it’s scary”. He actually wasn’t talking about developers, but more the wireframes, but it still applies. Fear is what kept me from blogging and sharing for so long. You never know how someone is going to take what you post or if you’re practicing what you’re preaching or if you’re going to live up to whatever standards you or someone else has set for you…it’s tough, but well worth it. I’m really thankful for all the bloggers in our communities and all the commenters I get on this site.
    • Apparently I like just saying Russ…whatever.
  • Keynote by Jared Spool
    • Fun presentation.
    • Showed the different types of design styles.
      • Unintended Design
      • Self Design
      • Genius Design
      • Activity-Focused Design
      • Experience-Focused Design
    • All good designers know which design style they’re using.
    • Use a design style through the completion of a project, don’t mix and match.
    • Some different design decision samples:
    • The girl under tree rule for universities…he listed at least 10 universities with girls under or around trees on their homepage.
    • He gave examples of different types of design styles.
      • Self Design – 37 Signals
      • Activity-Focused Design – Six Flags
      • Experience-Focused Design – Disney World
      • Unintended Design – American Airlines error page
      • Genius Design – New City something or another maybe? Can’t Remember.

Books Bought Due to Conference:

Books I Intend to Buy Due to Conference:

Other things learned

  • SMU has an awesome quad.
  • There are a ton of community driven people in the UX area too.
  • Section 508 compliant isn’t enough to make your site a universal design.
  • BigD Conference gives out some awesome notebooks.
  • My wife can navigate and find her way around Dallas. I was impressed.
  • Don’t Tweet so much that your phone dies and you miss your wife’s text messages stating that she’s outside waiting and has been for the past 30 minutes.
  • Check out #bigd10

I think that’s it. I really enjoyed this conference and thought I’d share my experience. I’ll definitely be headed back next year! If you attended the conference and have posted your experience, please let me know and I’ll link to you.

Thanks for reading!

kick it on DotNetKicks.com

Tuesday, May 25, 2010

Creating a Fluent Interface with C#




So I’ve been using fluent interfaces for a while now and I’ve really grown to like them. It made me want to write one, so I did. I made a simple interface for creating an LDAP URL. It’s really basic, but I thought it was cool nonetheless. Here’s what I ended up doing…

I wrote a test of how I wanted it to read, which looked like this:

[Test]
public void LDAP_WithBaseDN_WithHost_Should_Return_Valid_URL()
{
var ldapurl = new LDAP()
.WithBaseDN(dc =>
"ad", dc => "derans", dc => "lab")
.WithHost(
"noc-dc01")
.URL;

Assert.That(ldapurl, Is.EqualTo("LDAP://noc-dc01/dc=ad,dc=derans,dc=lab"));
}

So what does this look like in inteface form…

    public interface ILDAP
{
ILDAP WithBaseDN(params Func<string, string>[] dnitems);
ILDAP WithHost(string hostName);
string URL { get; }
}

As you can see here, I’m using one of my favorite new methods to map/pass data, the good ole Func<string,string>. I could pass create the WithPort, WithScope, etc, but I wanted to keep this short and simple.

So here’s the actual implementation of ILDAP:

    public class LDAP : ILDAP
{
private const string _protocol = "LDAP://";
private string _ldap = _protocol;
private bool hasBaseDN;

public ILDAP WithBaseDN(params Func<string, string>[] dcitems)
{
hasBaseDN =
true;
_ldap += BuildBaseDN(dcitems);
return this;
}

public ILDAP WithHost(string hostName)
{
if (_ldap.Length > _protocol.Length)
_ldap = _protocol + hostName +
"/" + _ldap.Remove(0, _protocol.Length);
else
_ldap += hostName + "/";

return this;
}

public string URL
{
get
{
if (!hasBaseDN)
throw new InvalidOrMissingBaseDN();
return _ldap;
}
}

private static string BuildBaseDN(IEnumerable<Func<string, string>> dcitems)
{
var baseDN = "";
foreach (var dc in dcitems)
{
var dnitem = dc.Method.GetParameters()[0].Name;
if (!Enum.IsDefined(typeof(LdapOptions), dnitem))
throw new InvalidOrMissingBaseDN();

baseDN +=
"," + dnitem + "=" + dc.Invoke(null);
}
return baseDN.Remove(0, 1);
}
}

One thing about being fluent is that you don’t know which order someone is going to do something in. If someone knows how to handle this, that would be great. I suppose I could look in the NUnit code or fluent NHibernate, but haven’t really had a chance to do a whole lot of research into how to do this…so hopefully this is an okay start :)

So here’s what the LdapOptions looks like:

    internal enum LdapOptions
{
dc, cn, ou
}

Not a great name, but it works for now. Here are all the tests:

[TestFixture]
public class LDAP_Tests
{
[
Test]
public void LDAP_WithBaseDN_WithHost_Should_Return_Valid_URL()
{
var ldapurl = new LDAP()
.WithBaseDN(dc =>
"ad", dc => "derans", dc => "lab")
.WithHost(
"noc-dc01")
.URL;

Assert.That(ldapurl, Is.EqualTo("LDAP://noc-dc01/dc=ad,dc=derans,dc=lab"));
}

[
Test, ExpectedException(typeof(InvalidOrMissingBaseDN))]
public void WithBaseDN_Should_Throw_InvalidOrMissingBaseDN_If_BaseDN_Is_Invalid()
{
var ldap = new LDAP().WithBaseDN(dc => "ad", test => "test", dc => "derans", dc => "lab");
}

[
Test, ExpectedException(typeof(InvalidOrMissingBaseDN))]
public void URL_Should_Throw_InvalidOrMissingBaseDN_If_BaseDN_Is_Invalid()
{
var ldap = new LDAP().URL;
}

[
Test]
public void WithBaseDN_Should_Return_Valid_LDAP_URL()
{
var ldapurl = new LDAP().WithBaseDN(cn => "employees", dc => "ad", dc => "derans", dc => "lab").URL;
Assert.That(ldapurl, Is.EqualTo("LDAP://cn=employees,dc=ad,dc=derans,dc=lab"));
}

[
Test]
public void WithHost_And_WithBaseDN_Should_Return_Valid_LDAP_URL()
{
var ldapurl = new LDAP().WithHost("noc-dc01").WithBaseDN(cn => "employees", dc => "ad", dc => "derans", dc => "lab").URL;
Assert.That(ldapurl, Is.EqualTo("LDAP://noc-dc01/cn=employees,dc=ad,dc=derans,dc=lab"));
}
}

That’s it. Please let me know if you see ways to improve on the fluent goodness. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...