Sander
terug naar het overzicht

One of the programming      guys

Als ontwikkelaar mag ik graag problemen oplossen en nieuwe functionaliteit bouwen. Vanuit mijn creatieve kant hou ik me ook graag bezig met hoe iets bij de eindgebruiker aankomt. Je kunt bij mij dus ook terecht voor de opmaak en layout van een oplossing. Als je mij wilt afleiden, dan lukt dat altijd met een coole nieuwe gadget. Dat is namelijk mijn andere passie.

.NET and ISO 3166-1 Country codes.

door Sander 19-1-2012

The ‘co’ (country) attribute in Active Directory is a strange property… You cannot just set it to some value and be done with it. This attribute has two partners in crime and they are picky about the stuff you throw at them!

The attributes I’m talking about are:

  •  
    • co
    • c
    • countryCode

These attributes must be set together at the same time with specific values for them to be stored in Active Directory.

Let’s look at the values you are allowed to use for these properties.. yep, you will need the ISO 3166-1. My first guess was using the CultureInfo and RegionInfo objects that are available in the .NET Framework, but beware! The list of cultures in .NET is incomplete and you cannot get the numeric code from the RegionInfo either.

So we need to set the name of a country, its two-letter name, and some cryptic code all at once. ‘co’ needs the full name of a country, ‘c’ needs a two-letter countrycode and the ‘countryCode’ requires the numeric code. Below you will find some code that has all that stuff ready-made so you don’t have to! All you need to do now is have your code find a country and update a DirectoryEntry.

Here is the code that you can adjust to your needs for the taking! The code has all the countries that are on the ISO 3166-1 list. Feel free to leave a comment if you have an improvement on this code!

Use it any way you want, happy copy-pasting Smile

