Wednesday, December 28, 2011

Room Finder - Outlook 2007 Add-in

Often, when we want to book a meeting room, we end up gathering all the rooms in the vicinity, removing those that are already booked, and then narrowing down our choices based on our preferred rooms. This sounds like quite a lot of manual effort each time we want to book a room. Fortunately, the Outlook APIs are good enough to allow us to automate most of this.

Introducing, the Room Finder - an add-in for Outlook 2007 users.

Sources of inspiration:
1. A large retailer's IT company that I used to work with had a Room Finder utility added in Outlook. This was back in 2008. I wasnt allowed access to the source code, though. So, I had to create one on my own, based on my experiences as an end-user.

2. Outlook 2010 has this feature. So, for those who haven't got a chance to use Outlook 2010 yet, this is a feature that you would be using once the upgrade happens. Using this add-in in Outlook 2007 makes you get used to this feature.

Steps to create the Room Finder add-in:
1. Using Visual Studio 2010, create an Outlook 2007 Add-in project

2. Add an Outlook Form Region.

Name it RoomFinderFormRegion instead of the default FormRegion1.
How would you like to create this form region?
Select 'Design a new form region'
What type of form region do you want to create?
Select 'Adjoining' type. Replacement is not supported for built-in forms.
What name, title and description do you want to use?
Name it 'Room Finder'
In which display modes should this form region appear?
Turn on the first checkbox and turn off the other 2. We only want this to be available in compose mode.
Which standard message classes will display this form region?
Turn on the first one checkbox for Appointment. Turn off the others, including the default one for Mail Message. We only want this for Appointments / Meeting Requests.
We don't need to specify any custom message classes either.
Click on Finish
(Optional) If you used the default name of FormRegion1 and want to rename it to RoomFinderFormRegion, rename it on the file instead of the class. This keeps the file and the class name in sync. For sake of completeness, there are some more regions where this name would need to be udpated. Find and replace all in the solution for 'FormRegion1'. You would find a string literal, some comments, a corresponding factory class and event handlers where this needs to be updated.
(Note) A pfx key would also be added automatically to the project. You don't need to worry about that.

3. Open the RoomFinderFormRegion in design mode. Add a normal (Windows Forms) Button from the toolbox. Change the Name and Text properties of this button to 'btnSuggest' and 'Su&ggest me a room...' respectively. The & is obviously just to make the g a hot-key so that one can get to it sooner by using the Alt-G key combination.
Ensure that you reduce any whitespace on the form region, except for the button. Resize the form region vertically. Resizing horizontally is not required, as the form region would occupy the entire width of the appointment item anyway.

