User login

DylanW's picture

A Post About How I Haven't Posted

It seems like it's been about a month and a half since I posted anything substantial. Which is sad, because I actually do have a nice long backlog of programming stuff I could post about. No, literally. I have a text file of about five or six topics I could write about.

Plus I could gripe about how Dungeons and Dragons 4th Edition turned the game into WoW.

I also considered posting about all the new header photos I've put on the site... mainly to give credit where credit is due. I'm not a narcissist, I just keep finding pictures begging to be tweaked into header images among other people's photos. (Like Charlie's picture of me in costume at MTAC, or Liz's random picture of me in the hall at MTAC, or Crystal's photo of me at the Knoxville Zoo.)

So, there's credit where credit is due. Also, if anyone needs some similar graphics for their website, I'd be glad to take a look at their photos and see what I can do. (I'm looking at you, Nathan, with your new site design. :P)

Also among potential blogging topics was the rantworthy call I received from a recruiter yesterday. He cold-called me about a developer position... because he found my name and my company listed on the ETNUG site. And so he called my company, and somehow eventually got to me... after going through my manager.

Which is awkward, since I'm about to start a new job, and have sworn that it's an opportunity that sort of fell into my lap and I wasn't looking. Which is true, but a call like that would make it seem like it wasn't.

So, yeah. Professionalism and confidentiality. It's awesome.

Anyway, that's a summary of what I could have been posting. Except I guess I just did, if greatly summarized.

I can technically blame preparation for MTAC, or preparation for a recent cookout at the house, or the fact that I'm about to start a new job, or the fact that I've had a lot of offers for contracting work (outside of my normal job) recently. And I'm going to blame the fact that I'm going to be on vacation in Florida next week for the fact that it'll probably be another two weeks before I actually post anything.

There. I have absolved myself of all responsibility for my laziness, despite the fact that posting about how you haven't posted is bad form in blogging.

More...

Compile a Web User Control into a DLL ( .Net / c# )

So, for those parties interested, I have recently done some work trying to compile "controls" so that I can begin to have a self-contained code snippet library on my site.  After doing a bit of research, I have found what I feel to be the best way to go about this.  In this example, I am going to create a simple web user control to compile into a dll and add it to a separate website.

First things first...

There is a bit of different between the types of controls that you can create.  The most notable of control types are the user control and the web user control.  The big difference between the two is that user controls require that you either inherit from a existing control class or create a new one from scratch.  This includes hand coding all the front end view properties and such through the render method that all controls have... blah!

Another option is making an web user control (or .ascx file, which is probably more familiar).  The downfall of this control is that it is not edit-proof, and does not allow you to store it in places where it can "auto-refresh" itself.  You only option, if you want to share them cross-app, is to make a separate virtual directory of controls and share them across your sites... blah again...

Anyway...

The option that I like the best takes the best of both worlds.  We will use the awesome fludity of the .ascx file, but also compile them into .dll's (protection and versioning!!), which can be added as a reference, entered into the GAC, and all that other fun stuff.

Without futher ado...

The process is rather basic, but you can build on it as it goes.  Here is the basic steps to follow:

1)  Create a new website.
2)  Add a web user control to the site (.ascx).  You will find this in the "Add New Item" menu of your site.
3)  Do whatever you need to do on your user control.  Remember to make whatever properties you need access on the control declaration public in the C# (just encapsulate your fields!).
4)  Once complete, go to the Build menu and choose "Publish Web Site"
5)  You will be given the option to change some of your setings here.  Naturally you want to select where to build to.  Also, uncheck the "Allow this precompiled site to be updatable" for right now.  Finally, check the "Use fixed name and single page assemblies".  You can do some more fun stuff here, but play with that later when you master the basics.

So now you have your .dll (check in the bin folder of the site you complied).  In order to use it, just do this...

1)  Create a new site or open the one you want to stick it into.
2)  Add the .ddl to the bin. 
3)  Register the .dll on the page.  (do this using the @Register attribute of the page)

<%@ Register TagPrefix="ASP" Namespace="ASP" Assembly="App_Web_test.ascx.cdcab7d2" %>
<%@ Register TagPrefix="ASP" Namespace="ASP" Assembly=" App_Web_amazonservices.ascx.cdcab7d2" %>

*Remember to exclude the .dll from the Assembly name... 

Once you have done this, you will be good to go!

This process has some great advantages, which I am sure you all recognize.  Also, those publice encapsulated fields are now availiable for you to set on the .net side of things. 

I have created a web user control for amazon web services, which I will post a tutorial about at a later time.  Happy coding! 

Generic Lists (List) and Predicates

So, for those of you who have much experience w/ C# / vb .net, you are most likely used to the generic list.  List<T>, which is a child of the System.Generic namespace, is a generic container in which you can stuff whatever items you wish, so long they are of the same type.  This includes basic structures like strings and complex objects / class instances. 