public class CountryData
    {
        public string Name { get; private set; }
        public string TwoLetterCode { get; private set; }
        public int NumericCode { get; private set; }

        public CountryData(string fullName, string twoLetterCode, int numericCode)
        {
            Name = fullName;
            TwoLetterCode = twoLetterCode;
            NumericCode = numericCode;
        }
    }

    public class CountryInfo
    {
        public readonly ICollection<CountryData> Countries;

        public CountryInfo()
        {
            Countries = new List<CountryData>
            {
                { new CountryData("Afghanistan", "AF", 4) },
                { new CountryData("Åland Islands", "AX", 248) },
                { new CountryData("Albania", "AL", 8) },
                { new CountryData("Algeria", "DZ", 12) },
                { new CountryData("American Samoa", "AS", 16) },
                { new CountryData("Andorra", "AD", 20) },
                { new CountryData("Angola", "AO", 24) },
                { new CountryData("Anguilla", "AI", 660) },
                { new CountryData("Antarctica", "AQ", 10) },
                { new CountryData("Antigua and Barbuda", "AG", 28) },
                { new CountryData("Argentina", "AR", 32) },
                { new CountryData("Armenia", "AM", 51) },
                { new CountryData("Aruba", "AW", 533) },
                { new CountryData("Australia", "AU", 36) },
                { new CountryData("Austria", "AT", 40) },
                { new CountryData("Azerbaijan", "AZ", 31) },
                { new CountryData("Bahamas", "BS", 44) },
                { new CountryData("Bahrain", "BH", 48) },
                { new CountryData("Bangladesh", "BD", 50) },
                { new CountryData("Barbados", "BB", 52) },
                { new CountryData("Belarus", "BY", 112) },
                { new CountryData("Belgium", "BE", 56) },
                { new CountryData("Belize", "BZ", 84) },
                { new CountryData("Benin", "BJ", 204) },
                { new CountryData("Bermuda", "BM", 60) },
                { new CountryData("Bhutan", "BT", 64) },
                { new CountryData("Bolivia, Plurinational State of", "BO", 68) },
                { new CountryData("Bonaire, Sint Eustatius and Saba", "BQ", 535) },
                { new CountryData("Bosnia and Herzegovina", "BA", 70) },
                { new CountryData("Botswana", "BW", 72) },
                { new CountryData("Bouvet Island", "BV", 74) },
                { new CountryData("Brazil", "BR", 76) },
                { new CountryData("British Indian Ocean Territory", "IO", 86) },
                { new CountryData("Brunei Darussalam", "BN", 96) },
                { new CountryData("Bulgaria", "BG", 100) },
                { new CountryData("Burkina Faso", "BF", 854) },
                { new CountryData("Burundi", "BI", 108) },
                { new CountryData("Cambodia", "KH", 116) },
                { new CountryData("Cameroon", "CM", 120) },
                { new CountryData("Canada", "CA", 124) },
                { new CountryData("Cape Verde", "CV", 132) },
                { new CountryData("Cayman Islands", "KY", 136) },
                { new CountryData("Central African Republic", "CF", 140) },
                { new CountryData("Chad", "TD", 148) },
                { new CountryData("Chile", "CL", 152) },
                { new CountryData("China", "CN", 156) },
                { new CountryData("Christmas Island", "CX", 162) },
                { new CountryData("Cocos (Keeling) Islands", "CC", 166) },
                { new CountryData("Colombia", "CO", 170) },
                { new CountryData("Comoros", "KM", 174) },
                { new CountryData("Congo", "CG", 178) },
                { new CountryData("Congo, the Democratic Republic of the", "CD", 180) },
                { new CountryData("Cook Islands", "CK", 184) },
                { new CountryData("Costa Rica", "CR", 188) },
                { new CountryData("C“te d'Ivoire", "CI", 384) },
                { new CountryData("Croatia", "HR", 191) },
                { new CountryData("Cuba", "CU", 192) },
                { new CountryData("Cura‡ao", "CW", 531) },
                { new CountryData("Cyprus", "CY", 196) },
                { new CountryData("Czech Republic", "CZ", 203) },
                { new CountryData("Denmark", "DK", 208) },
                { new CountryData("Djibouti", "DJ", 262) },
                { new CountryData("Dominica", "DM", 212) },
                { new CountryData("Dominican Republic", "DO", 214) },
                { new CountryData("Ecuador", "EC", 218) },
                { new CountryData("Egypt", "EG", 818) },
                { new CountryData("El Salvador", "SV", 222) },
                { new CountryData("Equatorial Guinea", "GQ", 226) },
                { new CountryData("Eritrea", "ER", 232) },
                { new CountryData("Estonia", "EE", 233) },
                { new CountryData("Ethiopia", "ET", 231) },
                { new CountryData("Falkland Islands (Malvinas)", "FK", 238) },
                { new CountryData("Faroe Islands", "FO", 234) },
                { new CountryData("Fiji", "FJ", 242) },
                { new CountryData("Finland", "FI", 246) },
                { new CountryData("France", "FR", 250) },
                { new CountryData("French Guiana", "GF", 254) },
                { new CountryData("French Polynesia", "PF", 258) },
                { new CountryData("French Southern Territories", "TF", 260) },
                { new CountryData("Gabon", "GA", 266) },
                { new CountryData("Gambia", "GM", 270) },
                { new CountryData("Georgia", "GE", 268) },
                { new CountryData("Germany", "DE", 276) },
                { new CountryData("Ghana", "GH", 288) },
                { new CountryData("Gibraltar", "GI", 292) },
                { new CountryData("Greece", "GR", 300) },
                { new CountryData("Greenland", "GL", 304) },
                { new CountryData("Grenada", "GD", 308) },
                { new CountryData("Guadeloupe", "GP", 312) },
                { new CountryData("Guam", "GU", 316) },
                { new CountryData("Guatemala", "GT", 320) },
                { new CountryData("Guernsey", "GG", 831) },
                { new CountryData("Guinea", "GN", 324) },
                { new CountryData("Guinea-Bissau", "GW", 624) },
                { new CountryData("Guyana", "GY", 328) },
                { new CountryData("Haiti", "HT", 332) },
                { new CountryData("Heard Island and McDonald Islands", "HM", 334) },
                { new CountryData("Holy See (Vatican City State)", "VA", 336) },
                { new CountryData("Honduras", "HN", 340) },
                { new CountryData("Hong Kong", "HK", 344) },
                { new CountryData("Hungary", "HU", 348) },
                { new CountryData("Iceland", "IS", 352) },
                { new CountryData("India", "IN", 356) },
                { new CountryData("Indonesia", "ID", 360) },
                { new CountryData("Iran, Islamic Republic of", "IR", 364) },
                { new CountryData("Iraq", "IQ", 368) },
                { new CountryData("Ireland", "IE", 372) },
                { new CountryData("Isle of Man", "IM", 833) },
                { new CountryData("Israel", "IL", 376) },
                { new CountryData("Italy", "IT", 380) },
                { new CountryData("Jamaica", "JM", 388) },
                { new CountryData("Japan", "JP", 392) },
                { new CountryData("Jersey", "JE", 832) },
                { new CountryData("Jordan", "JO", 400) },
                { new CountryData("Kazakhstan", "KZ", 398) },
                { new CountryData("Kenya", "KE", 404) },
                { new CountryData("Kiribati", "KI", 296) },
                { new CountryData("Korea, Democratic People's Republic of", "KP", 408) },
                { new CountryData("Korea, Republic of", "KR", 410) },
                { new CountryData("Kuwait", "KW", 414) },
                { new CountryData("Kyrgyzstan", "KG", 417) },
                { new CountryData("Lao People's Democratic Republic", "LA", 418) },
                { new CountryData("Latvia", "LV", 428) },
                { new CountryData("Lebanon", "LB", 422) },
                { new CountryData("Lesotho", "LS", 426) },
                { new CountryData("Liberia", "LR", 430) },
                { new CountryData("Libya", "LY", 434) },
                { new CountryData("Liechtenstein", "LI", 438) },
                { new CountryData("Lithuania", "LT", 440) },
                { new CountryData("Luxembourg", "LU", 442) },
                { new CountryData("Macao", "MO", 446) },
                { new CountryData("Macedonia, the former Yugoslav Republic of", "MK", 807) },
                { new CountryData("Madagascar", "MG", 450) },
                { new CountryData("Malawi", "MW", 454) },
                { new CountryData("Malaysia", "MY", 458) },
                { new CountryData("Maldives", "MV", 462) },
                { new CountryData("Mali", "ML", 466) },
                { new CountryData("Malta", "MT", 470) },
                { new CountryData("Marshall Islands", "MH", 584) },
                { new CountryData("Martinique", "MQ", 474) },
                { new CountryData("Mauritania", "MR", 478) },
                { new CountryData("Mauritius", "MU", 480) },
                { new CountryData("Mayotte", "YT", 175) },
                { new CountryData("Mexico", "MX", 484) },
                { new CountryData("Micronesia, Federated States of", "FM", 583) },
                { new CountryData("Moldova, Republic of", "MD", 498) },
                { new CountryData("Monaco", "MC", 492) },
                { new CountryData("Mongolia", "MN", 496) },
                { new CountryData("Montenegro", "ME", 499) },
                { new CountryData("Montserrat", "MS", 500) },
                { new CountryData("Morocco", "MA", 504) },
                { new CountryData("Mozambique", "MZ", 508) },
                { new CountryData("Myanmar", "MM", 104) },
                { new CountryData("Namibia", "NA", 516) },
                { new CountryData("Nauru", "NR", 520) },
                { new CountryData("Nepal", "NP", 524) },
                { new CountryData("Netherlands", "NL", 528) },
                { new CountryData("New Caledonia", "NC", 540) },
                { new CountryData("New Zealand", "NZ", 554) },
                { new CountryData("Nicaragua", "NI", 558) },
                { new CountryData("Niger", "NE", 562) },
                { new CountryData("Nigeria", "NG", 566) },
                { new CountryData("Niue", "NU", 570) },
                { new CountryData("Norfolk Island", "NF", 574) },
                { new CountryData("Northern Mariana Islands", "MP", 580) },
                { new CountryData("Norway", "NO", 578) },
                { new CountryData("Oman", "OM", 512) },
                { new CountryData("Pakistan", "PK", 586) },
                { new CountryData("Palau", "PW", 585) },
                { new CountryData("Palestinian Territory, Occupied", "PS", 275) },
                { new CountryData("Panama", "PA", 591) },
                { new CountryData("Papua New Guinea", "PG", 598) },
                { new CountryData("Paraguay", "PY", 600) },
                { new CountryData("Peru", "PE", 604) },
                { new CountryData("Philippines", "PH", 608) },
                { new CountryData("Pitcairn", "PN", 612) },
                { new CountryData("Poland", "PL", 616) },
                { new CountryData("Portugal", "PT", 620) },
                { new CountryData("Puerto Rico", "PR", 630) },
                { new CountryData("Qatar", "QA", 634) },
                { new CountryData("R‚union", "RE", 638) },
                { new CountryData("Romania", "RO", 642) },
                { new CountryData("Russian Federation", "RU", 643) },
                { new CountryData("Rwanda", "RW", 646) },
                { new CountryData("Saint Barth‚lemy", "BL", 652) },
                { new CountryData("Saint Helena, Ascension and Tristan da Cunha", "SH", 654) },
                { new CountryData("Saint Kitts and Nevis", "KN", 659) },
                { new CountryData("Saint Lucia", "LC", 662) },
                { new CountryData("Saint Martin (French part)", "MF", 663) },
                { new CountryData("Saint Pierre and Miquelon", "PM", 666) },
                { new CountryData("Saint Vincent and the Grenadines", "VC", 670) },
                { new CountryData("Samoa", "WS", 882) },
                { new CountryData("San Marino", "SM", 674) },
                { new CountryData("Sao Tome and Principe", "ST", 678) },
                { new CountryData("Saudi Arabia", "SA", 682) },
                { new CountryData("Senegal", "SN", 686) },
                { new CountryData("Serbia", "RS", 688) },
                { new CountryData("Seychelles", "SC", 690) },
                { new CountryData("Sierra Leone", "SL", 694) },
                { new CountryData("Singapore", "SG", 702) },
                { new CountryData("Sint Maarten (Dutch part)", "SX", 534) },
                { new CountryData("Slovakia", "SK", 703) },
                { new CountryData("Slovenia", "SI", 705) },
                { new CountryData("Solomon Islands", "SB", 90) },
                { new CountryData("Somalia", "SO", 706) },
                { new CountryData("South Africa", "ZA", 710) },
                { new CountryData("South Georgia and the South Sandwich Islands", "GS", 239) },
                { new CountryData("South Sudan", "SS", 728) },
                { new CountryData("Spain", "ES", 724) },
                { new CountryData("Sri Lanka", "LK", 144) },
                { new CountryData("Sudan", "SD", 729) },
                { new CountryData("Suriname", "SR", 740) },
                { new CountryData("Svalbard and Jan Mayen", "SJ", 744) },
                { new CountryData("Swaziland", "SZ", 748) },
                { new CountryData("Sweden", "SE", 752) },
                { new CountryData("Switzerland", "CH", 756) },
                { new CountryData("Syrian Arab Republic", "SY", 760) },
                { new CountryData("Taiwan, Province of China", "TW", 158) },
                { new CountryData("Tajikistan", "TJ", 762) },
                { new CountryData("Tanzania, United Republic of", "TZ", 834) },
                { new CountryData("Thailand", "TH", 764) },
                { new CountryData("Timor-Leste", "TL", 626) },
                { new CountryData("Togo", "TG", 768) },
                { new CountryData("Tokelau", "TK", 772) },
                { new CountryData("Tonga", "TO", 776) },
                { new CountryData("Trinidad and Tobago", "TT", 780) },
                { new CountryData("Tunisia", "TN", 788) },
                { new CountryData("Turkey", "TR", 792) },
                { new CountryData("Turkmenistan", "TM", 795) },
                { new CountryData("Turks and Caicos Islands", "TC", 796) },
                { new CountryData("Tuvalu", "TV", 798) },
                { new CountryData("Uganda", "UG", 800) },
                { new CountryData("Ukraine", "UA", 804) },
                { new CountryData("United Arab Emirates", "AE", 784) },
                { new CountryData("United Kingdom", "GB", 826) },
                { new CountryData("United States", "US", 840) },
                { new CountryData("United States Minor Outlying Islands", "UM", 581) },
                { new CountryData("Uruguay", "UY", 858) },
                { new CountryData("Uzbekistan", "UZ", 860) },
                { new CountryData("Vanuatu", "VU", 548) },
                { new CountryData("Venezuela, Bolivarian Republic of", "VE", 862) },
                { new CountryData("Viet Nam", "VN", 704) },
                { new CountryData("Virgin Islands, British", "VG", 92) },
                { new CountryData("Virgin Islands, U.S.", "VI", 850) },
                { new CountryData("Wallis and Futuna", "WF", 876) },
                { new CountryData("Western Sahara", "EH", 732) },
                { new CountryData("Yemen", "YE", 887) },
                { new CountryData("Zambia", "ZM", 894) },
                { new CountryData("Zimbabwe", "ZW", 716) }
            };
        }

        public CountryData GetCountryByNumericCode(int code)
        {
            var data = Countries.FirstOrDefault(cd => cd.NumericCode == code);

            if (data == null)
                throw new ArgumentException(string.Format("{0} is an invalid numeric countrycode!", code), "code");

            return data;
        }

        public CountryData GetCountryByNameOrCode(string nameOrTwoLetterCode)
        {
            var data = Countries.FirstOrDefault(cd => string.Equals(cd.Name, nameOrTwoLetterCode, StringComparison.InvariantCultureIgnoreCase) || string.Equals(cd.TwoLetterCode, nameOrTwoLetterCode, StringComparison.InvariantCultureIgnoreCase));

            if (data == null)
                throw new ArgumentException(string.Format("CountryData with name or two letter code {0} does not exist!", nameOrTwoLetterCode), "nameOrTwoLetterCode");

            return data;
        }
    }

