Creating Case Insensitive Dictionaries In .NET

For millennia, mankind has looked to the stars and wondered, “How can I create a generic Dictionary in .NET that allows me use case insensitive strings as keys?” Well today that age old question will be answered with this neat trick.

Simply put, all you need to do is add a StringComparer object when constructing a generic Dictionary that uses a string key, and make sure to use on of the IgnoreCase StringComparers that are offered. Below is some sample code to illustrate just how easy this is.

// Create a generic dictionary with a string comparer that ignores case sensitivity.
// This includes the following:
//  - CurrentCultureIgnoreCase
//  - InvariantCultureIgnoreCase
//  - OrdinalIgnoreCase
Dictionary<string, string> stringMap = 
     new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
stringMap.Add("Test Key", "Some value");

// Now try to access or change the corresponding value with the key.
// The case of the key string no longer matters.
stringMap["test key"] = "This will work";
stringMap["TEST KEY"] = "And also this";
stringMap["tEsT kEy"] = "And this as well";
stringMap["tEST kEY"] = "And finally this";

// This can be done with any dictionary that uses a string as the key
Dictionary<string, int> numberMap = 
     new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
numberMap.Add("Test Key", 0);

// Same deal here, you can use any case to get or set the values in the map
numberMap["test key"] = 1;
numberMap["TEST KEY"] = 2;
numberMap["tEsT kEy"] = 3;
numberMap["tEST kEY"] = 4;

And that’s all there is to it.  I hope you enjoy and find this useful.

Richard Franzen
ImageSource, Inc.

What Johnny Cash, stolen cars & software development have in common

“Now the headlights they was another sight
We had two on the left and one on the right
But when we pulled out the switch all three of ‘em come on.”
– Johnny Cash
“One Piece at a Time”

Many years ago, Johnny Cash sang a song called “One Piece at a Time”, in which he describes an automobile assembly plant worker stealing parts and pieces of various automobiles and assembling them into a very distinctive, one-of-a-kind car.

Given the nature of software, the essence of which is some form of code, building software is somewhat like putting that car together.  Technology evolves over time, operating systems change, and new tools all contribute to the complex process of building an application.  Code is pieced together in files and modules, and the output of the code in the form of log files and/or visual display on a monitor are the effects of the code.  When building an engine, putting on the heads and bolting up the crankshaft before attaching the pistons and connecting rods isn’t recommended.  Similarly, software designers aren’t always able to see all the parts until there is a basic framework constructed, and limitations of the system come to light.  Re-designing components and restructuring development schedules are not uncommon. Continue reading

ILINX Capture Mobile for iOS and Android Update

ILINX Capture Mobile extends document capture, normally limited to scanners inside of your organization, out to mobile devices in the field.

  • Capture documents on your mobile device via its camera or existing photos folder
  • View and select batch profiles and associated document types live from your internal ILINX Capture system
  • Index and send documents directly into your ILINX Capture workflow for processing, all from your supported mobile device

ILINX Capture Mobile is great for city/county inspectors, accident photos, realtors, appraisers, or anyone needing to document information remotely or even just expedite travel expenses.

Look for the full details coming soon at:

Robert Hughet
Product Manager
ImageSource, Inc. 

Defining Batch Profiles in ILINX Capture

In ILINX Capture, the most basic unit is a batch profile. A batch profile is a container that includes batch fields, one or more document types and a workflow. It is unique, self-contained and completely independent from each other. In general, you would want to create a batch profile for each unique workflow process in the system.

If you have multiple doc types that mostly follow the same process, you should think about creating a single batch profile to hold all the doc types. With this setup, you can then use permissions to give users access to their specific doc types. Furthermore, within the workflow designer you want to break your workflow logic into common processes, shared by all doc types and specific doc type sub-flows. If you find that you need to create too many sub-flows, re-evaluate the relationship between a batch and doc types and see if you can fix the problem.

The goal is to create unique workflow processes so that system maintenance is easy; and one way to deal with that is to avoid duplicating batch profiles that are performing the same tasks.

Phong Hoang
Development Manager
ImageSource, Inc.

Update UI controls form background worker

When you try to update an UI control from background worker, you might see this error message.

Cross-thread operation not valid: Control ‘MyLabel’ accessed from a thread other than the thread it was created on.

This is how you update UI controls from background worker.

public void UpdateLabel(string text)
MyLabel.Invoke((Action)(() => MyLabel.Text = text));
   MyLabel.Invoke((Action)(() => MyLabel.Update()));


Using SQL Parameters for Insert statement.

Sometimes you need to insert a data to your database. Here is the safer way to insert a row using SQL parameter.
Passing parameters to SQL prevents you build dynamic SQL statement. Building a dynamic SQL statement is a security risk such as SQL injection.
Here is the sample code for insert statement using parameters.

public void InsertRowToDatabaseUsingParams()
//create SQL connection.
using (SqlConnection conn = new SqlConnection(connectionString))
//open sql connection.
string sqlCommand = "Insert into TestTable (column1,column2) Values(@column1,@column2);";

using (SqlCommand cmd = new SqlCommand(sqlCommand, conn))
//add column value to parameters of SqlCommand
SqlParameter param = new SqlParameter("@column1", SqlDbType.VarChar, 50);
param.Value ="value1";

param =new SqlParameter("@column2", SqlDbType.VarChar, 50);
param.Value ="value2";



Kyoungsu Do
Software Developer
ImageSource, Inc.

Making Command Line Calls In .NET

Sometimes you just need to call a console executable.  Whether it is legacy code or the only interface for 3rd party software, console applications are still used and still need to be interfaced with.  Fortunately, .NET comes with a class built specifically to get that job done.  The Process class, located in the Systems.Diagnostics library, can be called to handle console executables and their command line arguments.  Below is an example on how to call this useful class:

Process proc = new Process();

// First, specify the executable file name and any command line arguments
proc.StartInfo = new ProcessStartInfo("C:\\temp\\CmdLineProgram.exe", 
     "-i \"C:\\temp\\InputFile.txt\" -o \"C:\\temp\\OutputFile.txt\"");

// Next, since we want to run this in our program, we don't want the 
// shell to execute it nor have it display in an external window.
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;

// We also want to get any error or output data that the executable might write out.
// This should capture data normally written out to the console screen.
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;

// Now let the executable run.  We'll wait here for it to finish process.

// Gather any exit code information
int exitCode = proc.ExitCode;

// And get the output and error messages.
string errorMsg = string.Empty;
using (StreamReader reader = proc.StandardError)
     errorMsg = reader.ReadToEnd();
}string outMsg = string.Empty;
using (StreamReader reader = proc.StandardOutput)
     outMsg = reader.ReadToEnd();

Hopefully this small sample will help out with making calls to console applications.  Regarding retrieval of exit codes, output and error messages, not all console applications like to output them to the same place.  Sometimes all output messages actually go to the error message, so you may need to look there.  Some trial and error may be necessary, so make sure to test out the code to find what works and what doesn’t.