This is all pretty awesome, but the fun only increases when you are trying to check to see if one of those class instances has a value you are looking for.  This is where the Predicate Generic Delegate comes into play. In a nutshell, the Predicate "represents the method that defines a set of criteria and determines whether the specified object meets those criteria" (Thanks MSDN, that clears it right up!).  In other words, it lets you delegate an action (like the action of checking an item instance for a value) to a separate function.  This is very good for us!  Check out the following code...

Basic Class...

<code type="c#">

public class AccessItem
{
    private object _objKey;

    public object ObjKey
    {
        get { return _objKey; }
        set { _objKey = value; }
    }

    private string _strKeyName;

    public string StrKeyName
    {
        get { return _strKeyName; }
        set { _strKeyName = value; }
    }

    private string _strAccessLevel;

    public string StrAccessLevel
    {
        get { return _strAccessLevel; }
        set { _strAccessLevel = value; }
    }

    public AccessItem(object Key, string KeyName, string AccessLevel)
    {
        _objKey = Key;
        _strAccessLevel = AccessLevel;
        _strKeyName = KeyName;
    }
}

</code>

Create a List and add some class instances...

<code type="c#">

List<AccessItem> tempList = new List<AccessItem>();

for(int x = 0; x < 10; x++)
{
  tempList.Add(new AccessItem(x, x + "Name", x + "AccessLevel");
}

</code>

Now, lets say that you want to find the access item w/ the key of 5.  If this were a basic int list, you could simply use the Contains bool in the List&#60;T&#62; properties.  In this case (since we are not dealing w/ a basic object), we are either stuck w/ looping through the list and checking values of each instance, or using the predicate.  The syntax for checking w/ a predicate is as follows...

<code type="c#">

tempList.Exists(delegate(AccessItem ai) { return ai.ObjKey == 5; })

</code>

Anyway, it is very painless and very maintainable.  Also, you have full access to your stuffed object, so feel free to drill down as far as you would wish in order to compare values...  Very cool!

The Game

If you are like me, you have 10 gazillion movies lying around your house.   In my case, I literally own hundreds of movies that are sitting around, never watched or only watched once.  That is not to say that I do not ever watch movies, but frankly “they” churn out movies faster than I can keep up.  Consequently, certain movies tend to get overlooked and never watched as the blockbusters are released and become the “must-have / must-watch” movie of the week.   Sadly, that leaves quite a few movies that might as well be coasters rather than anything useful.
In the odd occurrence that I have time to watch a movie and the movie choice is not evident, we have problems.  Living in a house with my wife and 3 roommates, it is needless to say that we have different tastes.  I tend to favor the action / adventure (I am also a sucker for the “classics” but I don’t want ppl to know.  I would hate to lose the man-points).  Crystal usually goes for the love / tragedy tear-jerker.  She also loves the classic slapstick comedy, National Lampoons Christmas Vacation being her favorite movie of all time.  Crystal and I both meet in the middle in that we are horror nuts.  Needless to say the choice is very difficult due to the fact that I want to watch Lord of the Rings for the 100th time and that she wants to see Because I Said So or some Lifetime Special (that usually makes me want to stab out my eyes halfway through).

In order to keep the peace, Crystal and I devised a way to determine the movie we want to watch without having to deal w/ the debate of what to do.  We leave the decision making process to a game which we call…  The Game..  nice huh?  Anyway, the rules are simple…

 

  1. The Game is all powerful.  All decisions are final… there can be no exceptions!  (if you violate this rule, you pretty much invalidate the game) On a side note, we have violated this rule before and replayed the game, only to get the same movie choice…  the Game knows!
  2. You chose a set number of movie entries that everyone has.  You can enter ANY movie and the rest of the group is subject to having to watch it.
  3. As just stated, everyone MUST watch the selected movie.  This makes it fun to select choices that only makes ppl suffer
  4. Optional Rule: You much decide a new game for every instance of The Game.  This rule is really fun and requires a bit of thought.  Eventually, you run out of steam though, but I recommend it.
  5. Optional Rule:  Taunting is allowed so long as the movie is not being played.  The selector of the movie can determine whether you can trash talk throughout the viewing (some movies it works, some it does not.

Beyond those rules, you simply have to create / select a game that is able to randomly determine the final result.  Currently we have played house miniature golf, all manner of card games, bingo, ring tosses, etc.  We ended up enjoying the Game almost as much as the movie.  The more creative The Game, the crazier it gets.

As it turns out, this turned out being a very fun way thing to do even though it is rather simple.  Also, there is another aspect to the Game.  Usually we have to pick about 5 movies each to enter.  Depending upon the number of players, you end up w/ around 20 movies on the table, which makes a very broad selection.  Usually, you end up watching movies that you would never watch in a million years, but enjoy it just the same. 

Pretty cool!

Active Directory Fun

Active Directory

If you have spent any amount of time working w/ authentication in C#, I am sure that you have run across having to authenticate / query Active Directory.  Although it is really not a hard process, it can be a bit of a hassle in that there are a few gotchas and a few concepts that are not in your standard bag of tricks.   Below are a few tips on how to work w/ Active Directory and how to interface with it.  I am going to be focusing on how to work with users only.  Working w/ other objects (Computers, Groups, etc.) work in a similar fashion, but can get a bit more hairy that simply dealing w/ users.

  First off, you need to understand how you interface with <a href=" http://en.wikipedia.org/wiki/Active_Directory">Active Directory</a>.  All connections, searches, and queries to Active Directory is done using <a href="http://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol">LDAP</a>.  Although LDAP can be a bit confusing  at first, you will find that it is very simple to master and use.  In fact, once you get pretty good with it, you can do advanced LDAP queries in Active Directory using the Active Directory Users and Computers tool in the Administrator Tools of windows.  (TIP:  if you have having trouble configuring a LDAP query, go to your Active Directory Users and Computers tool and run the query there.  You get instant results and it is much easier to test them. )

<a href=" http://technet.microsoft.com/en-us/library/aa996205.aspx">Nice Place to start w/ LDAP</a>

Once you get the concept of LDAP under your belt, you are good to go w/ C#.  The biggest thing that you do need to do is to add a reference to System.DirectoryServices.  You can do this by adding a reference by right-clicking your project and choosing “Add Reference”.

One final hurtle you may run across before you can start pounding out the code is specifying your domain path in LDAP.  This not hard, but sometimes it throws people for a loop in figuring out how to structure it.  If I am querying users, I would use something like this…. “CN” being the container name I am trying to access…

LDAP://CN=Users,DC=nathanblevins,DC=com

From there on out, it is pretty much downhill.  Here are a few examples of things that you can do (that I use all the time…)

Note:  Most of these code samples are an excerpt from a larger class.  You will need to make sure the _DomainPath and _outputPath strings exist before this will compile.

Authenticating Users – This is a quick method used to authenticate users.  Pretty much, you need to have the username, password, and domain path in which to look for the user.  Also, I have added a quick method used to write the authentication attempts to a text file.  Only do this for debugging, please. 

<code type="c#">

/// <summary>
/// Accepts a username and password and tries to authenticate it in active directory.
/// </summary>
/// <param name="Password">The user's password attempt.</param>
/// <param name="Username">The username you are trying to authenticate</param>
public bool AuthenticateUser(string Username, string Password)
{
    //Create a new directory entry object.
    DirectoryEntry entry = new DirectoryEntry(_DomainPath, Username, Password);

    //Write the attempt to a log file.
    if (_outputPath != String.Empty)
    {
        WriteAttemptToLogFile("Login Attempt: " + Username + " --- " + Password + " --- " + DateTime.Now.ToString());
    }

    try
    {
        DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = "(SAMAccountName=" + Username + ")";
        search.PropertiesToLoad.Add("cn");
        SearchResult result = search.FindOne();

        if (result == null)
        {
            //User Authentication Failed.
            return false;
        }
        else
        {
            //User Authentication Succeeded
            return true;
        }
    }
    catch
    {
        //Error thrown, user authentication failed.
        //TODO:  Add output varibles to specify the error.
        return false;
    }
}

/// <summary>
/// Writes a provided string to the specified log file.
/// </summary>
/// <param name="LogString">String that you wish to write to the long file.</param>
private void WriteAttemptToLogFile(string LogString)
{
FileInfo fi = new FileInfo(_outputPath);
if (fi.Exists)
{
    File.AppendAllText(_outputPath, LogString + "\n\r");
}
else
{
    File.WriteAllText(_outputPath, LogString + "\n\r");
}
}

</code>

Check for user existence by SamAccountName

<code type="c#">
/// <summary>
/// Checks to see if a Username exists in Active Directory.  No Password required.
/// </summary>
/// <param name="Username">The username that you want to check for</param>
public bool CheckToSeeIfUserExists(string Username)
{

//Start a new directory searcher that looks for a match in the SAMAccoutName records.
DirectorySearcher search = new DirectorySearcher();
search.Filter = String.Format("(SAMAccountName={0})", Username);
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();

if (result == null)
{
    //No records found
    return false;
}
else
{
    //Record found, the username exists
    return true;
}
}

</code>

Sometimes you just need to know what is available to you.  In this case, I usually use this class that I have thrown together.  It has reference to most of the common Active Directory User properties and a brief description of what they are.  Usually, I cut what I really want out of this class, but feel free to use it in its entirety as well (although it is a bit messy).

<code type="c#">
public class ActiveDirectoryUser
{

private string _strCN;
/// <summary>
/// CN=Guy Thomas.  Actually, this LDAP attribute is made up from givenName joined to SN.
/// </summary>
public string StrCN
{
    get { return _strCN; }
    set { _strCN = value; }
}
private string _strDescription;
/// <summary>
/// What you see in Active Directory Users and Computers.  Not to be confused with displayName on the Users property sheet.
/// </summary>
public string StrDescription
{
    get { return _strDescription; }
    set { _strDescription = value; }
}
private string _strDN;
/// <summary>
/// DN is simply the most important LDAP attribute.
/// </summary>
public string StrDN
{
    get { return _strDN; }
    set { _strDN = value; }
}
private string _strGivenName;
/// <summary>
/// Firstname also called Christian name
/// </summary>
public string StrGivenName
{
    get { return _strGivenName; }
    set { _strGivenName = value; }
}
private string _strSAMAccountName;
/// <summary>
/// sAMAccountName = guyt.  Old NT 4.0 logon name, must be unique in the domain.  Can be confused with CN.
/// </summary>
public string StrSAMAccountName
{
    get { return _strSAMAccountName; }
    set { _strSAMAccountName = value; }
}
private string _strUserAccountControl;
/// <summary>
/// Used to disable an account.  A value of 514 disables the account, while 512 makes the account ready for logon.
/// </summary>
public string StrUserAccountControl
{
    get { return _strUserAccountControl; }
    set { _strUserAccountControl = value; }
}
private string _strUserPrincipleName;
/// <summary>
/// userPrincipalName = guyt@CP.com    Often abbreviated to UPN, and looks like an email address.  Very useful for logging on especially in a large Forest.   Note UPN must be unique in the forest.
/// </summary>
public string StrUserPrincipleName
{
    get { return _strUserPrincipleName; }
    set { _strUserPrincipleName = value; }
}
private string _strMail;
/// <summary>
/// An easy, but important attribute.  A simple SMTP address is all that is required billyn@ourdom.com
/// </summary>
public string StrMail
{
    get { return _strMail; }
    set { _strMail = value; }
}
private string _strHomeMDB;
/// <summary>
/// Here is where you set the MailStore
/// </summary>
public string StrHomeMDB
{
    get { return _strHomeMDB; }
    set { _strHomeMDB = value; }
}
private string _strMSExchHomeServerName;
/// <summary>
/// Exchange needs to know which server to deliver the mail.  Example:
/// </summary>
public string StrMSExchHomeServerName
{
    get { return _strMSExchHomeServerName; }
    set { _strMSExchHomeServerName = value; }
}
private string _strCompany;
/// <summary>
/// Company or organization name
/// </summary>
public string StrCompany
{
    get { return _strCompany; }
    set { _strCompany = value; }
}
private string _strDepartment;
/// <summary>
/// Useful category to fill in and use for filtering
/// </summary>
public string StrDepartment
{
    get { return _strDepartment; }
    set { _strDepartment = value; }
}
private string _strHomePhone;
/// <summary>
/// Home Phone number, (Lots more phone LDAPs)
/// </summary>
public string StrHomePhone
{
    get { return _strHomePhone; }
    set { _strHomePhone = value; }
}
private string _strPostalCode;
/// <summary>
/// Zip or post code
/// </summary>
public string StrPostalCode
{
    get { return _strPostalCode; }
    set { _strPostalCode = value; }
}
private string _strStreetAddress;
/// <summary>
/// First line of address
/// </summary>
public string StrStreetAddress
{
    get { return _strStreetAddress; }
    set { _strStreetAddress = value; }
}
private string _strTelephoneNumber;
/// <summary>
/// Office Phone
/// </summary>
public string StrTelephoneNumber
{
    get { return _strTelephoneNumber; }
    set { _strTelephoneNumber = value; }
}
private string _strSN;
/// <summary>
/// SN = Thomas. This would be referred to as last name or surname.
/// </summary>
public string StrSN
{
    get { return _strSN; }
    set { _strSN = value; }
}
private string _strState;
/// <summary>
/// State, Province or County
/// </summary>
public string StrState
{
    get { return _strState; }
    set { _strState = value; }
}
private string _strHomeDrive;
/// <summary>
/// Home Folder : connect
/// </summary>
public string StrHomeDrive
{
    get { return _strHomeDrive; }
    set { _strHomeDrive = value; }
}
private string _strOffice;
/// <summary>
/// Office! on the user's General property sheet
/// </summary>
public string StrOffice
{
    get { return _strOffice; }
    set { _strOffice = value; }
}
private string _strLegacyExchangeDN;
/// <summary>
/// Legacy distinguished name for creating Contacts. In the following example,
/// </summary>
public string StrLegacyExchangeDN
{
    get { return _strLegacyExchangeDN; }
    set { _strLegacyExchangeDN = value; }
}
private string _strProxyAddresses;
/// <summary>
/// As the name 'proxy' suggests, it is possible for one recipient to have more than one email address.  Note the plural spelling of proxyAddresses.
/// </summary>
public string StrProxyAddresses
{
    get { return _strProxyAddresses; }
    set { _strProxyAddresses = value; }
}
private string _strManager;
/// <summary>
/// Boss, manager
/// </summary>
public string StrManager
{
    get { return _strManager; }
    set { _strManager = value; }
}
private string _strMobile;
/// <summary>
/// Mobile Phone number
/// </summary>
public string StrMobile
{
    get { return _strMobile; }
    set { _strMobile = value; }
}
private string _strDisplayName;
/// <summary>
/// displayName = Guy Thomas.  If you script this property, be sure you understand which field you are configuring.  DisplayName can be confused with CN or description.
/// </summary>
public string StrDisplayName
{
    get { return _strDisplayName; }
    set { _strDisplayName = value; }
}
private string _strCountryRegion;
/// <summary>
///Country or Region.
/// </summary>
public string StrCountryRegion
{
    get { return _strCountryRegion; }
    set { _strCountryRegion = value; }
}

/// <summary>
/// String of active directory property names.  Order matches the order of the property listings...
/// </summary>
private string[] ActiveDirectoryPropertyValues = new string[] {
    "cn",
    "company",
    "c",
    "department",
    "description",
    "displayName",
    "DN",
    "givenName",
    "homeDrive",
    "homeMDB",
    "homephone",
    "legacyExchangeDN",
    "mail",
    "manager",
    "mobile",
    "msExchHomeServerName",
    "physicalDeliveryOfficeName",
    "postalCode",
    "proxyAddresses",
    "sAMAccountName",
    "SN",
    "st",
    "streetAddress",
    "teleponeNumber",
    "userAccountControl",
    "userPrincipleName",
};
/// <summary>
/// Accepts a username to load user data.
/// </summary>
/// <param name="Username">Sam Account Name to Load.</param>
public ActiveDirectoryUser(string Username)
{
    DirectorySearcher search = new DirectorySearcher();
    search.Filter = String.Format("(SAMAccountName={0})", Username);

    for (int x = 0; x < ActiveDirectoryPropertyValues.Length; x++)
    {
        search.PropertiesToLoad.Add(ActiveDirectoryPropertyValues[x]);
    }

    SearchResult result = search.FindOne();

    //Take care to make sure order matches with that of the string[]ActiveDirectoryPropertyValues.
    _strCN = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[0]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[0]][0].ToString() : "";
    _strCompany = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[1]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[1]][0].ToString() : "";
    _strCountryRegion = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[2]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[2]][0].ToString() : "";
    _strDepartment = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[3]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[3]][0].ToString() : "";
    _strDescription = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[4]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[4]][0].ToString() : "";
    _strDisplayName = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[5]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[5]][0].ToString() : "";
    _strDN = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[6]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[6]][0].ToString() : "";
    _strGivenName = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[7]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[7]][0].ToString() : "";
    _strHomeDrive = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[8]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[8]][0].ToString() : "";
    _strHomeMDB = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[9]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[9]][0].ToString() : "";
    _strHomePhone = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[10]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[10]][0].ToString() : "";
    _strLegacyExchangeDN = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[11]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[11]][0].ToString() : "";
    _strMail = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[12]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[12]][0].ToString() : "";
    _strManager = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[13]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[13]][0].ToString() : "";
    _strMobile = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[14]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[14]][0].ToString() : "";
    _strMSExchHomeServerName = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[15]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[15]][0].ToString() : "";
    _strOffice = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[16]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[16]][0].ToString() : "";
    _strPostalCode = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[17]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[17]][0].ToString() : "";
    _strProxyAddresses = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[18]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[18]][0].ToString() : "";
    _strSAMAccountName = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[19]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[19]][0].ToString() : "";
    _strSN = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[20]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[20]][0].ToString() : "";
    _strState = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[21]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[21]][0].ToString() : "";
    _strStreetAddress = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[22]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[22]][0].ToString() : "";
    _strTelephoneNumber = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[23]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[23]][0].ToString() : "";
    _strUserAccountControl = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[24]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[24]][0].ToString() : "";
    _strUserPrincipleName = Convert.ToBoolean(result.Properties[ActiveDirectoryPropertyValues[25]].Count > 0) ? result.Properties[ActiveDirectoryPropertyValues[25]][0].ToString() : "";
}
}
</code>