4. Add a button click event handler. Include the following code in the event-handler.
            try
            {
                var item = (Outlook.AppointmentItem)this.OutlookItem;
                var mapi = Globals.ThisAddIn.Application.GetNamespace("MAPI");
                mapi.Logon();
                // get appointment time info
                DateTime startOn = item.Start;
                DateTime endOn = item.End;
                //TODO: sort rooms based on floor, user preferences & people count
                string identifiedRoom = string.Empty;
                foreach (var room in rooms)
                {
                    //get meeting room's calendar properties
                    var resource = mapi.CreateRecipient(room);
                    bool isFree = resource.AddressEntry.GetFreeBusy(startOn, endOn);
                    if (isFree)
                    {
                        identifiedRoom = room;
                        break;
                    }
                }
                mapi.Logoff();
                if (!string.IsNullOrEmpty(identifiedRoom))
                {
                    item.Resources = identifiedRoom;
                    item.Location = identifiedRoom;
                }
                else
                {
                    MessageBox.Show("No rooms found for this time period! Please consider scheduling the appointment at another time.");
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(string.Format("Error: {0}", ex.ToString(), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation));
            }
This code won't compile yet. Complete the following steps for that.

5. Add the following class-level member variable to the RoomFinderFormRegion class.
        private string[] rooms = new string[] {
            "Conf Room 1",
            "Conf Room 2",
        };
The array needs to contain all the rooms that we are intersted in. For each room, the string can either be the display name, alias or the full SMTP e-mail address of the meeting room.

6. Add a using statement for the MessageBox.
You can see a few more that were automatically added to the RoomFinderFormRegion class. Use Remove and Sort to remove the redundant ones. You will find that these are the only ones we need for now:
using System;
using System.Windows.Forms;
using Outlook = Microsoft.Office.Interop.Outlook;

7. If you attempt to use the in-built AddressEntry.GetFreeBusy method, it doesn't feel a lot DotNetty. It returns a string, with each character being a free/busy indicator for a certain time interval, the default being 30 minutes. The appointment, on the other hand, already has the start and end datetime values specified. So, what we actual need is for the AddressEntry object to give us a method that would tell us if the resource (meeting room) is available during that time. Since the AddressEntry object doesnt have a method of that kind, we use extensions. And for that, we need to put that in a separate static class, as shown here.
    public static class AppointmentHelper
    {
        private const int DEFAULT_INTERVAL = 30;
        public static bool GetFreeBusy(this AddressEntry addressEntry, DateTime start, DateTime end)
        {
            string freeBusyInfo = addressEntry.GetFreeBusy(start.Date, DEFAULT_INTERVAL, false);
            int position = (int) start.TimeOfDay.TotalMinutes / DEFAULT_INTERVAL;
            TimeSpan ts = (end - start);
            int blocks = (int) ts.TotalMinutes / DEFAULT_INTERVAL;
            return freeBusyInfo.Substring(position, blocks).All(c => c.Equals('0'));
        }
    }

8. Build the code. Ensure that the Outlook client has been closed. You can now run/debug the code. When you create a new appointment, you can now see the new region at the bottom part of the item window.
Click on the button in this Room Finder region to invoke the code that looks for a room which is free during the time selected in the appointment. If no rooms could be identified, a corresponding message is shown. Once a room is identified from the order in which it is present in the array, the search is called off, and the room is added as a resource to the appointment item.

9. Notice that I have left a TODO comment in the code above, which states that another feature could be built into this to sort the rooms based on location/floor, user preferences & people count. For instance, you wouldn't want to book a room which is good enough for 28 people if only 3 of you are going to use it. All this logic would execute to give a sorted list of the rooms array mentioned earlier. The rest of the code remains the same.

10. It is typical to expect the list of rooms to be configured externally instead of being hard-coded as an array of strings.
Add an application configuration file to the project. Include a key named Rooms and a value having a semi-colon delimited string of conf rooms. This is what it would look like.
<configuration>
  <appSettings>
    <add key="Rooms" value="Conf Room 1; Conf Room 2"/>
  </appSettings>
</configuration>

Add a reference to System.Configuration, and add a using statement for the same namespace. Add the following code at the top of the button click event hander, making sure this is still within the try block.
                //TODO: provide a way to edit and store this from Outlook
                string roomsDelimited = ConfigurationManager.AppSettings["Rooms"];
                rooms = roomsDelimited.Split(';');
You can also remove the array initializer since it is now being done only on the button click. The array definition can remain there.
private string[] rooms;
Again, I have left a TODO comment here since managing rooms from Outlook (another button in the add-in, plus storing this data in the mailbox) would be a better approach than having to manage it thru the config file.

11. Note that once you start the project, it will publish this add-in to Outlook. Any changes that you make to the add-in reflect in Outlook during the next launch. Even if you are launching Outlook separately after that, these changes are reflected.
To remove a certain add-in locally, you can use Tools → Trust Center → Add-ins.
Click on Go, select the add-in you don't want anymore (ignore the checkboxes - those are only for enable/disable) and click on Remove.

12. To deploy/distribute & for others to install
Use the Publish wizard. This also creates the setup file.
I suggest publishing to a website so that you can put in updates to the same place.
The default behavior is for the add-in to check for updates every 7 days.

References:
http://msdn.microsoft.com/en-us/library/bb410039(v=office.12).aspx
http://www.eggheadcafe.com/microsoft/Outlook-Program-Forms/35554170/how-to-read-single-instance-of-recursive-meetings-in-outlook.aspx
http://www.tech-recipes.com/rx/1959/outlook_2007_disabling_enabling_add_ins/
http://www.codeproject.com/KB/office/Outlook_Add-in.aspx
http://msdn.microsoft.com/en-us/library/bb147704(v=office.12).aspx
http://msdn.microsoft.com/en-us/library/ms526723(v=exchg.10).aspx
http://support.microsoft.com/kb/310259

Tuesday, December 27, 2011

OWASP Top 10 for .NET Developers

http://www.troyhunt.com/2011/12/free-ebook-owasp-top-10-for-net.html

This article includes a link to a free eBook​ that includes content from all the related blog posts.

Excerpts from the author:
I knew – and many of us know – that unsalted hashes are vulnerable to a rainbow attack but I’d never actually executed one of these attacks myself. So I did. Same again on sniffing packets; knowing that lack of transport protection leaves network traffic vulnerable is one thing, sitting in the car outside McDonald’s and actually capturing wifi traffic and hijacking the session (my own, that is!) is another thing altogether.

My analysis:
Completed just the first topic so far. It's nice to see a step-by-step approach that shows the vulnerabilities being exploited, and ways to reduce those risks.

Monday, December 12, 2011

Ctrl-Alt-Del on remote desktop

Needed to change my password on a different domain, into which I remote login.
Ctrl-Alt-Del equivalent is Ctrl-Alt-End
source: https://www.google.com/#q=ctrl%20alt%20del%20remote%20desktop

More remote desktop keyboard shortcuts are listed here:

Remote desktop connection navigation

  • CTRL+ALT+END (Open the Microsoft Windows NT Security dialog box)
  • ALT+PAGE UP (Switch between programs from left to right)
  • ALT+PAGE DOWN (Switch between programs from right to left)
  • ALT+INSERT (Cycle through the programs in most recently used order)
  • ALT+HOME (Display the Start menu)
  • CTRL+ALT+BREAK (Switch the client computer between a window and a full screen)
  • ALT+DELETE (Display the Windows menu)
  • CTRL+ALT+Minus sign (-) (Place a snapshot of the entire client window area on the Terminal server clipboard and provide the same functionality as pressing ALT+PRINT SCREEN on a local computer.)
  • CTRL+ALT+Plus sign (+) (Place a snapshot of the active window in the client on the Terminal server clipboard and provide the same functionality as pressing PRINT SCREEN on a local computer.)
source: http://support.microsoft.com/kb/301583

Sunday, December 11, 2011

Thursday, December 8, 2011

FlowDocument issues

We created this service that would fire prints on a network printer. When tested for performance, the code showed signs of memory leaks. This was strange, because I was expecting the .Net's garbage collector to cleanup unused objects. Perhaps there were some objects that were left to be disposed.

So, as part of our analysis, using WinDebugger, a memory dump of the process was collected. Using DebugDiag, this dump was analyzed. Multiple objects of type FlowDoument (used in CreateXpsDoc) were found blocking the finalizer queue. Googling for this type led us to some similar problems with this type being discussed in tech forums. It seems FlowDocument uses System.Windows.Threading.Dispatcher to free all resources

Reference: http://stackoverflow.com/questions/952985/flowdocument-memory-issue-in-c-sharp

Solution:
Execute these lines of code between printing and deleting the xps file.
var dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.SystemIdle);
System.Windows.Threading.Dispatcher.Run();

