Sunday, December 21, 2014

Lenovo Yoga 13 and Screen Brightness On Fedora 21

Just upgraded to Fedora 21 and the screen brightness controls do not work in Gnome.

Before Fedora 21 I had modified the following variable GRUB_CMDLINE_LINUX in the default grub file: /etc/default/grub in order to append `acpi_backlight=vendor`

#emacs /etc/default/grub

GRUB_CMDLINE_LINUX="...existing vars here... acpi_backlight=vendor"

After the upgrade I had to change this from acpi_backlight=vendor to acpi_backlight=intel. Once the file is updated run:

#grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

Once done, reboot and the screen brightness controls should work however the screen brightness range goes from 0 to 4882 (/sys/class/backlight/intel_backlight/max_brightness) instead of around 100 to 4882 so if you dim the brightness all the way down, your screen will be completely black.

Friday, October 3, 2014

Understanding DB2 OLAP By Example

The OLAP features in DB2 are very cool however I don't see a lot of people using them. In addition, sometimes reading the docs on these features are overwhelming so hopefully these examples will make it easy to understand.

We'll look at the following OLAP features in particular. There are more available if you navigate to the IBM website for your DB2 version.
 First we need to create a sample table and data:

CREATE TABLE sales(
     item VARCHAR(20), 
     state CHAR(2),
     store VARCHAR(20),
     amount DECIMAL);

Then lets insert some sample data:

INSERT INTO sales VALUES('Watch', 'IL', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'MN', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Buymore', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Buymore', 15);

INSERT INTO sales VALUES('Phone', 'MN', 'Buymore', 150);
INSERT INTO sales VALUES('Phone', 'IL', 'Buymore', 150);
INSERT INTO sales VALUES('Phone', 'NY', 'Buymore', 150);
INSERT INTO sales VALUES('Phone', 'NY', 'Buymore', 150);
INSERT INTO sales VALUES('Phone', 'NY', 'Buymore', 150);
INSERT INTO sales VALUES('Phone', 'MN', 'Buymore', 150);

INSERT INTO sales VALUES('Watch', 'NY', 'Amazing', 15);
INSERT INTO sales VALUES('Watch', 'IL', 'Amazing', 15);
INSERT INTO sales VALUES('Watch', 'NY', 'Amazing', 15);

INSERT INTO sales VALUES('Phone', 'MN', 'Amazing', 150);
INSERT INTO sales VALUES('Phone', 'NY', 'Amazing', 150);
INSERT INTO sales VALUES('Phone', 'MN', 'Amazing', 150);

Now lets look at the result of a common group by clause:
SELECT 
     store,
     SUM(amount)
FROM
     sales
GROUP BY
     store
STORE                                     TOTAL_SALES 
-------------------- --------------------------------- 
Buymore                                           1020 
Amazing                                            495
As we can see the group by clause took the sum of sales by store. Now lets look at the sum of sales by state using a group by store and state.

SELECT 
     store,
     state,
     SUM(amount) AS total_sales
FROM
     sales
GROUP BY
     store,
     state
STORE                ST                       TOTAL_SALES 
-------------------- -- --------------------------------- 
Amazing              MN                               300 
Buymore              NY                               525 
Buymore              IL                               165 
Amazing              IL                                15 
Amazing              NY                               180 
Buymore              MN                               330 

These are some pretty common group by scenarios but what if you needed a grouping by store and state, and also to display the total sales for each store, as well as for all stores. Here is where rollup comes into play.

Rollup

Rollup is similar to a group by clause except that it also outputs running totals for your rollup groups.
SELECT 
     store,
     state,
     SUM(amount) AS total_sales
FROM
     sales
GROUP BY
     ROLLUP(store, state)
STORE                ST           TOTAL_SALES 
-------------------- -- ---------------------- 
Amazing              IL                     15 
Amazing              MN                    300 
Amazing              NY                    180 
Amazing                                    495 <-Total Amazing
Buymore              IL                    165 
Buymore              MN                    330 
Buymore              NY                    525 
Buymore                                    1020 <-Total Buymore
                                           1515 <-Total

You could also swap the rollup fields and rollup on state and then store:

SELECT 
     store,
     state,
     SUM(amount) AS total_sales
FROM
     sales