Finally, a big gotcha… when you are wanting to sort your queries, you can call the Search Option method on your Active Directory Searcher.  On a side note, people sometimes get Filter and Sort mixed up.  Sorting specifies  the order in which you receive your result.  Filtering actually weeds out unneeded results.  Anyway, one of the big problems is that the active directory sorter will only allow you to sort on items that are indexed in active directory. Sadly, the display name and username are not indexed.  Therefore, if you want to sort them (to populate a drop down list or something), I would recommend implementing the IComparable Interface, like this…

Quick note – By implementing the interface, you are changing the Default sort option on that object.  You can add additional sorts by creating a public static Comparison<T> method.  Then, by adding an additional parameter to the Sort Method (changing it from the default sort), you can access those as well.  Pretty sweet!

<code type="c#">
public class ActiveDirectoryUserListing : IComparable<ActiveDirectoryUserListing>
{
private string _strDisplayName;

public string StrDisplayName
{
    get { return _strDisplayName; }
    set { _strDisplayName = value; }
}
private string _strUsername;

public string StrUsername
{
    get { return _strUsername; }
    set { _strUsername = value; }
}

public ActiveDirectoryUserListing(string Username, string Displayname)
{
    _strDisplayName = Displayname;
    _strUsername = Username;
}

#region IComparable<ActiveDirectoryUserListing> Members

public int CompareTo(ActiveDirectoryUserListing other)
{
    return StrDisplayName.CompareTo(other.StrDisplayName);
}

public static Comparison<ActiveDirectoryUserListing> UsernameComparison =
    delegate(ActiveDirectoryUserListing listing1, ActiveDirectoryUserListing listing2)
    {
        return listing1.StrUsername.CompareTo(listing2.StrUsername);
    };

#endregion
}