Friday, December 2, 2011

Ascii Character as Symbols

I wanted to create a spreadsheet like this in Excel.



I figured I could use - and > for the right arrow to make it ->. But, what about the down arrow? Should I use a | and a V? That didn't feel good. So, I googled for "down arrow ascii" and it brought me to this page.
http://chexed.com/ComputerTips/asciicodes.php

This tells me I could use Alt-26 for the right arrow and Alt-25 for the down arrow. The results are for you to see. Nice. :)

Note: Use the number pad on the keyboard for the digits.

Wednesday, November 30, 2011

Rolling Flat File Trace Listener

Here are the standard trace listeners supported by Enterprise Library 3.1 Logging Application Block.

Table 7 mentions the Rolling Flat File Trace Listener. The flat file rolls over based on either the size of the file or the time interval (such as daily). You could also do both.

Managing emails in Outlook

Most of what I knew about improving productivity managing emails in Outlook. But, sums it up nicely.

http://www.microsoft.com/atwork/productivity/emailtools.aspx

Monday, November 21, 2011

Evaluate websites

http://www.websiteoutlook.com/
Currently, Google is ranked #1 with more than a billion page views every day, and Facebook is at #2 with about half a billion page views every day.

In comparison, our retail client's online shopping website gets about a million page views every day.