GROUP BY 
     ROLLUP(state,store)
 STORE               ST                       TOTAL_SALES 
-------------------- -- --------------------------------- 
Amazing              IL                                15 
Buymore              IL                               165 
                     IL                               180
Amazing              MN                               300 
Buymore              MN                               330 
                     MN                               630
Amazing              NY                               180 
Buymore              NY                               525 
                     NY                               705
                                                     1515

Cube

The cube feature is similar to the rollup feature except it aggregates the data into all combinations in your cube clause. For example this will list the total sales by all combinations of store and state:
  • Store per State Total
  • Store Total
  • State Total
SELECT 
     store,
     state,
     SUM(amount) AS total_sales
FROM
     sales
GROUP BY 
     CUBE(store, state)
STORE            ST       TOTAL_SALES 
---------------- -- ----------------- 
Amazing          CT                15 
Amazing          IL                15 
Amazing          MD                 5 
Amazing          MN               300 
Amazing          NY               180 
Amazing                           515 <-Total Amazing
Buymore          IL               165 
Buymore          MN               315 
Buymore          NY               525 
Buymore                          1005 <-Total Buymore  
                                 1520 <-Grand Total    
                 MD                 5 <-Total by states
                 IL               180                  
                 MN               615                  
                 CT                15                  
                 NY               705                       

Grouping Set

You can also do aggregates based off grouping sets. For example this will list the total sales by store and item, as well as state and item.
SELECT 
     store,
     state,
     item,
     SUM(amount) AS total_sales
FROM
     sales
GROUP BY 
     GROUPING SETS((store, item), (state, item));
STORE                ST ITEM                 TOTAL_SALES 
-------------------- -- ----------- -------------------- 
Buymore                 Watch                        105 
Amazing                 Watch                         60 
Buymore                 Phone                        900 
Amazing                 Phone                        450 
Amazing                 Pen                            5 
                     MD Pen                            5 
                     NY Phone                        600 
                     CT Watch                         15 
                     IL Watch                         30 
                     MN Watch                         15 
                     MN Phone                        600 
                     IL Phone                        150 
                     NY Watch                        105 

Rank

Now lets say you want to rank/order the stores by state of most sales. Here is where the rank function comes into play:
SELECT 
     store,
     state,
     SUM(amount) AS total_sales,
     RANK() OVER (PARTITION BY store ORDER BY SUM(amount) DESC) AS rank
FROM
     sales
GROUP BY 
     state,
     store;
STORE        ST TOTAL_SALES    RANK 
------------ -- -------------- ----- 
Amazing      MN 300            1 <-Highest sale state for Amazing
Amazing      NY 180            2 
Amazing      IL  15            3 
Buymore      NY 525            1 <-Highest sale state for Buymore
Buymore      MN 330            2 
Buymore      IL 165            3 
Rank basically gives an ordering to your results based on how you want that ordering to work. "Partition by store" means your ordering is specific to each store. "order by sum(amount) desc" means for each store, order the results by the highest sales in descending order.

Please note that if two rows tie for a ranking, the ranking number will not increment on the tied row.

Dense Rank

There is also a slightly different rank type; dense rank that differs from rank in how subsequent rows after a tie will increment.

To demonstrate, lets add a new state, CT that ties with IL for Amazing sales. Lets also add another state with lower sales than CT and IL.
INSERT INTO sales VALUES('Watch', 'CT', 'Amazing', 15);
INSERT INTO sales VALUES('Pen', 'MD', 'Amazing', 5);
 
SELECT 
     store,
     state,
     SUM(amount) AS total_sales,
     DENSE_RANK() OVER (PARTITION BY store ORDER BY SUM(amount) DESC) AS dense_rank,
     RANK() OVER (PARTITION BY store ORDER BY SUM(amount) DESC) AS rank
FROM
     sales
GROUP BY 
     state,
     store;