/// <summary>
/// Gets all the usernames in active directory and stuffs them into a List.
/// </summary>
public List<ActiveDirectoryUserListing> GetAllUsernames
{
get
{
    //Make the list.
    List<ActiveDirectoryUserListing> tempList = new List<ActiveDirectoryUserListing>();
    //Make the searcher object
    DirectorySearcher search = new DirectorySearcher();
    //Add the search filter... one must be present in order to get any results...
    search.Filter = "(&(objectCategory=user)(objectClass=person)(sAMAccountName=*)(!msExchUserAccountControl=2)(!Description=Built*)(!Description=Hide*))";
    search.PropertiesToLoad.Add("sAMAccountName");
    search.PropertiesToLoad.Add("displayName");

    SearchResultCollection result = search.FindAll();

    for (int x = 0; x < result.Count; x++)
    {
        //Make sure the items found has a username property (does not return null).  If it has a value, stuff it!
        string SAMAccountName = Convert.ToBoolean(result[x].Properties["sAMAccountName"].Count > 0) ? result[x].Properties["sAMAccountName"][0].ToString() : "";
        string DisplayName = Convert.ToBoolean(result[x].Properties["displayName"].Count > 0) ? result[x].Properties["displayName"][0].ToString() : "";

        if (SAMAccountName != String.Empty)
        {
            //Stuffed...
            tempList.Add(new ActiveDirectoryUserListing(SAMAccountName, DisplayName));
        }
    }

    return tempList;
}
}
</code>

