skip to Main Content

Bag of Links #2

.NET/C# Programming

PowerShell

Apps and Tools

Other Stuff

Learning Java from a .NET Developer’s Perspective

I feel like I am discovering a whole new world. For my latest project, I have to do a lot of stuff in Java (1.6). While I am familiar with Java the language, I am a total newbie when it comes to Java related technologies, frameworks, and tools. Some of the specific Java technologies and tools I am using are JAXB/JAX-WS web services, Spring Framework, WebSphere Application Server, Maven, Rational Software Architect/Eclipse IDE.

Java Learning Resources

Here are some of the resources I found very useful while learning Java and related technologies in the past several weeks:

Portals

  • Java.sun.com – From the creator of Java itself.
  • Dzone – It’s like DotNetKicks but has everything including Java stuff.
  • IBM Redbooks – Tons of reference materials and everything is free.
  • developerWorks: IBM’s version of MSDN. There is a busy community section with forums as well.
  • Safari Books Online offers on-demand digital access to reference books. It’s not free, but it’s a great resource if you can read lots of books in a short time. Subscribe to their unlimited account and read all the books you want for a month. Remember to cancel before the month is over. Also remember that IBM Redbooks are free on the Redbooks site. Don’t waste your Safari points on Redbooks. And even if you have an unlimited Safari account, IBM’s site is still better because it offers PDFs.

Java

Web Services

Spring Framework

Eclipse IDE, Rational Software Developer/Architect

Misc

C# Features I Wish Java Has

I am sure Microsoft was pretty much thinking about Java when they created C#. The Java language itself it very similar to C# in terms of syntax, keywords, and use of punctuations such as semicolons and braces. I have found that most language features in C# have equivalents in Java. However, there are a few notable exceptions which I particularly miss:

  • Code regions – I use code regions extensively in C#. Eclipse does support code outlining but it’s only for existing code structures (methods) and is not nearly as flexible as c# regions.
  • Properties – Java only has fields and methods. “Properties” are implemented as get* and set* methods. I really miss properties, especially after typing 10 getters and setters in a row.
  • var keyword – Another small but very nice feature in C# that helps make code more compact and reduce typing.
  • Verbatim (@) strings – Very handy for regular expressions and other string literals that contain lots of escape characters.

Java is still evolving. Here’s hoping that some of the above features will make it into the next version of the language.

Wrap Your Unit Tests in Transactions

I have found that the key to writing good unit tests that interact with the database is making sure that the data is in a known state before and after the test. System.Transactions makes this very easy. All you have to do is wrap your unit test inside a TransactionScope and rollback at the end.

For example, in the test below, I am testing the update feature of my Customer data access class. To make sure I have a customer to update, I create it myself at the start of test, then I update it. At the end, scope.dispose() rolls back the whole thing. The database should look exactly like it was before my test.

[TestMethod]
public void CanUpdateCustomer()
{
    using (TransactionScope scope = new TransactionScope) {
        Customer customer = CreateTestCustomer();
        customerDac.saveCustomer(customer);
 
        customer.Phone1 = "804-555-1212";
        customerDac.updateCustomer(customer);
 
        // TODO: verify that update works
 
        scope.Dispose(); // roll back
    }
}

Here are a few more tips I have for unit tests that interact with the database:

  • Maintain scripts to create/rebuild a starting-point database. The starting-point database may contain some data such as lookup data, codes, etc. If your unit tests work correctly, the database will stay the same across tests. With the rebuild scripts, you can easily rebuild in the case of other mishaps or a bug in one of the unit tests causing corrupt data.
  • If you need to create a database record that doesn’t have an auto-generated key, use a random key to minimize the chance that your test will collide with another test running somewhere else. Seed your random generator with Environment.TickCount or a hash code of the machine name or user name.
  • With my Transactional File Manager, you can also restore the state of the file system in addition to the database. Transactional File Manager is great at automatically cleaning up any temporary files you create in your unit tests.
  • Don’t assume your code is the only thing that is touching the database. If the count of records in a table is x, it won’t necessarily be x + 1 after you add a new record to the table. Somebody else may have added to or deleted from the table while your test is running.

For Java programmers, try using Spring TestContext Framework. It’s a bit more complicated to use but it works just as well.

My Silverlight 2.0 Hello World Application

This is an update to my original article that was based on Silverlight 1.0 alpha. The code for the old article no longer worked with the current Silverlight runtime.

Instead of the traditional and simple display of a string, this Hello World application uses animation in code to say “hello”.

Pre-requisites

You will need to have the following installed:

Create a New Silverlight Project

  • In Visual Studio 2008, choose File/New/Project and select Visual C#/Silverlight/Silverlight Application. The Silverlight project type is added when you install the Silverlight Tools.
  • Give your project a name and choose OK.

    New Silverlight Project

  • On the next dialog window, accept the default “Add a new ASP.NET Web project…” and choose OK.

Silverlight Project Files

Since we will be drawing objects, we need a Canvas control instead of the default Grid. Change your Page.xaml file to read like this:

<UserControl x:Class="SilverlightHelloWorld.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="520" Height="140" Loaded="UserControl_Loaded">
    <Canvas x:Name="MyCanvas"/>
</UserControl>

Press F7 when you have Page.xaml opened to switch to the code-behind file Page.xaml.cs, and replace the code there with this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace SilverlightHelloWorld
{
    public partial class Page : UserControl
    {
        // private Storyboard _timer = new Storyboard();
        private DispatcherTimer _timer;
        private List<Cell> cells = new List<Cell>(); // list of all cells
        private int _xSize = 26; // width of the grid, in number of cells
        private int _ySize = 7; // height of the grid
        private int _numCells; // total number of cells
        private int _cellIdx = 0;

        /// <summary>Represents a cell on the grid</summary>
        private class Cell
        {
            public double X; // x-coordinate of cell
            public double Y; // y-coordinate
            public bool On; // True if cell is "on"
            public double Order; // Display order
        }

        public Page()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            // Assign a random value to each cell 
            Random rnd = new Random(Environment.TickCount);
            _numCells = (int)(_xSize * _ySize);

            string template = "                          "
                + " x  x xxxx x    x     xx  "
                + " x  x x    x    x    x  x "
                + " xxxx xxxx x    x    x  x "
                + " x  x x    x    x    x  x "
                + " x  x xxxx xxxx xxxx  xx  "
                + "                          ";


            for (int y = 0; y < _ySize; y++)
            {
                for (int x = 0; x < _xSize; x++)
                {
                    Cell cell = new Cell();
                    cell.X = x * (this.Width / _xSize);
                    cell.Y = y * (this.Height / _ySize);
                    cell.Order = rnd.NextDouble();
                    cells.Add(cell);
                }
            }

            for (int i = 0; i < template.Length; i++)
            {
                cells[i].On = template[i] == 'x';
            }

            // Sort the cells by the random values
            cells.Sort(
                delegate(Cell c0, Cell c1)
                {
                    return c0.Order.CompareTo(c1.Order);
                }
            );

            _timer = new System.Windows.Threading.DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(1);
            _timer.Tick += new EventHandler(timer_Completed);
            _timer.Start();

        }

        void timer_Completed(object sender, EventArgs e)
        {
            if (_cellIdx < _numCells)
            {
                // Get the next cell
                Cell cell = cells[_cellIdx];

                // Draw the cell
                Rectangle r = new Rectangle();
                r.Stroke = new SolidColorBrush(Colors.DarkGray);
                if (cell.On)
                {
                    r.Fill = new SolidColorBrush(Colors.Red);
                }
                else
                {
                    r.Fill = new SolidColorBrush(Colors.LightGray);
                }

                r.Width = this.Width / _xSize;
                r.Height = this.Height / _ySize;
                r.SetValue(Canvas.LeftProperty, cell.X);
                r.SetValue(Canvas.TopProperty, cell.Y);
                MyCanvas.Children.Add(r);
                _cellIdx++;
            }
            else
            {
                _timer.Stop();
            }
        }
    }
}

Save the file. Right click on SilverlightHellowordTestPage.aspx and choose Set As Start Page, then run the app.

Hosting the Application

To host the application on your web site, just copy the following files:

  • Silverlight.js
  • SilverlightHelloWorldTestPage.html
  • ClientBin/SilverlightHelloWorld.xap

Click here to see the application in action.

Bag of Links #1

A while ago I had been posting my Finds of the Weeks series and this is the continuation of that. Instead of weekly though, this series will be more of a “whenever possible” kind of thing.

General Programming

.NET/C# Stuff

Database

Windows

Software, Tools, etc.

  • If you have a Linksys WRT54* router, I highly recommend loading Tomato firmware. I have been using it for about 6 months now and it’s so much better than the built-in Linksys firmware. Tomato’s QOS works great to make sure my Vonage phone line remains usable at all times.Tomato firmware

PowerShell

  • Ben Pierce posted a series of very useful PowerShell command-line demos: Demo1 (Administering Windows), Demo 2 (Administering Servers in bulk), Demo 3 (How do I Know Which Class to Use), Demo 4 (Administering Hyper-V).

Something Different

Detecting Blank Images with C#

Greetings visitor from the year 2020! You can get the latest optimized working source code for this, including a version that does not use unsafe code, from my Github repo here. Thanks for visiting.

Recently I needed a way to find blank images among a large batch of images. I had tens of thousands of images to work with so I came up with this c# function to tell me whether an image is blank.

The basic idea behind this function is that blank images will have highly uniform pixel values throughout the whole image. To measure the degree of uniformity (or variability), the function calculates the standard deviation of all pixel values. An image is determined to be blank if the standard deviation falls below a certain threshold.

Here’s the code. In order to compile, the project to which this code resides must have “Allow Unsafe Code” checked.

public static bool IsBlank(string imageFileName)
{
    double stdDev = GetStdDev(imageFileName);
    return stdDev < 100000;
}