STORE                ST      TOTAL_SALES        DENSE_RANK                 RANK 
-------------------- -- ---------------- ----------------- -------------------- 
Amazing              MN              300                 1                    1 
Amazing              NY              180                 2                    2 
Amazing              CT               15                 3                    3
Amazing              IL               15                 3                    3 
Amazing              MD                5                 4                    5
Buymore              NY              525                 1                    1 
Buymore              MN              315                 2                    2 
Buymore              IL              165                 3                    3 
In this example, after a tie ranking (ranking #3), rank skipped over ranking #4 and went straight to 5 while dense rank incremented one count to 4. Rank is nice if you need a total count of items in the rank.

Row Number

Row number is similar to rank however instead of ranking the row, just gives the row a number starting at 1 and incrementing by 1. In the following example, we assign a row number to each row and partition the row number by store. This basically means that each store will have a row number assigned starting at 1.
SELECT 
     store,
     state,
     SUM(amount) AS total_sales,
     ROW_NUMBER() OVER (PARTITION BY store) AS row_number
FROM
     sales
GROUP BY 
     state,
     store;
STORE                ST      TOTAL_SALES       ROW_NUMBER
-------------------- -- ---------------- ----------------- 
Buymore              NY              525                 1 
Buymore              IL              165                 2 
Buymore              MN              315                 3 
Amazing              MN              300                 1 
Amazing              CT               15                 2
Amazing              NY              180                 3 
Amazing              IL               15                 4
Amazing              MD                5                 5

Friday, September 26, 2014

Disabling the Lenovo Yoga Touchpad and Keyboard In Fedora

I can't find an easy way to disable the mouse and keyboard on screen flip of the Yoga in Fedora however an easy enough approach is to disable them by hand using xinput.

Issue an: xinput --list

[richie@localhost ~]$ xinput --list
⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ Logitech Unifying Device. Wireless PID:1028       id=9    [slave  pointer  (2)]
⎜   ↳ ELAN Touchscreen                          id=10   [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=14   [slave  pointer  (2)]
⎜   ↳ Microsoft Natural® Ergonomic Keyboard 4000        id=15   [slave  pointer  (2)]
⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Power Button                              id=8    [slave  keyboard (3)]
    ↳ Lenovo EasyCamera                         id=11   [slave  keyboard (3)]
    ↳ Ideapad extra buttons                     id=12   [slave  keyboard (3)]
    ↳ Microsoft Natural® Ergonomic Keyboard 4000        id=16   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=13   [slave  keyboard (3)]
Then look for the id of the mouse and touchpad. Mine are 13 and 14.

With the id's you can then create a simple bash script. The simplest would be to create a file; disable_keyboard_mouse.sh, with the following contents:
#!/bin/bash
xinput set-int-prop 13 "Device Enabled" 8 $1
xinput set-int-prop 14 "Device Enabled" 8 $1
Then issue 'chmod +x disable_keyboard_mouse.sh' and call it with ./disable_keyboard_mouse 0 or ./disable_keyboard_mouse 1 with 1 turning the keyboard and mouse on and 0 turning it off.

Friday, May 2, 2014

MythTV transcoding user job

For some reason I was having trouble with existing online MythTV transcoding jobs. Specifically this and MythBrake were nice but after many attempts I couldn't get HandbrakeCLI to output a decent quality video and opted to write my own using ffmpeg.

Please be aware this script will automatically cut out commercials even if mythcommflag is inaccurate.

To get started copy the script into a file on your mythbackend box. In the example below it is called transcode.sh. Then `chmod +x` and review the contents of the `./transcode.sh -h` help command like so:

[richie@localhost mythtv]$ chmod +x transcode.sh
[richie@localhost mythtv]$ ./transcode.sh -h
Transcodes a video to .mkv auto cutting commercials.
User job example: /home/richie/mythtv/transcode.sh -c %CHANID% -s %STARTTIMEUTC%

-v         show version
-h         show usage
-l         limit CPU usage
-s [arg]   starttime from mythtv. In user job %STARTTIMEUTC%
-c [arg]   chanid from mythtv. In user job %CHANID%
-u [arg]   MySql username
-p [arg]   MySql password
-o [arg]   output Directory
-t [arg]   temp Directory
-r [arg]   ffmpeg crf. See: https://trac.ffmpeg.org/wiki/Encode/H.264
-z [arg]   ffmpeg preset. See: https://trac.ffmpeg.org/wiki/Encode/H.264

Here is the script:

#!/bin/bash
# ------------------------------------------------------------------                                                      
# [Author] Richard Kanavati                                                                                               
#          A simple MythTV script to transcode video to mkv                                                               
# ------------------------------------------------------------------                                                      

# ---------User Variable Defaults-----------------------------------                                                      
# For simplicity in configuring a MythTV user job, default command                                                        
# line parameters can be specified here.                                                                                  
# These will be overridden if you supply command line parameters.                                                          
db_user="mythtv"
db_password="mythtv"
output_dir="~/"
temp_dir="/tmp"
mythtranscode_options="--mpeg2 --honorcutlist"
ffmpeg_crf=23
ffmpeg_preset="slow"
limit_cpu=1
# ------------------------------------------------------------------                                                      

set -e
trap 'exit_handler' EXIT

exit_handler()
{
    if [ -e "$temp_transcoding_file" ]; then
        rm "$temp_transcoding_file"
    fi

    if [ -e "$temp_transcoding_file.map" ]; then
        rm "$temp_transcoding_file.map"
    fi
}

display_usage() {
    local directory="$(cd "$(dirname "${0}")"; echo $(pwd))"
    local file="${directory}/$(basename "${0}")"

    echo "Transcodes a video to .mkv auto cutting commercials."
    echo "User job example: $file -c %CHANID% -s %STARTTIMEUTC%"
    echo ""
    echo "-v         show version"
    echo "-h         show usage"
    echo "-l         limit CPU usage"
    echo "-s [arg]   starttime from mythtv. In user job %STARTTIMEUTC%"
    echo "-c [arg]   chanid from mythtv. In user job %CHANID%"
    echo "-u [arg]   MySql username"
    echo "-p [arg]   MySql password"
    echo "-o [arg]   output Directory"
    echo "-t [arg]   temp Directory"
    echo "-r [arg]   ffmpeg crf. See: https://trac.ffmpeg.org/wiki/Encode/H.264"
    echo "-z [arg]   ffmpeg preset. See: https://trac.ffmpeg.org/wiki/Encode/H.264"
}

if [ $# == 0 ] ; then
    display_usage
fi

while getopts ":s:c:u:p:o:t:r:z:vhl" optname
  do
    case "$optname" in
     v)
        echo "Version $VERSION"
        exit 0;;
      c)
        chanid=${OPTARG};;
      s)
        starttime=${OPTARG};;    
      l)
        limit_cpu=1;;
      m)
        db_user=${OPTARG};;
      p)
        db_password=${OPTARG};;
      o)
        output_dir=${OPTARG};;
      t)
        temp_dir=${OPTARG};;
      r)
        ffmpeg_crf=${OPTARG};;
      z)
        ffmpeg_preset=${OPTARG};;
      h)
        display_usage;
        exit 0;;
    esac
  done