Anyway, I hope this helps out a bit.  In the interest of space, I am not posting the entire class, but you have the bulk of the methods.   Hope this helps.

Detect Page Refresh C# (after Post methods)

Okay...  So you are working on this great site.  You have all your DataTables set and your are just churning away, inserting records and keeping track of data.  Then, as you look through your database, you realize that you have duplicate records everywhere.  After grinding your code, you realize that is not really a programing error, but it is simply your "wonderful" users refreshing the stupid page, or navigating using the back button. Arggg!  Programming would be awesome w/o users!  lol.

This is really a situation that all programmers of all languages have to face.  Thankfully, if you are a .Net programmer, you have a pretty good option to get around this.  After googling a bit, I found all sorts of ideas / work arounds, provided by a great assortment of folks ranging from Dino Esposito to just random people, like me. 

Anyway, here is the basic concept.  Whenever a page is first loaded, the SaveViewState method is called.  This method is only called when the page is loaded.  After that, the LoadViewState is called on every page refresh.  What this means, is that you have an overwritable method that is only called on the page's first and another that is called every time that page is requested.  Lets abuse that! 

DISCLAIMER - I am piggiebacking on quite a few different people here and using pieces of their code.  I am having a bit of trouble finding the sources right now, but I will post them as soon as I find them.