Parkour

Parkour: method of movement focused on moving around obstacles with speed and efficiency
More at http://en.wikipedia.org/wiki/Parkour
Source: http://www.santabanta.com/jokes.asp?catid=10760

PDF Printer for Windows

Whenever I need to have a copy of something important, such as a travel ticket, I like to print to file instead of a regular printer. This way, I could always print it again without having to generate the material again. I used to use the Microsoft Office Document Image Writer for this. This is one of the non-default features that comes with Microsoft Office 2003 or 2007, but has been discontinued in Office 2010.
http://support.microsoft.com/kb/982760

So, when I have Office 2010 on my new PC, I install just this component from the Office 2007 installer, up until now. The MDI or TIF format works fine locally, but if I have to share it with someone else, it doesnt work as well.

For instance, when I booked a ticket for my father, I feel sending a PDF is a much better option. So, I googled for it, and the first paid ad brought this free PDF printer for Windows.
http://www.pdflite.com/printer?gclid=CPDAgNqyyawCFUwaQgodmHatrQ

Tried and tested, works fine.

Wednesday, November 16, 2011

Unread mails in Gmail

Once in while, I go to the Spam folder in my Gmailbox and retrieve the ones I do not consider spam. This pushes such emails to my inbox and then I see the nagging sign next to the Inbox that says 20 unread messages. Typically, I can find all of them on page 1. But since these are retrieved from the Spam folder, the dates would stretch to a few days earlier and so, I would have to navigate across pages to find each of these unread emails.

Gmail, fortunately, like Outlook and unlike most other web mail providers, gives a way to filter emails based on whether they are unread. To do this, simply search for label:unread while in Gmail, and you get this filtered list. Cool, huh?

Source: http://www.dailyblogtips.com/gmail-tip-how-to-browse-only-the-unread-messages/

Monday, November 14, 2011

Monday, November 7, 2011

Ways to work faster on slow connections

The science of Science

This is what the Google homepage looks like today:

And this is the first link from the ensuing search page at https://www.google.com/#q=Marie+Curie&ct=curie11-hp&oi=ddle&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=b5ba79dc84c9cc2c&biw=1280&bih=907

http://www.csmonitor.com/Innovation/Horizons/2011/1107/Marie-Curie-Why-her-papers-are-still-radioactive

From the ignorance of radioactive materials in those days, it makes one think... the things we take for granted today need not remain so once we later find a better reasoning. And that's why Science never dies, it never will.

SQL Server encryption issues with mirrored db

We wanted to store some encrypted data in some fields. So, went ahead with this approach.

DBA creates a MASTER KEY encrypted with a password known only to him.
DBA creates a SERVER CERTIFICATE encrypted with this MASTER KEY.
DBA creates a SYMMETRIC KEY encrypted with this SERVER CERTIFICATE.

And then, we just have to open the SYMMETRIC KEY and provide it the name of this SERVER CERTIFICATE before executing any

OPEN SYMMETRIC KEY KeyName DECRYPTION BY CERTIFICATE CertName
-- Include this in a SELECT command
-- CONVERT(varchar(128),DECRYPTBYKEY(@encrypted_value))
CLOSE SYMMETRIC KEY KeyName

This worked well in dev & test environments. But, in prod, we would have a mirrored server as failover to improve availability. And hence when we tried this out before we went live, in perf/staging environment, we got these errors when we attempted to manually failover the primary db server.

Please create a master key in the database or open the master key in the session before performing this operation.
The key 'KeyName' is not open. Please open the key before using it.

When the use the DBA's master key, the queries work fine. But, we wouldnt like our queries to use the master key, would we?