if [ -z "$chanid" ] || [ -z "$starttime" ]; then
  echo
  echo "Must supply -c and -s parameters!";
  echo
  display_usage
  exit 1
fi

if [ "$limit_cpu" -eq 1 ]; then
    renice 19 $$
    ionice -c 3 -p $$
fi

sql="                                                                                                                     
SELECT                                                                                                                    
    s.dirname as storagegroup,                                                                                            
    r.basename,                                                                                                           
    r.commflagged,                                                                                                        
    CONCAT(r.title,' ', CASE                                                                                              
                         WHEN r.season > 0                                                                                
                         THEN concat('s', lpad(r.season,2,0), 'e', lpad(r.episode,2,0), ' ')                              
                         ELSE ''                                                                                          
                        END, r.subtitle) AS title                                                                         
FROM                                                                                                                      
    recorded r                                                                                                            
    JOIN storagegroup s                                                                                                   
       ON s.groupname = r.storagegroup                                                                                    
WHERE                                                                                                                     
   r.chanid = '$chanid'                                                                                                   
   and r.starttime='$starttime'                                                                                           
LIMIT 1;                                                                                                                  
"

query_results=$(mysql -u"$db_user" -p"$db_password" -Dmythconverg -NBse  "$sql")
if [ ! "$query_results" ]; then
    echo "Could not locate video in the mythtv database."
    exit 1
fi

storage_group=$(echo "$query_results"|cut -f1)
if [ ! "$storage_group" ]; then
    echo "Could not locate storage group in the mythtv database."
    exit 1
fi

basename=$(echo "$query_results"|cut -f2)
commflagged=$(echo "$query_results"|cut -f3)
title=$(echo "$query_results"|cut -f4|sed 's/ *$//'|sed "s/[:?]/ /g"|sed "s/[.]//g")
if [ ! "$title" ]; then
    title="unknown_title_${starttime}"