Tags:

Persist Telerik RadTreeView (ASP.NET Ajax) state in cookie

door Sander 24-11-2011

Finding myself without a nice example of how to accomplish this, there was no other way of doing this myself :-)

First, we need to find out which nodes are expanded. The right time to check for this is when nodes are expanded/collapsed. So here is the client-side function:

function uxProfileTree_NodeToggle(sender, args) {
    var tree = $find("<%= uxProfileTree.ClientID %>");
    var allNodes = tree.get_allNodes();
    var nodeString = "";
    for (var i = 0; i < allNodes.length; i++) {
        var node = allNodes[i];
        var expanded = node.get_expanded();
            if (expanded) {
                nodeString = nodeString + node.get_value() + "*";
                createCookie("preofileTreeState", nodeString, 365);
        }
    }
}

This function is hooked into the OnClientCollapsed and OnClientExpanded client-side handlers of the treeview that you want to persist.

We now know what nodes are expanded so lets put the nodeString to work. In the Page_LoadComplete handler of my ASP.NET page I check for the cookie we created on the client and parse its value into an array by splitting the nodeString at the * char.

HttpCookie cookie = Request.Cookies[treeCookieName];
            try
            {
                if (cookie != null)
                {
                    string[] toggleParts = cookie.Value.Split(new[] { "*" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string part in toggleParts)
                    {
                        RadTreeNode toggledNode = uxProfileTree.FindNodeByValue(part);
 
                        toggledNode.Expanded = true;
                    }
                }
            }
            catch
            {
                // Remove the cookie if it messes up!
                Request.Cookies.Remove(treeCookieName);
            }

For every value we find in the array, we look up the corresponding node in the tree. The only thing left is setting the node’s Expanded property to true. As a failsafe, the cookie is removed if anything messes up while trying to find the matching node. This is to make sure the user isn’t stuck with a broken cookie and a tree that wont expand its nodes.

Tags:

Telerik | Development

Renaming an object in Active Directory

door Sander 28-10-2011

This took me well over an hour to figure out and even though I now know how to get around the problem, I still don’t know what’s causing it.

I have a piece of code that calls the DirectoryEntry.Rename(…) method. It does exactly what is says on the box, it renames the entry. (see here).

The first pitfall you’ll encounter is the input the method expects. The MSDN article states that it expects the new name, but that’s not how it works. You need to prefix it with CN= (or OU= in case of an Organizational Unit).

But now for the real issue.

Me method takes a SID (as string) as a parameter which is used to look up the entry like this:

   1:  using (var targetGroup = new DirectoryEntry(string.Format("{0}<SID={1}>", ConfigSettings.LdapPrefix, groupSid)))
   2:  {
   3:  }

Works great and does what needs to be done. But I also want to rename the targetGroup entry.

   1:  using (var targetGroup = new DirectoryEntry(string.Format("{0}<SID={1}>", ConfigSettings.LdapPrefix, groupSid)))
   2:  {
   3:      targetGroup.Rename(string.Format("CN={0}", newGroupName));
   4:  }
But guess what…when you call it like this, it throws a NotImplementedException

As I said, I don’t know what is causing this (bug in the framework?), but there is a way around it:

   1:  using (var targetGroup = new DirectoryEntry(string.Format("{0}<SID={1}>", ConfigSettings.LdapPrefix, groupSid)))
   2:  {
   3:      var groupDn = AdUtil.GetProperty(targetGroup, "distinguishedName");
   4:      using (var actualGroup = new DirectoryEntry(string.Format("{0}{1}", ConfigSettings.LdapPrefix, groupDn))
   5:      {
   6:          actualGroup.Rename(string.Format("CN={0}", newGroupName));
   7:      }
   8:  }

So here’s the trick, bind to the entry via its SID, then bind to it again with a new DirectoryEntry object using the distinguishedName of the previous object. It’s not pretty, but now you can rename your object without being slapped with a NotImplementedException.

Tags:

Setting up a wireless 3G connection in Windows

door Sander 5-10-2011

I found myself without Wi-Fi the other day and in need of internet access. My notebook is equipped with a wireless 3G adapter but the last time I repaved the it I forgot the little tool that comes with the 3G card to configure the connection. Still in need of a connection I assumed there had to be a native Windows way of doing things because I did install the proper drivers for the card. I had some trouble figuring out where to find the right setup wizard to set it up so here it is:

The card is a Huawei somethingsomethingcard (not sure what type it is) and I’m using a Vodafone SIMcard. I did this on the Windows 8 Dev Preview but my guess is it will work the same on a Windows 7 machine Smile

First, we need to create a new connection. I want to go online so the ‘Connect to the internet’ option is the obvious choice. The next choice in the wizard is the Dial-up connection. When you select this option, you'll need to know a few thing about the mobile network you are connecting to. For the Vodafone network these are:

  • The number that needs to be dialed for the connection.
  • A username and password.

The number in this case is *99# and the username and password are both vodafone. Please note that these settings depend on the provider you are using! I did not encounter a screen that required me to put in the APN (live.vodafone.com) but it worked even without this Smile

Put in all the settings and hit connect. It took a while before the connection started working so give it some time before hitting the ‘Skip’ button Smile

A step by step walkthrough:

1

2

3

4

5

I would normally do all these settings though the tool that comes with the notebook (Acer 3G Connection Manager) but this way there is no need for the 3G tool at all. The tool however is prone to hanging… This way: no more crashes!

Tags:

Telerik RadChart Dynamic Height

door Sander 21-7-2011

Something nice again today, one of our clients had an issue with the way a graph was showing its data. The issue is the fixed height of the radchart. At first it did have a fixed height, but that has two problems. One is displayed here on these images:

1bar_before  2bars_before

Now imagine this moving forward to about 40 to 50 bars in the graph… that was the issue reported by our client. The data wouldn’t fit inside the rectangle the graph was rendering.

 

I wanted to solve two things here:

    - The height must be dynamic (depending no how many bars are showing)

    - The bars must all have the same height to keep things uniform.

 

Since all my data is loaded at Page_Load that’s the place I’m going to address this.

I know how many bars will be rendered in advance which is the first number in my calculation. The second number I need is the amount of dead space between the edge of the chart and the area where the bars are drawn.

before_borders

 

The second number of our calculation is found using the IE ruler (Press F12, go to Tools). I measure from the topmost border of the chart to the edge of the area where the bars are drawn. I found that with my chart setup the gap is 65 pixels

 

Now for the fix. Say I have 2 bars that need rendering and I want each bar to be 25 pixels high. In the event where my data is bound to the grid I set the height to:

 

<numberOfBars (2)> * 25 + 65 = 115px

Translating that to code:

uxChart.Height = new Unit((dataItems.Count() * 25) + 65);

(dataItems is my charts datasource.)

In my case, this will give me this:

1bar_after  2bars_after

 

Of even with three bars:

3bars_after

 

The RadChart now scales correctly no matter how many bars I need to display. It will just keep on growing according to the amount of bars.

Tags:

Hidden Validator…

door Sander 20-7-2011

Working on some large complex ASP.NET thing and have a client-side validator blocking a postback but you cant see which one because it is invisible? Check… The validator that was blocking the postback was not visible, but was still enabled. 

 

Page.IsValid will obviously say false when a postback occurs and a validator is tripped. In my case the validator tripped without me knowing about it. You could call that PEBCAK but it had to be solved. Since I didn’t want to spend to much time finding the annoying validator I used trusty old LINQ to find it for me.

 

At the point Page.IsValid is checked, I wrote this line and slapped a breakpoint on it:

var annoyingValidator = Page.Validators.OfType<IValidator>().Where(v => !v.IsValid);

From there I could see the errormessages of the validators that were being tripped, Ctrl + F and hey presto. Added some code to make sure the validator is disabled at the right time and problem solved.

Tags:

Find a computer in Active Directory

door Sander 8-6-2011

I’m pretty sure this is covered in some post already on the world wide interwebs but since it took me some time to figure this one out I’m putting it up here.

 

For those of you who write code that talks to Active Directory (using the DirectorySearcher object in this case), this is a nice little detail.

 

The code I was working on validates a computername supplied by the user. Since I already had code that can find a user via their SAMAccountName, I decided to go down that same route.

 

Here is the code for a DirectorySearcher that finds users by their SAMAccountName:

var searcher = new DirectorySearcher(rootEntry)
{
    SearchScope = SearchScope.Subtree,
    Filter = string.Format("(&(sAMAccountName={0})(objectClass=user))", 
        dHelper.EscapeForLdap(sAMAccountName))
};

So my guess was:

var searcher = new DirectorySearcher(rootEntry)
{
    SearchScope = SearchScope.Subtree,
    Filter = string.Format("(&(sAMAccountName={0})(objectClass=computer))", 
        AdHelper.EscapeForLdap(computerSAMAccountName))
};

The code ran fine, but it never found any computers even though they existed in Active Directory. What’s up with that?

 

After some digging around I came across this tiny little detail using ADSI Edit:

 

adsi

 

So there is a dollar ($) sign appended there? Hmm, creating a new computer also adds the dollar sign to the end of the supplied name. Using this info I continued my search and ended up here:

 

http://msdn.microsoft.com/en-us/library/aa370254(v=vs.85).aspx

 

Aha!

 

A computer account name always has a trailing dollar sign ($). Any functions used to manage computer accounts must build the computer name such that the last character of the computer account name is a dollar sign ($). For interdomain trust, the account name is TrustingDomainName$.

 

Changing the Filter to this:

Filter = string.Format("(&(sAMAccountName={0}$)(objectClass=computer))", 
    AdHelper.EscapeForLdap(computerSAMAccountName))
Solves my filtering problem and the method is now returning the correct results.

Tags:

IE9 Jumplist

door Sander 28-3-2011

In the latest version of Internet Explorer users now have the option to pin a tab to the taskbar. It works like a favorite, but just one click away instead of having to open the browser first.

Pinning a tab is a nice feature, but they didn’t stop there, these pinned pages can also supply custom jumplists to make access to common tasks even friendlier.

To demonstrate this feature I added a jumplist to our own product Provisior Smile

 

pinnedtab3

 

Provisior uses a MasterPage to define the overall layout of the site. This is where the custom jumplist lives as well.

This is what a jumplist item looks like in the HTML source:

<meta name="msapplication-task" content="name=Mijn Info;action-uri=http://localhost/Celerior.Annapurna.UI/MyInfo.aspx;icon-uri=http://localhost/Celerior.Annapurna.UI/App_Themes/Light/Icon/myinfo.ico" />

Just another meta in the page head section, easy enough. But what about dynamic jumplist items? Here’s how I take care of that:

 

In the MasterPage codebehind I created a simple method that adds a new <meta /> to the page header. Note that the head section in the aspx needs to have the runat=”server” attribute set to programmatically manipulate the header.

private void addMeta(string name, string content)
        {
            var m = new HtmlMeta();
            m.Name = name;
            m.Content = content;
 
            Page.Header.Controls.Add(m);
        }

To add the jumplist item I can now write the following in the MasterPage Page_Load event:

addMeta("msapplication-task", "name=Mijn Info;action-uri=" + webHost + "/MyInfo.aspx;icon-uri=" + iconPath + "myinfo.ico");

The code above outputs the <meta /> in the first codesnippet.

 

In the Page_Load you can now write anything you want about when the jumplist items are shown.

 

There are some other tricks you can do like set the name of the jumplist and the size of the browser window when the site is launched from the taskbar:

<meta name="application-name" content="Provisior" />
<meta name="msapplication-window" content="width=1024;height=768" />

There is also a way to do all this in Javascript but I’ll let you discover that on your own (Here is a good start Smile)

 

To see some of these jumplists in action, try pinning Twitter or Facebook to your taskbar and right-clicking the icons.

 

Have fun!

Tags:

Development | Provisior | Internet Explorer 9

With your head in the clouds

door Sander 16-1-2011

imagesCloud, cloud cloud cloud… heard it enough? Hope not, this post is about clouds. The internet is full of cloud at the moment. Will the cloud take us all and connect us permanently to the internet? Or are we hanging on to a disconnected part of our digital lives? I took a dive in into the clouds to see where it would take me.

 

The first thing I did was install a cloud operating system. It still requires some installation, but after that, you’re floating somewhere in the clouds. This is where my first issue with the current cloud peeks around the corner. “Login or set up an account if you don’t have one” … great, more passwords to remember. Almost every cloud app I’ve used required me to set up an account. For some apps that’s not an issue as I had accounts for them already, but still, want to add an app, there is a good chance you need an account to take full advantage of the app. In some cases there is no way around it (for the OS itself for example), but for a news app that needs to display Dutch news instead of United States?

 

Accounts aside, it did all work. I had my documents (Dropbox/Skydrive), I had my music (Spotify) and my social stuff was there as well (Facebook, Twitter and Pidgin). With my Windows Live account I could access Office Live to edit my documents (part of this post was written in the cloud).

 

This is where we get to the real issue I see in the clouds. They are my files and folders on both Dropbox and Skydrive, but who’s to say they are safe and secure (this applies to all the stuff you can put in the cloud)? And what happens when my files go missing? What if I want to move all my stuff to a service that suits me better? Who can still access them after I delete my account? Privacy peeks around the corner as well, but I’ll skip that one.

 

I think the cloud is a great invention but are we heading towards an internet where everything is stashed away in a place we do not fully control? As it stands right now, I’m not ready yet to fully commit to the cloud, are you?

Tags:

Cloud | Algemeen

Telerik RadChart Pie part colors

door Sander 4-1-2011

Fun little task today of making every pie-part a different color, but still within the range of colors used in the style of our app (Provisior).

 

I was unable to find a simple example as to go about this so here is one for those in need of one. The sample code is used with a Telerik RadChart for ASP.NET AJAX.

 

The cause of the problem is the unknown number of pie-parts that the chart will render. I could just make them all the same color, but that isn’t very pretty to look at and the default color aren’t bad, but they look out of place in our app (see the Provisior website and you’ll know what I mean).

 

before

 

We use a lot of white and gray in our style sheet, but to add some life to all the white and gray, we use orange. That will be the color from which we start mixing up new colors ending with red.

 

after

 

That is looking a lot better Smile Here is how this is done:

 

// The starting point of the G value in our RGB color
int baseG = 216;
 
// The amount we change the color for each item
int stepSize = baseG / uxChart.Series[0].Items.Count;
 
// Values for the G in our RGB colors
int mainG = baseG;
int secondG = 0;
 
foreach (var item in uxChart.Series[0].Items)
{
    // Set each item to a slightly different color.
    item.Appearance.FillStyle.MainColor = 
                        Color.FromArgb(255, mainG, 0);
    item.Appearance.FillStyle.SecondColor = 
                        Color.FromArgb(255, secondG, 0);
 
    mainG = mainG - stepSize; // Lower the main G value
    secondG = secondG + stepSize; // Raise the secondary G value
 
    // Don't let the colors error out due to an invalid value.
    if (mainG <= 0)
    {
        mainG = 0;
    }
 
    if (secondG >= 255)
    {
        secondG = 255;
    }

}

 

This code is executed right after the RadChart is databound using the .DataBind() method.

 

This is not perfect though, as you can see in the picture below. Having many parts in the Pie makes the changes to the colors very small which turns the Pie into one big gradient. The lines separating the parts add enough detail for me, so I’m fine with that.

 

lots

 

So there you go Smile

Tags:

Development | Telerik