Thursday, October 27, 2011

How to receive execution arguments on a C# WinForms Application?

The below code that illustrates how to receive arguments for a WinForms Application.The example expects two arguments and validates that the are converted properly.
If the appropiate argumetns are sent, these are stored in a public class named GlobalVars.


[STAThread]
 static void Main( string[] MyArgs)
 {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(
false);

     if (MyArgs.Length == 0 || MyArgs.Length < 2)
     {
        MessageBox.Show(
        "Please specify Parm1 and Parm2 as Arguments in order to
         Proceed.",
        "YourAppTitle", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Application.Exit();
        return;
      }
      else
      {
         try
         {
            GlobalVars lGlobalVars =
new GlobalVars(); 
            lGlobalVars.gOrderSkey = Int64.Parse(MyArgs[0]);
            lGlobalVars.gShipmentNo = Int64.Parse(MyArgs[1]);
          }
          catch (Exception Ex)
          {
             MessageBox.Show(
          "Invalid Parm1 and/or Parm2 Arguments. Please verify. \rError: "
          + Ex.Message, "YourAppTitle",
          MessageBoxButtons.OK, MessageBoxIcon.Error);
          Application.Exit();
          return;
          }
          Application.Run(
new Form1());   
      }

}

Notice the "\n" to break down the MessageBox in two lines. Is a nice little trick that I often forget
Hope this helps,
Will

Thursday, October 20, 2011

Where is Microsoft Outlook Temp Folder? (Windows 7 and Outlook 2010)

Ever wondered where Microsoft Outlook stores temp files?

It is useful to know this location, so you can go there and delete the multiple copies of attachments and pictures and other Outlook files. It can also be useful if you are looking for an attachment contained in a message that you deleted by mistake.

For Outlook 2010 running under Windows 7 go to:
C:\Users\UserName\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.Outlook

In this folder you will find that there is one or multiple folders named with a random combination of numbers and letters, for example: 82UOSVIP
Inside this directory you will find attachments and pictures stored by Outlook.

If you are curious. This is stored in a registry entry:
HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\14.0\Outlook\Security
Value Name: OutlookSecureTempFolder
Data Type: REG_SZ

If you need more info, or you are looking for the temp folder in previous versions of Outlook, go to:
http://support.microsoft.com/kb/817878





Wednesday, October 19, 2011

Executing a Stored Procedure from a WCF Service Method

Here is an example of a method that is used within a WCF Service to execute a Stored Procedure and  parse the return value (a success/failure string) to a local variable which can be manipulated to display a friendly success or failure message.

public String fSave (string aParm1, string aParm2, 
                             string aParm3, Int32 aParm4)
{
    SqlConnection lSQLConn = null;
    SqlCommand lSQLCmd = new SqlCommand();
    string lsResponse = "";
    string connStr = "";
 
    connStr = 
    ConfigurationManager.ConnectionStrings["MyConnStr"].ConnectionString;
 
    try
    {
        // create and open a connection object
        lSQLConn = new SqlConnection(connStr);
        lSQLConn.Open();
        //The CommandType must be StoredProcedure if we are using an ExecuteScalar
        lSQLCmd.CommandType = CommandType.StoredProcedure;
        lSQLCmd.CommandText = "sp_YourSPName"; 
        lSQLCmd.Parameters.Add(new SqlParameter("@Parm1", aParm1));
        lSQLCmd.Parameters.Add(new SqlParameter("@Parm2", aParm2));
        lSQLCmd.Parameters.Add(new SqlParameter("@Parm3", aParm3));
        lSQLCmd.Parameters.Add(new SqlParameter("@Parm4", aParm4));
               
        lSQLCmd.Connection = lSQLConn;
        //Executes the SP and returns the single select output to a variable
        lsResponse = Convert.ToString(lSQLCmd.ExecuteScalar());
    }
    catch (Exception Exc)
    {
        return "Error: " + Exc.Message;                
    }
    finally
    {
        lSQLCmd.Dispose();
        lSQLConn.Close();
    }
 
    if (String.IsNullOrEmpty(lsResponse))
    {
        return "Error: Unspecified problem while adding task.";                
    }
    return lsResponse;
}

Now, let's review the above method. There are a few interesting things:
Once the connection is open, the SQLCommand has to be defined as a CommandType = CommandType.StoredProcedure. This signals the type of action we need to execute.
Next, we define the Stored Procedure to be executed by defining the CommandText="sp_YourSPName".
To get the return value, we set the string variable to the results of a SQL Command, ExecuteScalar ()

But wait. What should we do if our Stored Procedure returns a result set rather than a single value?
Well, you need to make a slight change to the method, we need to add a DataAdapter and a DataSet to parse the result.
See below:

SqlConnection lSQLConn = null;
SqlCommand lSQLCmd = new SqlCommand();
//Declare a DataAdapter and a DataSet
SqlDataAdapter lDA = new SqlDataAdapter();
DataSet lDS = new DataSet();
 
//...Execution section
 
// create and open a connection object
lSQLConn = new SqlConnection(connStr);
lSQLConn.Open();
//The CommandType must be StoredProcedure if we are using an ExecuteScalar
lSQLCmd.CommandType = CommandType.StoredProcedure;
lSQLCmd.CommandText = "sp_YourSPName"; 
lSQLCmd.Parameters.Add(new SqlParameter("@Parm1", aParm1));
lSQLCmd.Parameters.Add(new SqlParameter("@Parm2", aParm2));
lSQLCmd.Parameters.Add(new SqlParameter("@Parm3", aParm3));
lSQLCmd.Parameters.Add(new SqlParameter("@Parm4", aParm4));
 
lSQLCmd.Connection = lSQLConn;
//Fill the DataAdapter with a SelectCommand
lDA.SelectCommand = lSQLCmd;
lDA.Fill(lDS);

Hope this is helpful,
Will




Thursday, October 13, 2011

Reading Keys from App.Config

I would like to share a small code snippet that is useful if you need to read entries from a configuration file, for example: App.config

Below are the entries I want to read from my App.config

<?xml version="1.0"?>
<configuration>
 <appSettings>
    <add key="MyServiceURL" value="http://10.12.64.190:8086/MyService"/>
  </appSettings>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>

Below is the best way I've found so far to read these entries in C#:

//Scan Thru the keys and use the Configuration Manager to make this happen
foreach (string key in ConfigurationManager.AppSettings)
{
 //Get your key
 string value = ConfigurationManager.AppSettings[key];
 this.Url = value;
}

Keep in mind that you need to add a reference to the System.Manager assembly for this to work.
I've tested this with the .NET Framework 3.5 and 4.0
HTH,
Will




Saturday, October 8, 2011

Sample LINQ with Multiple Joins and Selected Columns

If you are like me, I sometimes find difficult remembering the syntax of LINQ statements because I jump from T-SQL to ASP.Net and C#.
I was searching for a sample that may show how to write a LINQ statement with multiple joins and I had little luck finding it, so finally after I put my few brain cells in action, I came up with the following:

var dbRegCourses = (from a in db.CourseRegistries
                    join b in db.Courses on a.courseid equals b.id
                    join c in db.aspnet_Users on a.userid equals c.UserId
                    where a.userid == sUserID
                    orderby a.regdate, b.code, b.description,
                            b.instructor, b.date, b.venue
                    select new
                    {
                      a.regdate, b.code, b.description,

                      b.instructor, b.date, b.venue});

if (dbRegCourses.Count() > 0)
{
    ResultLbl.Text =
"We found that you are registered to: " +     
                      dbRegCourses.Count().ToString() + " Courses.";
    return;
}

If you notice, here we are joining three tables, using a where statement and then pick and choosing columns from at least two tables.

I also added an if statement bottom to see if I got any rows back from the LINQ Statement and if that's the case return a message.

Hope this helps somebody out there,
Will




Wednesday, October 5, 2011

Import Data from a Text or CSV file into SQL Server

I was recently in need of importing data from a CSV (Comma Separated File) to a table in SQL Server 2008.
After searching in Google for a little while, found this blog entry from Pinal Dave (SQL Authority) which always provides good content.

Besides passing along the technique described in Pinal's blog post, I would like to expand by explaining a few a snags that I ran into.

My source data in the CSV file, looks something like this:

HOU009,Windows Phone 7,Will Martinez,11/10/2011,Houston; TX,999,2
HOU010,WPF for Business Applications,Will Martinez,11/15/2011,Houston; TX,695,1


More an less I have all the data needed to fill the columns of my target table. My assumption is that my column id of type uniqueidentifier is going to be auto-generated. This is my table:

CREATE TABLE [dbo].[Courses](
   [id] [uniqueidentifier] NOT NULL DEFAULT NEWSEQUENTIALID(),
   [code] [varchar](50) NOT NULL,
   [description] [varchar](200) NULL,
   [instructor] [varchar](50) NULL,
   [date] [date] NULL,
       [venue] [varchar](50) NULL,
   [price] [money] NULL,
       [duration] [int] NULL,
 CONSTRAINT [PK_Courses]

    PRIMARY KEY CLUSTERED ([id] ASC,[code] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
  ON [PRIMARY]) ON [PRIMARY]

As you may notice, I have two datatypes that may be challenging, first my primary key is  of type uniqueidentifier and also, I'm using a date datatype.

Initially I tried to import my data from the CSV file using the below statement:


bulk insert [dbo].[Courses]
from 'C:\Courses.csv'

with (fieldterminator = ',', rowterminator = '\n')
go

On my first try I did not have any luck. I ran into the below issue:
Msg 4861, Level 16, State 1, Line 1
Cannot bulk load because the file "C:\Courses.csv" could not be opened. Operating system error code 5(Access is denied.).


Moved my file to the Public directory and then make sure permissions were set to 'Everyone'. No luck, although I did not get the "access denied" error. My insert returns 0 row(s) affected.

At this point my guess was that I had a couple of issues:
- First I did not have a value for the Id column which is our primary key
- My column of type date could be a problem if there is an implicit conversion of string data

To work around the problem, I decided to create a new temporary table, without a primary key and with a datetime datafield.  Here is the table:


CREATE TABLE [dbo].[CoursesTemp](

   [code] [varchar](50) NOT NULL,
   [description] [varchar](200) NULL,
   [instructor] [varchar](50) NULL,
   [date] [datetime] NULL,
   [venue] [varchar](50) NULL,
   [price] [money] NULL,
   [duration] [int] NULL)

Ran my insert statement again:
bulk insert [dbo].[CoursesTemp]
from 'C:\Users\Public\Downloads\Courses.csv'

with (fieldterminator = ',', rowterminator = '\n')
go

Success! Finally got to see what I was waiting for...(20 row(s) affected)

At this point, life is easy. I can use the data I just inserted in the temporary table and use it to insert into the "live" table.

insert [dbo].[Courses]
  (code, description, instructor, date, venue, duration)
select
   code, description, instructor, cast(date as date), venue,
   duration
from [dbo].[CoursesTemp]


Notice that, my Id column is not listed, since it has a uniqueidentifier with a default of  NEWSEQUENTIALID , it automatically generates a GUID for each record.
To deal with the issue of the date field, noticed that there is a CAST statement that will convert the data to the appropriate datatype.


Below is how the data looks in my table.



Now I have the data I needed and my id column has nice GUIDs generated for every record.
I'm ready to get some work done.

Hope this helps somebody out there,
Will







Tuesday, October 4, 2011

How to Force an Application to Open in Administrator Mode without Prompt

Say you have an application, in my case the ancient PowerBuilder and you want it to always "Run as Administrator" so it has access to writing files to the Program Files (x86) folder instead of the users AppData folder.

Obviously you don't want to turn off UAC, that would be silly.

Here is a little trick that I've been using for a while to get an application to open without the annoying User Account Control prompt asking you to Allow the Application to run in Admin mode.

1. Go go the Administrative Tools -> Scheduled Tasks
2. Create a new Scheduled Task

3. Add a Task name and then make sure you select the "Run with highest privileges" option

4. Click on the Actions tab and then browse for the Application you want to open. In my case PowerBuilder

5. Click OK to save the task. Make a note of the Task Name you assigned.
6. Now, create a shortcut, on the target, you will call the task scheduler and then send as an argument the name of the task you previously created, like this: C:\Windows\System32\schtasks.exe /run /tn "YourTaskName" this will run your taks by invoking the Task Scheduler Directly.


You are all set, now use the shortcut to access your application. It will open with Administrative privileges.

If you would like to see this workaround in action and get additional details, please check my video posting below:



Hope it helps,
Will





Monday, October 3, 2011

An awesome weekend with Opeth and Katatonia

First of all, I want to say that this blog entry is totally non-technical.

I just wanted to share with my friends the great experience I had this weekend.
A few months ago, I learned that my two favorite bands Opeth and Katatonia were on tour and coming to FL, they were scheduled to play at the House of Blues in Orlando on October 1rst.
I was lucky enough to grab one of the VIP tickets to meet and greet Opeth.

The experience was great. It was awesome to be able to spend a time and to talk and with the members of Opeth. All the guys are incredibly nice, kind and friendly; they talked to all the fans there, signed autographs, we took pictures with them and had an awesome time together.

The concert was great. Both bands played awesome sets. Katatonia played a mix of new and old material including some favs such as Teargas, My Twin and July.
Opeth had a great set, playing basically a set from their latest album Heritage and a few tracks from Watershed plus a track from Damnation.
I have to admit that I was curious to hear the tracks from Heritage live. They sound awesome! Actually listening to these tracks live, helped me to like the album even more now that I've realized how complex and varied those tracks are.

I want to share some of the pictures I took.


VIP Package


Pre-Concert Stage


Ready for the "Meet and Greet"


Got to talk with the great Mikael Ã…kerfeldt


Martin Mendez: Totally cool guy!

One of the best drummers out there: Martin Axenrot

Mikael signing a few cymbals for fans


Lead Guitar Fredrik Akesson


Katatonia


Katatonia


Katatonia


Stage Ready for Opeth


Opeth Intro


Opeth


Opeth


Opeth


Great Gig!


Thank you!



Katatonia - Nephilim (2 Min. Segment)



Opeth - I Feel the Dark (1:30 Segment)




Date Validation JavaScript vs Code Behind vs RangeValidator

Although you can use a RangeValidator or CustomValidator to evaluate the contents of a textbox that captures a date, there might be instances in which you want to use a Client-Javascript to manually validate or manipulate what's typed.
Another possible situation is to do this on the code behind to validate the input at the moment the data is sent to the server.

After reading a few blogs and articles, below are two JavaScript functions that I've found extremely useful to validate dates .

-Validating the String
Notice how this function will evaluate a string input by using a regular expression. It separates the string and checks if the date elements fall within the numeric range established.

        function validateUSDate(strValue) {
 
            var objRegExp = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/
 
            //check to see if in correct format
            if (!objRegExp.test(strValue))
                return false//doesn't match pattern, bad date
            else {
                var strSeparator = strValue.substring(2, 3)
                var arrayDate = strValue.split(strSeparator);
                //create a lookup for months not equal to Feb.
                var arrayLookup = { '01': 31, '03': 31,
                    '04': 30, '05': 31,
                    '06': 30, '07': 31,
                    '08': 31, '09': 30,
                    '10': 31, '11': 30, '12': 31
                }
                var intDay = parseInt(arrayDate[1], 10);
 
                //check if month value and day value agree
                if (arrayLookup[arrayDate[0]] != null) {
                    if (intDay <= arrayLookup[arrayDate[0]] && intDay != 0)
                        return true//found in lookup table, good date
                }
 
                var intMonth = parseInt(arrayDate[0], 10);
                if (intMonth == 2) {
                    var intYear = parseInt(arrayDate[2]);
                    if (intDay > 0 && intDay < 29) {
                        return true;
                    }
                    else if (intDay == 29) {
                        if ((intYear % 4 == 0) && (intYear % 100 != 0) ||
             (intYear % 400 == 0)) {
                            // year div by 4 and ((not div by 100) or div by 400) ->ok
                            return true;
                        }
                    }
                }
            }
            return false//any other values, bad date
        }


-Implementing validateUSDate
Below is another function that demonstrates how the validateUSDate function is being implemented in the JavaScript attached to the TextBox's OnBlur event. If the entered date fails. We default the date to Today.

        function fWorkDateValidate(str, object) {
            var dt = new Date();
            var dd = dt.getDate();
            var mm = dt.getMonth() + 1; //January is 0!
            var yyyy = dt.getFullYear();
 
            if (dd < 10) { dd = '0' + dd }
            if (mm < 10) { mm = '0' + mm } 
            
            var today = mm + '/' + dd + '/' + yyyy;
 
            if (validateUSDate(str) == false ) {
                alert('Invalid Work Date entered. Please specify date in format mm/dd/yyyy. Example: ' + today);
                object.value = today;
                object.focus();
            }
        }


-Textbox Date HTML

<asp:TextBox ID="TextBox3" runat="server"  style="font-familyArial, Helvetica, sans-serif;font-sizesmall;text-alignrightcolor#FF6600" Width="81px"onBlur="fWorkDateValidate(this.value, this);" MaxLength="10"></asp:TextBox>

I have to admit that I didn't write validateUSDate, I just modified it to fit my needs, I wanted to give credit to the authors but unfortunately since I tried code from several blogs, I can't find the exact pages where I took the function from. So credit is due to the author(s) whoever they are.

In case that you need to validate a date range in Code Behind. Below is an "if" statement to validate data elements using a Regular Expression. Notice how we can easily define the ranges, for example 0 to 1 and 0-9 for the month digits, then  a "/", then a 0-3 for the first digit of the day and so on... you get the idea.

if (String.IsNullOrEmpty(TextBox3.Text) ||
Regex.IsMatch(TextBox3.Text, @"^[0-1]?[0-9](/|-)[0-3]?[0-9](/|-)[1-2][0-9][0-9][0-9]$") == false)


-RangeValidator
Finally, let's review how can you use a RangeValidator to evaluate a date. It is a piece of cake. Just keep in mind that you need to specify a "type" of Date on your Validator and define the Minimum and Maximum Value.

<asp:RangeValidator ID="StDateValidator" runat="server" 
    ControlToValidate="TextBox1" Type="Date" 
    MinimumValue="01/21/1980" MaximumValue="12/31/2100" 
    ErrorMessage="Invalid Start Date. Please verify." 
    style="font-familyArial, Helvetica, sans-serif; 
    font-sizexx-smallfont-weight700"></asp:RangeValidator>

The validator will display the error message automatically, if the data on TextBox1 does not pass the validation.

Happy Coding,
Will