fi

transcoding_file="$storage_group$basename"
temp_transcoding_file="$temp_dir/${chanid}_$starttime.mpg"
output_file="$output_dir/$title.mkv"
if [ -e "$output_file" ]; then
   output_file="$output_dir/${title}_$starttime.mkv"
fi

if [ $commflagged -eq 0 ]; then
    /usr/bin/mythcommflag --chanid "$chanid" --starttime "$starttime"
fi

/usr/bin/mythutil --chanid "$chanid" --starttime "$starttime" --gencutlist
/usr/bin/mythtranscode --chanid "$chanid" --starttime "$starttime" --allkeys --buildindex --mpeg2 --showprogress
/usr/bin/mythtranscode --chanid "$chanid" --starttime "$starttime" $mythtranscode_options -o "$temp_transcoding_file"
/usr/bin/mythcommflag --file "$temp_transcoding_file" --rebuild
/usr/bin/ffmpeg -i "$temp_transcoding_file" -c:v libx264 -preset "$ffmpeg_preset" -crf "$ffmpeg_crf" -c:a copy "$output_file"

Tuesday, April 29, 2014

.Net Listing Classes or Methods With A Particular Attribute.

Whenever I build a website I always like to build an admin section and expose information such as which actions are cached, which controllers require authorization and which fields are required etc. Luckily in .Net MVC most of these things are implemented as attributes.

Here is an example of scanning an assembly and listing all the classes and methods with a particular attribute on them. I chose two random attributes for this example:

[Obsolete]
public class Program
{
    public static void Main(string[] args)
    {
        var program = new Program();
        var types = program.GetAttributesOnClasses();
        foreach (var t in types)
        {
            Console.WriteLine("Class: {0}  - Attribute: {1}", t.Type.Name, t.Attributes);
        }

        var methods = program.GetAttributesOnMethods();
        foreach (var method in methods)
        {
            Console.WriteLine("Method Name: {0} -  Attribute: {1}", method.MethodInfo.Name, method.Attributes);
        }

        Console.ReadLine();
    }
  
    public IEnumerable GetAttributesOnClasses<T>() where T : Attribute
    {
        return new AttributeScan().GetTypesWith<T>(new[] { Assembly.GetExecutingAssembly() }, false);
    }

    public IEnumerable<methodattributeinfo> GetAttributesOnMethods<T>() where T : Attribute
    {
        return new AttributeScan().GetMethodsWith<T>(new[] { Assembly.GetExecutingAssembly() }, false);
    }

    [STAThread]    
    public void DoNothing()
    {          
    }

    [STAThread]
    private void PrivateDoNothing()
    {
    }

}
Will output:

Class: Program  - Attribute: System.ObsoleteAttribute[]
Method Name: DoNothing -  Attribute: System.STAThreadAttribute[]

Note that the scan did not take into account the private method.

Friday, April 25, 2014

Why don't more people use the .Net Settings as opposed to Config settings.

I see a lot of people putting key-value pairs in web.config/app.config files and then using them in their applications via
var someConfigKey = ConfigurationManager.AppSettings["someConfigKey"];
int count;
if (int.TryParse(someConfigKey, out count))
{
    //// Do Something
}

However I rarely see people using application settings. I won't go into depth on what application settings are as the Microsoft website has a pretty good explanation of them here however Settings are strongly typed and so the above lines of code can all be replaced with:
var count = Properties.Settings.Default.Count;

I might be missing something here but it seems like the latter is much more convenient to use if you are simply using the appSettings section of the .config file. Of course it is a different story if you are using .config sections which are serialized into objects but for the most part what I can figure is that many people don't know about .net Settings.

Take this or this stackoverflow post which add to the confusion and were found on the first page of googling for the difference between settings and config files.

As a side note, if you do choose to use .Net Settings instead of a .Config file and you wanted to list your settings on some admin section of a webpage you could do something like so:
public Dictionary GetSettings()
{
  return Properties.Settings.Default.Properties.Cast<SettingsProperty>()
    .ToDictionary(property => property.Name, property => Properties.Settings.Default[property.Name].ToString());
}

Friday, April 11, 2014

