Wednesday 3 August 2011

OptGroup with asp:Dropdownlist

Most are aware that the out of the box DropdownList that comes with asp.NET doesnt allow for OptGroups. These are quite handy when it comes to structuring the layout.

One way around this is to use jQuery to insert the items required to make optgroup work.

Define your asp:DropdownList, remember to set the cssclass attribute as this makes it easier to find.

In this case I had a dropdown with the css class of eventDropDown attached.

In the data returned to the Dropdown I make sure 2 extra rows are added to separate the 2 sets of options, in this case one is PE and one is OE.

initially the data is bound with the separators (slightly edited)
<select>
<option>PE</option>
<option>ONE</option>
<option>OE</option>
<option>TWO</option>
</select>

using the :contains selector that comes with the standard jQuery libraray I was able to find the option of PE and OE to be replaced with my optgroup choices.
I have made the assumption that if PE exists, then so does OE. Makes life a bit easier.

<script type="text/ecmascript">
var item = $('.eventDropDown option:contains("PE")');
if (item != null) {
item.replaceWith("<optGroup label='Preferred Events' />");
item = $('.eventDropDown option:contains("OE")');
item.replaceWith("<optGroup label='Other Events' />");
}
</script>

I'm not sure on the accessibility level of what I am doing, but visually this will work for most cases where you want this to happen.

If you do want proper option groups do your site in MVC and make your own custom control, its fun. this is a way out for a control in ASP.NET.

Friday 15 July 2011

Using LinQ on a DataSet

This is quite straightforward:

Apply the AsEnumerable() extension to your DataTable, allowing you to select the data you want and return it as a collection. By using the extension AsDataView(), the collection is then returned as a friendly DataView object:

for example:
var dv = (from dr in ds.Tables[0].AsEnumerable()
where dr[0] == x
select dr).AsDataView();


Tuesday 31 May 2011

Grouping with LinQ

Using LinQ to group a set of data by something is quite straightforward.

In the example below I am returning a list of bookings, which is very flat. I wanted to group the data returned by the BookingID

Using group on BookingID, I am able to rearrange the data to "group" sets of data that relate to a specific booking. Brilliant!

var bkgs = dal.GetBookings();

var distinctbkgs = (from x in bkgs
group x by x.BookingID into xx
select new
{
Booking = xx.First(),
RelatedBookings = xx.ToList()
}).ToList();

Monday 7 March 2011

left join with LinQ comprehension syntax

I was trying to find a way to perform a left join on 2 comparable sets of data using LinQ, but the join keyword only appears to perform an inner join (unless I missed something).

By performing a LinQ statement for the Del entry at the point I create the anonymous type, the following output would act like a left join (returning a null for the Del value when there is no match).

I then go on to select all the null entries using the extension methods and call a delete routine for each entry found.

(from x in Entries
where x.Information["Information3"] == Session["GINumber"].ToString()
select new
{
Pre = x,
Del = (from y in _delegates
where y.EmailAddress == x.Information["Information1"]
select y.EmailAddress).SingleOrDefault()
}).Where(x => x.Del == null).ToList().ForEach(x => Service.DeleteEntry(x.Pre.InformationID));


As an aside I found out that the term for the “from” “in” style of LinQ is called “Query Comprehension Syntax”.

Tuesday 8 February 2011

Disable asp.net button

adding the following in the page load event in your ASP.NET page. This will setup the ability to disable the button you click, until the submission is complete or an error occurs.

MyButton.Attributes.Add("onclick", "this.disabled=true;" + Page.ClientScript.GetPostBackEventReference(MyButton, "").ToString());

Monday 17 January 2011

Split String To Dictionary

I have created a Survey System, which allows an admin to set the questions.

One question type is a dropdownlist and the information needed (to keep it simple) was stored as a semi-colon separated list (I also extended this to allow colon separated values within that to allow key and value sets).

for example:
spring;summer;autumn;winter
or
0:spring;1:summer;2:autumn;3:winter

Both are valid and the second example will store the values defined as the answer.

I wanted to split a string into a Dictionary and set a return for use on an MVC SelectList,

I refactored out the SplitAndReturnIndex to handle case where the string does not contain a Key, only a value, as can be seen from the code:


public IDictionary QuestionValues()
{
return Question.SurveyItemValues.Split(';')
.Select(x => new { Key = SplitAndReturnIndex(x, 0), Value = SplitAndReturnIndex(x, 1) })
.ToDictionary(x => x.Key, x => x.Value);
}

private string SplitAndReturnIndex(string x, int indexValue)
{
return x.IndexOf(':') == -1 ? x : x.Split(':')[indexValue];
}

Tuesday 4 January 2011

Hash Password using HMACSHA1 or HMACSHA512

Quite a handy snippet to generate an HMACSHA1 encoded string, I use this for passwords, but it could be used generate a check sum when passing values through to a webservice.

public static string GeneratePassword(string valueToHash)
{
byte[] saltValueBytes = Encoding.ASCII.GetBytes("This is for the Salt");
// Change passkey value to known value, I tend to use a guid
Rfc2898DeriveBytes passwordKey = new Rfc2898DeriveBytes("96D9E8D3-1318-4291-B459-84EAB0E268A6", saltValueBytes);
byte[] secretKey = passwordKey.GetBytes(16);
HMACSHA1 myHash = new HMACSHA1(secretKey);
byte[] encodedValue = Encoding.UTF8.GetBytes(valueToHash);

return Convert.ToBase64String(myHash.ComputeHash(encodedValue));
}


The problem with this, has always been everyone has the same salt.

So a change in security and use of SHA512:

With a way to generate a unique Salt:


public byte[] GenerateSalt()
        {
            System.Security.Cryptography.RNGCryptoServiceProvider r = new System.Security.Cryptography.RNGCryptoServiceProvider();

            byte[] array = new byte[16];

            r.GetBytes(array);

            return array;
        }

And return the Hash value with Generated Salt Passed in:

        public string GetHash(string password, byte[] salt)
        {
            string ret = string.Empty;

            try
            {
                byte[] passwordBytes = Encoding.ASCII.GetBytes(password);

                byte[] input = new byte[salt.Length + passwordBytes.Length];

                salt.CopyTo(input, 0);

                passwordBytes.CopyTo(input, salt.Length);

                System.Security.Cryptography.SHA512CryptoServiceProvider cr = new System.Security.Cryptography.SHA512CryptoServiceProvider();

                ret = Convert.ToBase64String(cr.ComputeHash(input));
            }
            catch (Exception Ex)
            {
                throw new Exception("Error hashing password", Ex);
            }

            return ret;
        }

Remember to save the salt somewhere that can be referrenced with the encrypted value, so you can check it.