So, it seems the DBA had created a certificate on each server with the same name. But, that means having 2 different certificates, one on each server, with just the name being common.

To get this in place properly, the DBA has to create a certificate on one server, take a backup, copy it to the other server, and then restore it on the failover partner. This way, both the servers would actually use the same certificate.

Some of these best practices are also mentioned here.
http://technet.microsoft.com/en-us/library/cc917681.aspx

Friday, November 4, 2011

DateTime difference

In C#, if I have this
DateTime startedOn = DateTime.MinValue;
DateTime endedOn = DateTime.Now;
then
endedOn - startedOn is a valid expression that returns a TimeSpan with the difference between the 2 dates.

However, the same doesnt work in SQL Server. We need to use
DATEDIFF(s, startedOn, endedOn)
where s stands for seconds. So, if the 2 datetime values have a difference of 10 seconds and 1 minute, and if you expect 10, you are thinking Excel. The value returned here would be 70.

http://msdn.microsoft.com/en-us/library/ms174420.aspx

Dumb-me values

I wanted to perform some load testing of my app. And for which I had to insert some dummy data into a SQL table. Since we wanted to put in maximum data into the fields, it followed that each of the varchar fields should have data with its size limit. Instead of the usual dummy data, I put in some thought to come up with this instead. Am sharing this  since I thought this was nice. :)

First Name16 charactersMyFirstNameIsBig
Last Name16 charactersMyLastNameIsLong
Address1 30 charactersMy Address1 field is humongous
Address2 30 charactersMy Address2 field is huge too!
City 30 charactersI live in a pretty cloudy city
State30 charactersI'm in a const state of denial
Postal Code14 characterswhat zip code?
Email Address46 characterswritingCodeCanBeFunIfUKnowHow000000@iMGeek.com

I didnt come up with the size limits, just the values. The last one is a 6-digit 0-prefixed number that is used to store a million possible values.

StringBuilder

We all know that a StringBuilder object should be used when we are concatenating a sizeable number of strings.

It seems the default capacity is 16. The default maximum capacity is 2147483647 (Int32.MaxValue), which is around 2 gigs, since Int32 can store 4G different values, from -2G to 2G-1.

The value of 16 was surprising. I thought it would be much higher than that. So, in my app where I need to load about 300MB into a StringBuilder object, I guess it is better to use it with a sizeable initial capacity. The initial capacity is also used as a delta when it runs out of the initial capacity. So, choose it wisely. I like to use a value that is a tradeoff between asking for a memory allocation every 16 bytes, and asking for all (like 300MB) in 1 or 2 allocations. For my current app, I have used it as 10MB.

StringBuilder sb = new StringBuilder(10 * 1024 * 1024);

Reference: http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx

Monday, October 31, 2011

Outlook folder renamed

I noticed today that a folder in my Outlook 2010 mailbox had been renamed by some strange force. This is what I could see. So, I googled for this issue, and found that a few folks have had this problem with their Inbox being renamed to image001.jpg. For me, it was the Outbox folder though. The fix was the same, to start Outlook with a switch.

Outlook.exe /resetfoldernames

BEFORE
AFTER

http://www.slickit.ca/2010/03/outlook-2007-inbox-renamed.html

Thursday, October 20, 2011

Unix Shell Commands

Re-learnt this
The usual command to list all files and directories in the Unix shell is
ls
similar to dir in DOS

This just shows the names though. To get more details such as timestamp, the command is
ls -l

Wednesday, October 19, 2011

ConnectionState

I was writing this common method that helps in managing SQL Connections. I came to the point of closing and disposing of connections. I guess having a connection object in a using block will not do, since we wont be able to close the connection before it gets disposed. So, I initialized, opened and used it in a try block, and attempted to close it in the finally block, like this

            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                    connection.Close();
            }
I put in this additional validation to check for the connection state, perhaps from my WCF experience. When I explored the possible state of values in the System.Data.ConnectionState enum, it appears that other than Open and Closed, the 4 other states were "reserved for future versions of the product". Well, the only thing this validation protects from now is if the connection is attempted to be closed when it already is closed.
http://msdn.microsoft.com/en-us/library/system.data.connectionstate.aspx