VB.Net Gotchas

VB.NET is a very user friendly language however I find its user friendliness to be quite confusing and error prone, especially when switching back and forth between C# and VB. Simple things like VB's handling of null or concatenation can lead to bugs if your not careful. For example:
 
   Sub Main()

        Console.WriteLine("The value of Nothing is also the value of the default type: " &
                         (Nothing = False))

        Console.WriteLine("The value of Nothing is also the value of the default type: " &
                          (Nothing = 0))

        Console.WriteLine("The value of Nothing is also the value of the default type: " &
                          (Nothing = String.Empty))

        Console.WriteLine("The & operator with two integers concats both: " & (3 & 4))

        Console.WriteLine("The + operator with two integers adds both: " & (3 + 4))

        Console.WriteLine("The + operator with two strings concats both: " & ("3" + "4"))

        Console.WriteLine("The & operator with a string and an integer concats both: " & 
                          ("3" & 4))

        Console.WriteLine("The + operator with a string and an integer adds both: " & 
                          ("3" + 4))

        Console.WriteLine("The + operator with an integer and string adds both: " & 
                          (4 + "3"))
        
        Console.WriteLine("The Length of a VB.NET array starts at 1 and not 0: " &
                          {"Dot", "Net", "Perls"}.Length)

        'Console.WriteLine("DirectCast can NOT convert types that are not inherited: " & 
        '               DirectCast(0, System.String))
        'System.IndexOutOfRangeException' 

        Console.WriteLine("CType can convert types that are not inherited: " &
                       CType(0, System.String))

        'Console.WriteLine("Nothing <> String: " & (Nothing = String.Empty))
        'System.IndexOutOfRangeException' 

        Console.WriteLine("Nothing is not string.Empty: " & (Nothing IsNot String.Empty))

        'Console.WriteLine("And operator always evaluates all conditions: " & 
        '                 (1 = 2 And 0 = String.Empty))
        'System.InvalidCastException

        Console.WriteLine("AndAlso operator evaluates left to right conditions as needed: " &
                          (1 = 2 AndAlso 0 = String.Empty))

        Console.WriteLine("The value of TestFunctionExitWithType is going to be the default" &
                          " return type: " & TestFunctionExitWithType())

        Console.WriteLine("The value of TestFunctionReturn is going to be Nothing: " &
                          TestFunctionReturn())

        Console.WriteLine("The value of TestFunctionExit is going to be Nothing: " &
                          TestFunctionExit())

        Console.WriteLine("Parenthesis are optional in Paremeterless methods: " & 
                          0.ToString)

        Console.ReadLine()

    End Sub

    Sub TestSubReturn()
        Return
    End Sub

    Sub TestSubExit()
        Exit Sub
    End Sub

    Function TestFunctionReturn()
        Return Nothing
    End Function

    'Compiler error: 'Return' statement in a Function, Get, or Operator must return a value.
    'Function TestFunctionReturn()
    '    Return
    'End Function

    Function TestFunctionExit()
        Exit Function
    End Function

    Function TestFunctionExitWithType() As Decimal
        Exit Function
    End Function

End Sub
Results:
The value of Nothing is also the value of the default type: True
The value of Nothing is also the value of the default type: True
The value of Nothing is also the value of the default type: True
The & operator with two integers concats both: 34
The + operator with two integers adds both: 7
The + operator with two strings concats both: 34
The & operator with a string and an integer concats both: 34
The + operator with a string and an integer adds both: 7
The + operator with an integer and string adds both: 7
The Length of a VB.NET array starts at 1 and not 0: 3
CType can convert types that are not inherited: 0
Nothing is not string.Empty: True
AndAlso operator evaluates left to right conditions as needed: False
The value of TestFunctionExitWithType is going to be the default return type: 0
The value of TestFunctionReturn is going to be Nothing: 
The value of TestFunctionExit is going to be Nothing: 
Parenthesis are optional in Paremeterless methods: 0

Monday, February 10, 2014

.Net Winforms Basic BackgroundWorker Example

I use a BackgroundWorker a lot when working with WinForms in order to perform database or webservice calls without freezing the UI thread. Of course web services can be called using their built in asynchronously methods however when you have a separate data access or model layer, these asynchronous methods are not readily available. 

