Friday, January 4, 2013

Switch to full screen on Remote Desktop

Ever so often, the default rdp gets set with a certain size which effectively takes away the full screen mode for the session. My earlier approach was to disconnect from the RDP session, and use the options tab to select full screen or the /f mode in mstsc to reconnect in full screen mode again.

I just found that you dont need to disconnect and reconnect. You can switch back to full screen mode in your existing RDP session with the simple (ok, its 3 keys) keyboard shortcut: Ctrl-Alt-Break.

source: http://social.technet.microsoft.com/Forums/en-US/w7itproui/thread/1da2cb6a-a016-4cc9-b802-0c3adc674507/

Back to blogging times after a few months. I feel I shouldnt keep waiting to write that nice big blog post, and should document all these points, however tiny they seem now.

Wednesday, May 23, 2012

Default size for VARCHAR

What is the output of this statement?
select cast('abcdefghijklmnopqrstuvwxyz1234567890' as varchar)

It's
abcdefghijklmnopqrstuvwxyz1234

Why?
Because, CAST uses a default size of 30 for varchar!
Always make sure you specify the size of your dataypes to avoid such gotchas.

Monday, May 21, 2012

XmlSerializationHelper

This is one of those helper classes that I keep using very often.

using System.IO;
using System.Text;
using System.Xml.Serialization;

public class XmlSerializationHelper<T> where T : class
    {
        public string Serialize(T objectToSerialize)
        {
            var sb = new StringBuilder();
            var serializer = new XmlSerializer(typeof(T));
            using (var writer = new StringWriter(sb))
            {
                serializer.Serialize(writer, objectToSerialize);
            }
            return sb.ToString();
        }

        public T Deserialize(string xml)
        {
            var serializer = new XmlSerializer(typeof(T));
            return (T)serializer.Deserialize(new StringReader(xml));
        }
    }

Usage:
string xml = new XmlSerializationHelper<SomeClass>().Serialize(obj);
AND
SomeClass obj = new XmlSerializationHelper<SomeClass>().Deserialize(xml);
Note: I am not using var here, just so that its clear what the return types are.

Monday, March 5, 2012

ASP.NET MVC 4 Beta Released!


Now featuring ASP.NET WEB APIs…

ASP.NET MVC was designed primarily for interacting with humans via web pages. The main use case is emitting HTML and responding to user input (submitting forms, clicking links, etc.). It does a great job at that.

ASP.NET Web API is built for all the other, non-human interactions your site or service needs to support. Think about jQuery code that's making an Ajax request, or a service interface that supports a mobile client. In these cases, the requests are coming from code and expect some kind of structured data and specific HTTP Status Codes.

These two are very complimentary, but different enough that trying to build out HTTP services using ASP.NET MVC took a lot of work to get right. The inclusion of ASP.NET Web API in ASP.NET MVC (and availability elsewhere, including ASP.NET Web Pages) means that you can build top-notch HTTP services in an ASP.NET MVC application, taking advantage of a common base and using the same underlying paradigms.

More at http://weblogs.asp.net/jgalloway/archive/2012/02/16/asp-net-4-beta-released.aspx

Monday, February 27, 2012

Get action name in view


If you want the name of the controller, action or the route values in your ASP.NET MVC view, this is how.
ViewContext.Controller.ValueProvider["action"].RawValue
ViewContext.Controller.ValueProvider["controller"].RawValue
ViewContext.Controller.ValueProvider["id"].RawValue
Source: http://stackoverflow.com/questions/362514/how-can-i-return-the-current-action-in-an-asp-net-mvc-view

NDepend

Had a quick look at NDepend today, for a team that doesnt have higher editions of Visual Studio 2010.

For a tenth of the cost, it does have some useful features for code metrics and finding dependencies.

Given a choice, though, I would rather work with Visual Studio. Probably Resharper might be a better add-in if the intention is to have better code quality.

Saturday, February 25, 2012

URL Typos & Dubious Redirects

Have you heard of phishing attacks? Typically, they are done via spam mails, where the sender wants the recipient to think that the email is authentic, and so are the links within the email. A usual practice followed is to show a hyperlink that supposedly takes the recipient to a known/safe website, but the hyperlink actually points to a similar looking website that would capture the user credentials and other sensitive data. Beware of such links in the email. Use your browser instead. How exactly? Just a minute, I am coming to that.

Another form of phishing is where the user, in an attempt to get to a website, is lured to such a similar looking website, thanks to the typo of the URL (website address) in the browser. For instance, if I mis-type the URL for a website, such as wikipidea.org, instead of the original wikipedia.org, I get redirected to a dubious looking site such as channel-reward-central.com. This one, though, has a look similar to YouTube! But anyway, you get the idea. So, how do we overcome such issues?

For one, use a very little used feature of your browser's - the favorites links. In fact, browsers these days show you a list of frequently visited web sites when you open a new tab. So, that's a good place as well.

But what if you have got a new PC, have installed a new browser, or have just not visited your bank's website in a month, and it isnt saved in your favorites either? Or let's say, what if I want to install Firefox, and i am not sure whether I need to go to firefox.com or mozilla.com? These are situations when your favorite search engine can help as well. Hopefully, you have set that as your home page, or are able to type in the URL with errors, otherwise we are back to square one: goog.com or googe.com for instance is where you shouldn't go. Now, with google.com open, search for the website or the product you are looking for, and the first non-ad link should get you there safely.

Here are some more tips: http://support.google.com/websearch/bin/answer.py?hl=en&answer=8091