Here's my DataHelper class:
    internal class DataHelper
    {
        private static readonly string sqlConnectionString = "ConnectionStringLiteral Or MethodCall Goes Here";
        internal static int ExecuteNonQuery(string storedProcName, SqlParameter[] parameters = null)
        {
            SqlConnection connection = null;
            int rowsAffectedCount;
            try
            {
                connection = new SqlConnection(sqlConnectionString);
                using (SqlCommand command = new SqlCommand(storedProcName, connection))
                {
                    SetCommandProperties(command, parameters);
                    rowsAffectedCount = command.ExecuteNonQuery();
                }
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                    connection.Close();
            }
            return rowsAffectedCount;
        }
        internal static DataSet ExecuteQuery(string storedProcName, SqlParameter[] parameters = null)
        {
            SqlConnection connection = null;
            DataSet dataSet = new DataSet();
            try
            {
                connection = new SqlConnection(sqlConnectionString);
                using (SqlCommand command = new SqlCommand(storedProcName, connection))
                {
                    SetCommandProperties(command, parameters);
                    new SqlDataAdapter(command).Fill(dataSet);
                }
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                    connection.Close();
            }
            return dataSet;
        }
        private static void SetCommandProperties(SqlCommand command, SqlParameter[] parameters)
        {
            command.CommandType = CommandType.StoredProcedure;
            if (parameters != null)
                command.Parameters.AddRange(parameters);
        }
    }

Identity field - int or not

I have an identity field in my SQL Server database's table. And I have this stored procedure which inserts a row in this table. The stored proc also returns a few other calculated values other than the new id created. So, I have a SELECT query at the end of the stored proc which goes like this

SELECT SCOPE_IDENTITY() as SomeId, @bar as SomethingImportant

And I use this code in C# to extract this id
int id = (int)rows[0]["SomeId"];

This gives me an invalid cast. Upon inspection, I notice that the value returned from the db call is decimal, not int! Why? Because SCOPE_IDENTITY, and even @@IDENTITY and IDENT_CURRENT(tablename) have the return type defined as NUMERIC(38, 0). This causes .Net to consider it as a decimal.

http://msdn.microsoft.com/en-us/library/ms190315.aspx
http://msdn.microsoft.com/en-us/library/ms187342.aspx
http://msdn.microsoft.com/en-us/library/ms175098.aspx

I ended up using it like this
int id = (int)(decimal)rows[0]["SomeId"];

UPDATE: In my second version, I assigned the value from SCOPE_IDENTITY() to a locally declared INT variable in the stored procedure, and returned that instead. That way, the C# code also takes it as in int.

Tuesday, October 18, 2011

SQL Server in-built functions

Some basic programming in SQL Server that comes handy.
Need to pad your number with zeroes? Use this
RIGHT('00000' + cast(@i as varchar(6)), 6)

Need a random 3-digit access code? Use this
RIGHT('00' + CAST(floor(rand()*1000) as VARCHAR(3)), 3)

Need your guid without the hyphens? Use this
REPLACE(CAST(NEWID() AS varchar(36)), '-', '')

References:
http://msdn.microsoft.com/en-us/library/ms177610.aspx

Monday, October 17, 2011

Reset IDENTITY field

Let us say you have an an IDENTITY field in your table in SQL Server, and have deleted all rows from it, and now wish to insert fresh data. But on doing so, you would notice that this table still remembers the identity value of the last row inserted into it. To start afresh, you would need to do an identity reset. And here is the syntax to do it
DBCC CHECKIDENT (tablename, RESEED, currentvalue)

So, if you want your orders table's identity field to start from 1, you need to use this as
DBCC CHECKIDENT (orders, RESEED, 0)

Reference: http://www.howtogeek.com/howto/database/reset-identity-column-value-in-sql-server/

Friday, October 14, 2011

SQL Server 2008 Editions

This is where you can get SQL Server 2008 Management Studio Express (free SQL client)
http://www.microsoft.com/download/en/details.aspx?id=7593

This is where you can get SQL Server 2008 Express (free SQL host)
http://www.microsoft.com/sqlserver/en/us/editions/express.aspx