On a new project I was working on, I was looking for a basic example online for quick reference but there wasn't one amongst the top search results so I thought I'd post one.

    using System.ComponentModel;
    using System.Threading;
    using System.Windows.Forms;

    public partial class MainForm : Form
    {
        private readonly BackgroundWorker backgroundWorker = new BackgroundWorker();

        public MainForm()
        {
            this.InitializeComponent();
            this.backgroundWorker.DoWork += this.BackgroundWorkerDoWork;
            this.backgroundWorker.RunWorkerCompleted += this.BackgroundWorkerCompleted;
            this.backgroundWorker.RunWorkerAsync("Passed Argument");
        }

        private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(1000);
            e.Result = e.Argument;
        }

        private void BackgroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show(e.Result.ToString());
            //// Shows "Passed Argument"
        }
    }

Keep in mind you can not run a background worker that is always running so you probably want to do an:
if (this.backgroundWorker.IsBusy)
{
    //// Perhaps do something like put the RunWork request in a Queue.
    //// Once RunWorkerCompleted is fired, Dequeue an kick off the background
    //// worker again.
}
else
{
    this.backgroundWorker.RunWorkerAsync("Passed Argument");
}
For example:
        private readonly Queue<string> queue = new Queue<string>();

        private void InitializeRunWorkerCompleted()
        {
            this.backgroundWorker.RunWorkerCompleted += (sender, e) =>
            {
                if (this.queue.Count > 0)
                {
                    this.backgroundWorker.RunWorkerAsync(this.queue.Dequeue());
                }
                
                //// Regular logic here.
            };
        }

Sunday, February 9, 2014

Easy .NET MVC Active Directory Attribute Based Authorization

Active Directory based authorization in .NET is fairly easy. Just throw an attribute on a controller as follows:
[Authorize (Roles="MyAdGroup")]
public class SettingsController : Controller
Sometimes though you do not want to hard code a role in an attribute as you may want to add or remove roles at will. You may also want to change the roles based on whether you are in production or not. I like to keep my Active Directory roles either in a database or a web.config file so that others can change authorization on the fly. In order to have greater control over your authorization roles you need to extend the AuthorizeAttribute and override AuthorizationCore. You also need to override HandleUnauthorizedRequest in order to have a custom redirect page.
    /// <summary>
    /// Redirects to the unauthorized page.
    /// </summary>
    public class AuthorizeSiteRedirect : AuthorizeAttribute
    {
        /// <summary>
        /// Authorization based on roles in web.config.
        /// </summary>
        /// <param name="httpContext" />The http context
        /// <returns>Whether a user is authorized.</returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            //// In this example we use a web.config key.
            //// <add key="Authorization.site" value="Your comma separated Ad Group List"/>
            var roles = ConfigurationManager.AppSettings["Authorization.Site"]
            return roles.Split(',').ToList().Any(role => httpContext.User.IsInRole(role.Trim());
        }

        /// <summary>
        /// Redirects an unauthorized request to the unauthorized page.
        /// </summary>
        /// <param name="filterContext" />The filter context
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        { 
            filterContext.Result = new RedirectResult("~/Unauthorized");
        }
    }
}

You can now add more authorization levels for example an Admin level.
    /// <summary>
    /// Redirects to the unauthorized page.
    /// </summary>
    public class AuthorizeAdminRedirect : AuthorizeSiteRedirect
    {
        /// <summary>
        /// Authorizes a user based on active directory groups.
        /// </summary>
        /// <param name="httpContext" />The http context</param>
        /// <returns>Whether a user is authorized.</returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var roles = ConfigurationManager.AppSettings["Authorization.Site.Admin"]          
            return roles.Split(',').ToList().Any(role => httpContext.User.IsInRole(role.Trim());
        }
    }
}
Now all you have to do is add an attribute to your controller and you are done:
    /// <summary>
    /// Administration page for site settings.
    /// </summary>
    [AuthorizeAdminRedirect]
    public class SettingsController : Controller
Please be aware that when you store you active directory groups in a location like your config file you need to be sure to trim whitespace from your group name. Otherwise httpContext.User.IsInRole will not work accurately. For example if User1 is in group Group1 then User.IsInRole(" Group1") will return false however User.IsInRole("Group1") will return true.

Friday, February 7, 2014

Common.Net library methods: Querying Active Directory for users and groups