Apologies to those who feel this to be a typical case of too many words and too little substance. :)

URL and URI

The terms URL (uniform resource locator) and URI (uniform resource identifier) are often used interchangeably, and very often, this is not correct.

More to read here: http://en.wikipedia.org/wiki/Uniform_Resource_Identifier

To me, a URL points to a physical path to get to the resource, such as one that points to a file or a web page.

On the other hand, a URI is a logical identifier, such as a namespace in a schema definition.

Thursday, February 9, 2012

Base 64 Encoding

When?
If you need to store binary data in a string/text, you could use Base 64 encoding.

What is the problem with storing bytes as such?
Every byte contains 2^8 (256) possible values. But some of these values cannot be represented as text.

Why is it called base 64?
Now, if we think of the usual characters that can be represented as text, they would be A-Z, a-z and 0-9. That gives us 26+26+10 = 62 characters. Let's take 2 more like + and - (or /) and make this 64. Why 64 instead of 62? Since 64 is a round figure. Err, not in the decimal (base 10) system. But, in the binary (base 2) system.
2^6 = 64
So, now in this base 64 system, each of these 64 characters can be represented in 6-bits.

Note: If 8-bits can be called octets, let us call these 6-bits as hexets for now. I just made that up.
Googling for it, I find here that hexet is also, in German, a second-person plural subjunctive I of hexen, which has to deal with magic!

How can I convert an octet sequence into a hexet sequence?
Consider a byte sequence such as "Man". In terms of bytes, the values are 77, 97 and 110.
In terms of bits, these can be represent as 01001101 01100001 01101110
Now, if progress thru this sequence in hexets, we get
010011 010110 000101 101110
which is 19, 22, 5 and 46
which translates to TWFu
considering A-Z as 0-25, a-z as 26-51, and so on.

What if my byte sequence is not divisable by 3?
We pad zeroes at the end of the sequence to make it so. Also, we could introduce ending characters such as = to make up for missing characters.

Any issues with it?
Well, since each 3 octets translate into 4 hexets, it does increase the size of your byte sequence by 33%.

Is this being used anywhere?
The ASP.NET ViewState is one such place that comes to mind.

Can you tell me more?
It's all here. http://en.wikipedia.org/wiki/Base64

Tuesday, February 7, 2012

System objects

If we want to find text in a stored proc definition, we can use this
select * from sysobjects where id in (
select id from syscomments where text like '%TextToFind%')

This approach seems to be outdated though. These system tables were available in SQL Server 2000, and are available in SQL Server 2005/8 as compatibility views for backward compatibility.

The recommend approach is to use the new system views such as sys.sql_modules and sys.procedures. The above query can now be written as
select * from sys.procedures
where object_definition(object_id) like '%TextToFind%'

Reference:
http://databases.aspfaq.com/database/how-do-i-find-a-stored-procedure-containing-text.html

Sunday, January 22, 2012

Remove a label from all posts

I initially had tagged most of my posts here as Technical. But decided to remove it later on, as this is the "Tech" Thirst Day blog-site. I didnt want to remove the label individually from each post. So, here's a way to do that more easily.
http://www.youtube.com/watch?feature=player_embedded&v=wVvd-Y-_mD8

Web Browsers

As web developers, if we are to target 80 to 90% of world-wide web users, we need to ensure that our app works well on at least IE, Firefox & Chrome. You can add Opera, Safari and others if you want to do better.

What is a web browser?
http://en.wikipedia.org/wiki/Web_browser

List
http://en.wikipedia.org/wiki/List_of_web_browsers

Timeline
http://en.wikipedia.org/wiki/Timeline_of_web_browsers

Usage share
http://en.wikipedia.org/wiki/Usage_share_of_web_browsers

Tuesday, January 10, 2012

At var with JavaScript

What does the var keyword do in javascript? Well, it's a little known fact that it defines the scope of the variable. Take for instance this js snippet.

<script>
var i = 10;
fun();
function fun()
{
 j = 20;
 var k = 30;
 alert ('in fun scope: ' + i + ' ' + j + ' ' + k);
};
alert ('in global scope: ' + i + ' ' + j + ' ' + k);
</script>

The second alert statement will give a js error since (because of the var keyword next to it) k is defined only within the function. j, on the other hand, retains global scope since we didnt declare it with var.

Reference: http://www.hunlock.com/blogs/Functional_Javascript#quickIDX3

Sunday, January 8, 2012

Reclaim hard-disk space

A remote Windows server had run out of disk space on the primary logical partition of the hard-disk where the operating system was installed. I wanted to reclaim some of the disk space, since otherwise I couldn't even delete a file! I went looking around for files/folders which were huge and which could be moved without causing too much trouble.

I found some setup files under %windir%\Installer that I could remove.

Note:
1. The Installer folder is hidden. From Windows Explorer menu, Tools → Folder Options → 'View' tab, turn on option to 'Show hidden files, folders and drives' and turn off option to 'hide protected operating system files'. You might want to switch these settings back once you are done with this file move.
2. When you attempt to uninstall a program, these setup files are usually required. So, make sure you either do this temporarily, or if you intend to delete this, do so only for programs you do not wish to uninstall.
3. You can ignore the folders in the Installer folder with the guid names. They just have some files under them such as icons. Sort the folder by size to look at the setup files that take up the most space.
4. Right-click on the column headers on the right pane of the explorer. Click on 'More...' and select 'Subject'. The folder view will now show the name or product titles of the corresponding installer files. This should help identify the setup files instead of the alpha-numeric file names.

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