And this is where you can find more about the other editions
http://www.microsoft.com/sqlserver/en/us/product-info/compare.aspx

I just noticed today that some people actually write (not just say) SQL as Sequel. :)
Found a discussion about it here as well.
http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=62158

New datatype - DateTime2

Want to know more about the datetime data type in SQL Server?http://technet.microsoft.com/en-us/library/ms187819.aspx

The first thing they will tell you is about the new datetime2 data type.
http://technet.microsoft.com/en-us/library/bb677335.aspx
"Use the datetime2 data type for new work. This type aligns with the SQL Standard. It is more portable."

The interesting thing is that it has more seconds precision with the same storage size of 8 bytes. In fact, it takes only 7 bytes for a precision of 3 or 4 digits, and 6 bytes for less than 3 digits.

datetime2 in SQL Server also has the same date range as that of DateTime defined in .Net, from
January 1, 0001 00:00:00.0000000
through
9999-12-31 23:59:59.9999999
as defined by DateTime.MinValue and DateTime.MaxValue
http://msdn.microsoft.com/en-us/library/system.datetime.minvalue.aspx
http://msdn.microsoft.com/en-us/library/system.datetime.maxvalue.aspx

The earlier datatype (datetime) in SQL Server has a lesser range and lesser precision.
January 1, 1753 00:00:00.000
through
December 31, 9999 23:59:59.997

So, beware when you use DateTime.MinValue or MaxValue in .Net and send it to a datetime parameter in SQL Server. Use datetime2 instead.

It seems System.Data.DbType.DateTime2 is also defined in .Net from framework 3.5 onwards.
http://msdn.microsoft.com/en-us/library/system.data.dbtype.aspx

Transfer data from remote server to local

We have a stored procedure on a SQL Server 2005 box which returns us a result-set. We wanted to execute this stored procedure from a SQL Server 2008 box and store the results into a table locally. So, we created a SQL user on the local (2008) box, a linked server to the 2005 box and executed the stored procedure

exec[linkedserver].[db].[schema].[storedproc]
This works fine.

But, if I try to insert this data into a table variable or a temp table, it gives me an error.
DECLARE @temp ASTABLE (column1 datatype, column2 datatype)
INSERT INTO @temp exec [linkedserver].[db].[schema].[storedproc]
The error is

OLE DB provider "SQLNCLI10" for linked server "linkedserver" returned message "The partner transaction manager has disabled its support for remote/network transactions.".
Msg 7391, Level 16, State 2, Line 2
The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "linkedserver" was unable to begin a distributed transaction.

We didnt want to turn on MSDTC for this since there were no distributed transactions involved. So, we decided to use OPENQUERY, like this.
DECLARE @temp ASTABLE (column1 datatype, column2 datatype)
INSERT INTO @temp exec [linkedserver].[db].[schema].[storedproc]
INSERT INTO @temp SELECT * FROM OPENQUERY([linkedserver],'[db].[schema].[storedproc]')

Note that the last argument to OPENQUERY is the command that gets executed on the remote server locally. So, make sure you dont have the linked server prefix in the stored proc's name.

Reference http://msdn.microsoft.com/en-us/library/ms188427.aspx

Also posted this on
http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/2da5983c-2256-4394-82e0-c0c26c663a7e/

Thursday, October 13, 2011

Clustering, log shipping or mirroring

Good details on the different options available in SQL Server for high availability.
http://sql-articles.com/articles/high-availability/comparison-between-mirroring-vs-log-shipping-and-mirroring-vs-clustering/

Sending table data to a stored procedure

For context, please refer my earlier post at http://wilth.blogspot.com/2011/10/cant-open-symmetric-keys-in-udfs.html

So, since we couldnt use our UDF and had to use a stored proc instead, the trouble with using a stored proc is that it cant directly go into the VALUES clause of an INSERT INTO---SELECT statement, like a UDF could. This means we would need to execute multiple (about a million, seriously) INSERT statements by looping on a temp table.