Finding the groups a user belongs to in active directory along with the members of that group is something that comes up a lot when .Net apps use Active Directory for authentication. Here are some common library methods to find members of a group or groups a member belongs to. This code requires a reference to System.DirectoryServices.AccountManagement.
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices.AccountManagement;
    using System.Linq; 

    public class ActiveDirectoryGateway 
    {
        private readonly string domain;

        private readonly ContextType contextType;

        public ActiveDirectoryGateway(ContextType contextType, string domain)
        {
            this.contextType = contextType;
            this.domain = domain;
        }

        /// <summary>
        /// Retrieves a list of AD groups belonging to an AD User.
        /// </summary>
        /// <param name="user">The active directory user.</param>
        /// <returns>A list of AD groups the user belongs to.</returns>
        public virtual IEnumerable<string> FindGroups(string user)
        {
            var list = new List<string>();
            using (var context = new PrincipalContext(this.contextType, this.domain))
            {
                using (var userPrincipal = UserPrincipal.FindByIdentity(context, user))
                {
                    if (userPrincipal == null)
                    {
                        return list;
                    }

                    using (var results = userPrincipal.GetGroups())
                    {
                        list.AddRange(results.Select(result => result.Name));
                    }
                }
            }

            list.Sort();
            return list;
        }

        /// <summary>
        /// Lists members of group.
        /// </summary>
        /// <param name="grp">The AD group.</param>
        /// <returns>A list of AD members of the group.</returns>
        public virtual IEnumerable<string> FindMembersOfGroup(string grp)
        {
            var list = new List<string>();
            using (var context = new PrincipalContext(this.contextType, this.domain))
            {
                using (var group = GroupPrincipal.FindByIdentity(context, grp))
                {
                    if (group == null)
                    {
                        return list;
                    }

                    list.AddRange(group.GetMembers(true).Select(result => result.Name));
                }
            }

            return list;
        }
}

Common .Net Library Methods: Easy XML Serialization and deserialization

Serializing XML to an object of a given type and back has been very common in a lot of my projects. It may not be allowable when you are working on multiple projects in different groups to import a common class library so I thought I'd post some basic serialization code generic to most projects that I have had to use a lot lately.
        /// <summary>
        /// Deserializes an XML document into a given type.
        /// </summary>
        /// <typeparam name="T">The type to deserialize.</typeparam>
        /// <param name="xml"> The xml. </param>
        /// <returns> An object representative of the XML document. </returns>
        public T Deserialize<T>(string xml)
        {
            var xmlSerializer = new XmlSerializer(typeof(T));
            using (var reader = XmlReader.Create(new StringReader(xml)))
            {
                if (xmlSerializer.CanDeserialize(reader))
                {
                    return (T)xmlSerializer.Deserialize(reader);
                }
            }

            return default(T);
        }

/// <summary> /// Serializes an object into an XML document. /// </summary> /// <param name="path"> The path. </param> /// <param name="o"> The object to serialize. </param> public void Serialize(string path, object o) { using (var writer = new StreamWriter(path)) { new XmlSerializer(o.GetType()).Serialize(writer, o); } }

Thursday, February 6, 2014

WCF Logging raw soap requests.

To troubleshoot a contract filter mismatch or other WCF fault message being thrown from  third party consumers, here is the web.config settings that will show the raw soap requests to inspect if the caller is using a malformed request. Please be aware that the first thing to do when troubleshooting a contract filter mismatch is to ensure the web reference is up to date and running. This message can be very deceiving such as if you are calling a web service from a web service, and the latter web service is not running or running on a different virtual etc.

Make sure the first section is contained within System.Servicemodel. As you can see I do not show the opening tag tag.
 
 <!-------- within the system.servicemodel element -------->
 <diagnostics>      
      <messageLogging
           logEntireMessage="true"
           logMalformedMessages="true"           
           logMessagesAtServiceLevel="false"
           logMessagesAtTransportLevel="true"
            maxSizeOfMessageToLog="65535000" 
      maxMessagesToLog="500" />
    </diagnostics>
  </system.serviceModel>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true" >
        <listeners>
          <add name="xml"/>
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="xml"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml"
           type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="C:\test\Traces.svclog" />
    </sharedListeners>
  </system.diagnostics>