/// <summary>
/// Get the standard deviation of pixel values.
/// </summary>
/// <param name="imageFileName">Name of the image file.</param>
/// <returns>Standard deviation.</returns>
public static double GetStdDev(string imageFileName)
{
    double total = 0, totalVariance = 0;
    int count = 0;
    double stdDev = 0;

    // First get all the bytes
    using (Bitmap b = new Bitmap(imageFileName))
    {
        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, b.PixelFormat);
        int stride = bmData.Stride;
        IntPtr Scan0 = bmData.Scan0;
        unsafe
        {
            byte* p = (byte*)(void*)Scan0;
            int nOffset = stride - b.Width * 3;
            for (int y = 0; y < b.Height; ++y)
            {
                for (int x = 0; x < b.Width; ++x)
                {
                    count++;
                    byte blue = p[0];                            
                    byte green = p[1];
                    byte red = p[2];

                    int pixelValue = red + green + blue;
                    total += pixelValue;
                    double avg = total / count;
                    totalVariance += Math.Pow(pixelValue - avg, 2);
                    stdDev = Math.Sqrt(totalVariance / count);

                    p += 3;
                }
                p += nOffset;
            }
        }

        b.UnlockBits(bmData);
    }

    return stdDev;
}

Web Scraping, HTML/XML Parsing, and Firebug’s Copy XPath Feature

If you do any web scraping (also known as web data mining, extracting, harvesting), you are probably familiar with the main steps: navigate to page, retrieve HTML, parse HTML, extract desired elements, repeat. I’ve found the SgmlReader library to be very useful for this purpose. SmglReader turns your HTML into XML. Once you have the XML, it’s fairly easy to use built-in classes such as XmlDocument, XmlTextReader, XPathNavigator to parse and extract the data you want.

Now to the labor intensive part: before your program can make sense of the XML, you have to manually analyze the HTML/XML first. Your program won’t know jack about how to extract that stock price until you tell it exactly where the stock price is, typically in the form of an XPath expression. My process of getting that XPath expression goes something like this:

  1. Scroll to/find desired element in the XML editor.
  2. Does element have unique attributes that can be used?
    • a – If yes, code XPATH statement with filter on attribute value. Example: //Table[@id=”searchResultTable”].
    • b – If no, code an absolute XPATH expression. Example: /html/body/div[4]/pre[2]/font[7]/table[2]/tr[5]/td[2]/table[1]/tr[2]/td[5]/span.

Step 2b is where it gets very labor intensive and boring, especially for a big web page with many levels of nesting. Visual Studio 2005 XML Editor/Resharper have a couple of features that I find useful for this:

– Visual Studio’s Format Document (Edit/Advanced/Format Document) command formats the XML with nice indentation and makes it a lot easier to look at.

– With Resharper, you can press Ctrl-[ to go to the start of the current element, or if you are already at the start, go to the parent element.

Even with the above tools, it’s still a painful and error-prone exercise. Luckily for us, Firebug has the perfect feature for this: Copy XPath. To use it, open your HTML/XML document, open the Firebug pane (Tools/Firebug/Open Firebug), navigate to the desired element, right click on it and choose “Copy XPath”.

Firebug Copy Xpath

You should now have this XPath expression in the clipboard, ready to be pasted into your web scrapper application: “/html/body/div[2]/table/tr/td[2]/table”.

A feature that I would love to have is the ability to generate an alternate XPath expression using “id” predicates, such as this: “//Table[@id=”searchResultTable”]”. With web pages that are not under your control, you want to minimize the chance that changes on the pages impact your code. Absolute XPath expressions are vulnerable to any kind of changes on the page that change the order and/or nesting of elements. On the other hand, XPath expressions using an “id” predicate are less likely to be impacted by layout changes because in HTML, element IDs are supposed to be unique. No matter where your element is on the page, if it has the same ID, you should still be able to get to it by looking up the ID. Hmm… this sounds like a good idea for a Visual Studio Add-in.

Interesting Finds – August 27, 2008

If you are a subscriber to my blog, you may have noticed that I have not been posting my more “Finds of the Week” in the last 2 months. Well, I was a little busy with the month-long Euro 2008 tournament in June, plus a couple of new games (Crysis and Medieval Total War II). Finally the Olympics in August finished me off.

I am going to turn this series into a periodic (as in longer than weekly :-)) Interesting Finds series from now on.

Oh, if you want to know… Crysis is ok. Very good graphics and requires a hot rod box but gameplay is just ok. I am more into realistic squad-based shooters. Medieval 2 is very addictive.

.NET, C#

Programming, General

PowerShell

  • I am finding more and more things I can do with PowerShell everyday. The other day I had to “touch” a file… two lines is what it takes:

    PS C:\Users\Cdo\AppData\Local\Temp> $f = ls testFile.txt
    PS C:\Users\Cdo\AppData\Local\Temp> $f.LastWriteTime = new-object System.DateTime 2007,12,31
    PS C:\Users\Cdo\AppData\Local\Temp> ls testFile.txt
    
    
        Directory: Microsoft.PowerShell.Core\FileSystem::C:\Users\Cdo\AppData\Local\Temp
    
    
    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    -a---        12/31/2007  12:00 AM          8 testFile.txt
    
    
    PS C:\Users\Cdo\AppData\Local\Temp>

Something Different

Back To Top