Anyway... the code:

<code type="c#">

private bool _refreshState;
private bool _isRefresh;

public bool IsRefresh
{
    get
    {
        return _isRefresh;
    }
}

protected override void LoadViewState(object savedState)
{
    object[] allStates = (object[])savedState;
    base.LoadViewState(allStates[0]);
    _refreshState = (bool)allStates[1];
    _isRefresh = _refreshState == (bool)Session["__ISREFRESH"];
}

protected override object SaveViewState()
{
    Session["__ISREFRESH"] = _refreshState;
    object[] allStates = new object[2];
    allStates[0] = base.SaveViewState();
    allStates[1] = !_refreshState;
    return allStates;
}

</code>

Essentially, this bit of code sticks a var into the session, comparing the value every time the page is "refreshed" and resetting the value when a the SaveState is called (after insertions and actual postbacks).

Now, the main question is where to put it.  Really you have 2 options.  If you are just wanting this functionality on 1 page, overwrite the page object and make sure your target page inherits your new page object rather than from the standard one.  In my case, I want this functionality everywhere.  Therefore, I overwrote the Master page object and made sure my masterpage inherited from my custom object.  Consequently, you can reference your page's master page and that nice "IsRefresh" boolean will be there as one of the MasterPage's properties.  Very cool!

If you a Web User Control user (like me).  You can still use this.  Unfortunately, you will have to assume that your master page of the control will be present and will be the Custom page you created.  If you can make that leap logic, you simply need to grab the Page object and its MasterPage. 