An alternative would be to have the remote stored proc instead do all the work of opening the key, executing the INSERT INTO---SELECT statement and then closing the key. This has the added benefit of not exposing the TABLE to the remote user. How do we do it? Using TABLE-type parameters. They just came up in SQL Server 2008.
http://msdn.microsoft.com/en-us/library/bb510489.aspx
explained more in
http://www.sqlservercentral.com/articles/Stored+Procedures/2977/

And so, we made this stored proc. But sadly, the DB server that makes the call is still on SQL Server 2005, and so could not invoke this stored procedure. The alternative, it seems, is to send an XML parameter.
http://www.sqlservercentral.com/articles/News/3182/

Web Code Snippet tester for web

If you want to try out some HTML, CSS, JavaScript or even jQuery, here is a convenient way to do so instead of on your dev box. Once you create a snippet, you can even share it with your friends.
http://jsfiddle.net/

Wednesday, October 12, 2011

Get caller's type

If I write a method in C#, can I get to know what type invoked this method? It seems we can, by inspecting the stack trace. But, a better design is just to accept a System.Type parameter and have the caller send that information.

Reference:
http://stackoverflow.com/questions/266115/pass-an-instantiated-system-type-as-a-type-parameter-for-a-generic-class

Secure Network Protocols

SSH - Secure SHell
used to execute remote shell commands over a secure network
replacement for rsh (remote shell) protocol
http://en.wikipedia.org/wiki/Secure_Shell
SSH Communications Security (now Tectia) is a Finnish company that developed the Secure Shell protocol.

SCP - Secure CoPy
http://en.wikipedia.org/wiki/Secure_copy
uses SSH, used to securely transfer files between a local and a remote host
replacement for rcp, which stands for remote copy command in Unix
command-line arguments are based on the cp command to copy files locally

SFTP - Ssh File Transfer Protocol
http://en.wikipedia.org/wiki/SSH_file_transfer_protocol
extension of SSH2 to provide secure file transfers
not to be confused with FTPS which is FTP over SSL
http://en.wikipedia.org/wiki/FTPS

More to read
http://en.wikipedia.org/wiki/Portal:Cryptography

TLS/SSL
http://en.wikipedia.org/wiki/Transport_Layer_Security

TCP
http://en.wikipedia.org/wiki/Transmission_Control_Protocol

UDP
http://en.wikipedia.org/wiki/User_Datagram_Protocol

Packet analyzer
http://en.wikipedia.org/wiki/Packet_analyzer

Cant open symmetric keys in UDFs

We had planned to abstract the use of our encryption logic inside a user-defined function in SQL Server 2008 R2. The caller would send the plain text and we could just send back the encrypted content without having the user to worry about with keys, certificates, encryption algorithms and the daily grind.

But, it appears its not so straightforward, since one would get this error if one attempted to create such a UDF:
"Invalid use of side-effecting or time-dependent operator in 'OPEN SYMMETRIC KEY' within a function."

The workaround is to write this logic in a stored procedure and have that executed by the caller. Of course, it isnt as nice as using the UDF in an INSERT statement directly. But, I guess we can live with that for now.

Reference:
http://social.msdn.microsoft.com/forums/en-US/sqlsecurity/thread/b56f3ef4-10d4-46c1-ade1-dedeee36ac33

Best cash back credit cards in the US

http://creditcardforum.com/content/best-cash-back-credit-cards-4/

Looks like I will go for one from Amex. Dunno yet if I should get the Costco one, or one of the Blue Cash ones.

Blog Name

I initially thought about this blog-site as WILT, with this in the description.

An honest attempt to capture "What I Learned Today". The acronym WILT is an attempt to be sarcastic about the ironical pun on the word of wilt, which means to lose strength, such as used in "to wilt after a day's hard work". Of course, the intent is quite the opposite - to provide energy in the form of knowledge.

But since the sub-domain name wilt was already being used in blogspot, I used wilth instead, with the h being for honestly.

Then, I turned to look for LRKG (Lambi Race Ka Ghoda). But, it seemed that sub-domain name was taken up as well. So, I used 1100010010 for a while.

And now, I have turned to techthirstday. Until last year, our team used to meet every Thursday, to discuss what we have learnt recently. And I thought I could use the same name for this. Sounds nice. :)