<code type="c#">


((CustomMasterPage)Page.Master).IsRefresh

</code>

Hope this works well for everyone.  It has done wonders for me, when I needed it.

I now have my "binky"

Call it what you will, but every person has that one thing that he /she desires above all things.  This thing is usually material (sometimes not) but represents something much deeper than the object itself.  It is something that, by its very nature, makes you happy and makes your quality of life better due to your connections / feelings w/ this object.  In <em>Gone in 60 Seconds</em>, Nicolas Cage called it his unicorn.  In <em>Teenage Mutant Ninja Turtles</em>, Slash called it his binky (I think, lol).  Whatever you call it, it is something that you want very badly not for material gain but more for the reasons that it triggers something in you that seems to make you more complete...

Anyone who has been around me much at all knows that there is one such item that I have been drooling over for the past 2 years (or maybe longer, lol)...  a motorcycle.  In fact, I have been drooling over bikes so long that it has become something of a running gag in which everyone delights in pointing them out every time I pass them in order to hear me whine about how much I would love to have one.  /sigh

Why a motorcycle?  To be honest, it is pretty hard to explain without sounding like some half-crazed hippie (no offense to those half-sane hippies out there, ;) ).  A motorcycle is a symbol of ultimate freedom to me.  You are out on the road as open to world as you can possibly be (without having to walk, lol).  You have options to go places and do things that you could never do w/ a car.  Cars have always felt very restrictive to me, due to the fact that you are viewing the world through some kind of TV-screen-like window, rather than experiencing it for yourself. 

When I was younger, I had very good experiences riding off-road trails w/ my brother and cousin on their bikes. It was a very fun time in my life and one that I would like to revisit now, if I could.  There is a measure of community in motorcycles as well (much like owning a beat up old truck).  When you meet other bikers, you have a bit more in common than any other passerby, which makes a huge difference sometimes.  Also, it makes for good stories later like... remember that time you half-died while trying to jump object x? ... ... ...  lol

Anyway, I have finally decided that this is the time to get a bike.  So, while visiting w/ my family  this weekend, I was able to place an order for this bike:

motorcycle2

motorcycle1

It is a dual-sport Kawasaki KLR650.  It is fitted for both on and off road travel.  The reasons I picked this bike are many.  First off, I had to have a on / off road bike.  Why would I want a bike that I could not jump / climb walls w/?  (unless it was bike #2...  lol).  The Kawasaki is a bit of bigger bike than than its equivalent model peers.  Although smaller bikes are nice for being able to maneuver in tight spots, such as the woods, I want something that will be comfortable for the highways.  Also, the Kawasaki seems to have a better accessory line than most others.  Although this is not a big concern, it was enough to assist w/ the decision making process.

Finally, I really liked the seat layout on this bike, as I hope to make Crystal my biker chick....  Maybe I need to get one of those "The B*tch fell off shirts" lol... (Just quoting the shirt, Crystal).  As I said before, riding is kindof a community thing for me, so it is really important to me to have my partner in life be riding w/ me as well. 

Anyway, I now have a new bike!  Rock!  I will hopefully be able to pick it up next weekend and go riding.  On a side note, I just got <a href="http://www.dylanwolf.com">Dylan</a> to say that he would "most likely" buy a bike if I ever did so. Of course, he does not know as of yet that I have already bought one...  lol

So, Dylan, its time to pony up!

TVersity

Media comes in all shapes and sizes nowadays.  Everyone knows that...  The problem we have,though, is methods to consume those formats.  I am one of those that likes to have 1 place to go to for all of my media stuff.  If I have avi's, dvd's, Internet videos feeds, etc, etc.,  I would prefer to be able to have them all accessible in 1 place.  To compound the issue, I also like to be able to play this centralized video repository anywhere I want.

Anyway, so I start looking for my solution.  The first obvious choice is Windows Media Center.  It is okay...  It really does not support all the file formats I want.  It does not do Internet video feeds.  Finally, it is not very friendly w/ other playback devices, other than a TV.  You can "make" it do more, but IMHO it is really more trouble than its worth, especially since any patching on M$'s side will break your fixes.

After looking around for a while, I ran across TVersity.  This little app is hardcore.  Basically, they promise that they can hook up to almost any video format that you can configure your computer to play and... it will play back on almost any device.  In order to do this, the have many differnt ways to connect to the server including uPNP, Flash, HTTP, etc.  Very nice!  Essentially, this means that I can not only consume any media into my library, but I can also play it back on my PS3, XBOX, XBOX 360, Wii, TV, other computers, PSP, Nintendo DS (I think), computer at work, hacker's computer in China, etc., etc., etc...  Awesome.  The basic gist is that if your computer can play it, Tversity can stream it.  I takes the playback on the computer and re-encodes the video feed into a the format that is applicable to the requesting device.  In fact, it has a large list and is rather "smart" when it comes to picking the right format for the right device.

Although I would never want to watch Dragonball Z on my PSP, knowing that I can is pretty freaking cool!

After downloading, installing, adding the media, and running the server, I was ready to start viewing...  Error: Unsupported format...  Error:  Cannot connect...  Error: Generic Message..  It seems that although Tversity may play on any system you will most likely have real issues getting to play on ANY system.  lol...

The problem w/ installing Tversity is that it depends upon many things.  1st off, you have to make sure you have all the right codecs.  2ndly, you have a lot of permission issues you have to work through.  Finally, you need to do some tweaking, depending upon what you are serving from. 

This problem is confounded b/c there are so many "fixes" out there for every issue, of which only 1/2 works...  I spent DAYS trolling forums, trying to get everything right.  As it turns out, most of it is pretty simple, but much of the advice tends to throw you down some deep rabbit holes.  After looking into it, here is the setting that finally worked for me.

1)  Install the latest and greatest FFDSHOW.  Many ppl will tell you to get the beta version or the version 2 years old, etc etc etc.  That only wasted my time...

2)  Tversity's service account MUST run as administrator.  I don't care what anyone else says.  If this is not running as Admin, it will not work.  Also, you will get very generic errors on your system like "Unsupported format".  It will not throw an error on the system.

3)  If you are grabbing a Linux share in your video list, you must make sure the tversity service account is a user on that Linux box.  This will allow the PS3 to read the share.  The 360, to date, still does not play nice.

4)  Restart the service every time you make a change of codecs.  You must choose restart service in the menu option or in the Services console to do so.  Closing and reopening the app does not touch the service.

5)  If you want subtitle support (for avi), they must be in a separate directory and of the .srt format.  (If you encoded them directly on the video, ignore this).  In order to allow the system to find them, go into the settings for FFDSHOW and point to the subtitle directory.  The subtitles must be named exactly like the movie file (excluding the extension).

6)  When the library is refreshing, do not try to access the videos b/c it will throw random generic error.  In fact, when you get the "Unsupported format" error, make sure the library is not being refreshed.  This is a total pain when you are troubleshooting.

7)  Also, if you have spent a long time on trying to fix it.  Be sure to clean up after yourself.  If worse comes to worse, uninstall the servers and all applicable codecs.  Many people have issues that they fix, but don't work b/c they tried so many fixes.

Anyway, TVersity is pretty awesome.  Once you get it up and running it is well worth the time it took to set up.  Check it out!

DylanW's picture

I Almost Died On Sunday

Well, not really. But I like telling everyone that because it sounds cool. And it got you to read this post, right?

And now, you can enjoy it too, thanks to the magic of YouTube:

I obviously have no clue how to ride a motorcycle, and it's pretty clear that it would be safer if I didn't even try.

More...

daryl's picture

Bobby

It’s my impression that by the time Lennie was Finn’s age, she was already speaking a ton of words, mostly the names of animals from an animal book we’ve also shared with Finn (though probably less often — having two kids is harder than having one, and you wind up short-changing both in lots of ways that make you feel really bad). Finn is turning out to be a little more sluggish with words (it’s pretty common for boys, I believe), but he’s finally started to show an interest in words and other linguistic feats. For example, he’s pretty good for saying “dog” now. He routinely says “mama,” but he tends to use it in a pretty general sense, usually barking it whenever he wants something. After some work with the animal book, he’ll volunteer “neeee” if you ask him what a horse says, and with a little prompting, he’ll do a chicken sound. The most impressive thing at the moment is that he’s picked up “bite, please,” which is what we croon at him when he’s insisting “maMA” and reaching for food. He’s not terribly consistent about it yet, but it’s not uncommon for him to say “bite, please” when he wants food or drink, though it comes out more like “Bobby” with a big pause in the middle.

Not to be outdone by her little brother, Lennie has started reading and writing on a limited basis. She’s been increasingly curious about letters, and we’ve been helping her learn their sounds and doing the old “duh, ahh, guh” drill to show her how to string them together to make words. The other morning, she had written “cat,” and neither of us had explicitly drilled her on that one. When we asked her how she had come up with it, she said that she had just worked it out based on the sounds. I’m not entirely sure I believe her, but it’s certainly not beyond the realm of what’s possible.

She continues to be a good little artist as well, picking up things like perspective without any prompting. The other day, she drew one fish at sort of an angle and some other fish from the side; the sideways ones had only one eye (they were not flounder). This sounds lame and obvious if you don’t have small children, but it’s a pretty neat thing to watch happen.