Wednesday, November 11, 2009

What we c# programmers need : bridging the gap between server side programming and client side programming

I've been using ASP.NET MVC to write a highly dynamic website which extensively uses JQuery, JQuery UI, JQGrid and some other plugins. After several months of programming, there comes a time of reflection on what was done, to look at what could be improved. One of the things I'm still struggling with is the integration of client side code (javascript) with server side code (ASP.NET Mvc). This is what this article is about.

I've been using HTML helpers to hide away javascript for some controls like jqgrid, datetpicker, autocomplete box. Each HTML helper takes in an parameter object, defining how the controls will behave and render. The necessary javascript is generated behind the scenes, and added to the view in one place using a custom HTML helper to render the javascript. This technique works quite well, providing the parameter object is flexible enough to cope with all different scenarios. As long as the parameter object only maps its properties to the properties of the javascript plugin, all is well.

As soon as you need to add more flexibility, which mostly means you will start to implement events on the javascript plugin, things get out of control. Mostly, it's because one or a few pages need some custom behaviour, which is too specific to make it part of the control (thus extending it).

I tried to create a c# scriptbuilder object, to enable me to add custom scripting to a view, but soon, you are recreating a lot of javascript code constructs inside the scriptbuilder. It gets too complicated, and the scriptbuilder is too different from the javascript code, to be convenient.

I also tried ScriptSharp, a project from Nokhil Kothari, which translates c# code into javascript code. For jquery and jquery plugins, you need to build some stub classes (they don't generate code, but are merely there for providing code completion and compile time checking). It's a project with great potential, I like it a lot. But it still has some shortcomings. I've been building a javascript application framework with it, and it works quite well. But the problems arise again when you want to link server side code with client side code..

I must say, ScriptSharp has some enormous advantages for c# developers :
  • compile time checking of code
  • type checking
  • code completion (for the code itself and for the jquery plugins if you write the necessary stub classes)
  • refactoring
  • code navigation
  • etc.. (all the advantages you get from a compiler environment like visual studio).

Some code constructs are a little bit awkward, due to the differences between c# and javascript.
Eg. all jquery code needs to be written using a proxy class : jqProxy.jQuery("#myDiv").css("color","red");
This is not so much a problem. Another example, which took my a while to discovery, to write $(document).ready, you have to write in c# : jqProxy.jQuery(typeof(Document)).ready( ...);
Most of these inconveniences are tollerable, considering the benifits you get.

The major drawback is lack of support and updates. It's been more than a year since the last version was released.

The other major drawback, is linking server side code, with client side code, one of the problems which stops me from extending current use of ScriptSharp. This code to link server side to client side code (using HTML helpers or scriptbuilder classes), tends to clutter server side code. I get a feeling it doesn't belong there, I should be able to separate it more cleanely. One could argue then, why not write all client side code on the client side in pure javascript.

There are two reasons, why I would not like this as a solution to the problem:
  • first of all, there is currently no good IDE for javascript, giving me what I currently have in c#/scriptsharp.
  • secondly, even if I would have a good development environment for javascript, this still leaves me in the cold, for linking server side with client side easily.

Ideally, I would like to write server side code and client side code in c#,  sharing some code to let me write the integration between them. Eg. the parameter object for my plugins would be a class I can use server side and client side.

One could see it as some kind of mix between MVC and Webforms, where the c# code for the client could be seen as a form of code behind for my view (but only and ONLY for writing display related code, NO business code!!). I realize that what I'm describing is kind of what Silverlight does. But I'm not convinced of Silverlight yet.

So I welcome any good ideas, links to other projects, which can help me in solving this problem... ASP.NET MVC is currently my choice of server side solution, so any ideas should work well with it!

Friday, November 6, 2009

ScriptSharp discussion group

ScriptSharp is a project from Nikhil Kothari, which let's you write c# code, that translates to javascript.
There are some benefits and drawbacks, but being able to have code completion, compile time checking etc... is in my opinion worth the effort.

In order to be able to exchange information about usage and news of scriptsharp, I started a discussion group on google groups : http://groups.google.com/group/scriptsharp_coding

Feel free to join in if you're intrested on this matter.

Tuesday, October 27, 2009

Extending visual studio : Addin with custom toolbar

Recently I started writing my first Visual Studio Addin. You can find several good examples on the internet, but I found it hard to find any on how to add a custom toolbar. Most of the examples I've seen, show you how to add a single menu item to the tools menu in Visual Studio. Want I wanted to do, is to create a toolbar to access the features in the addin. So maybe this article can give you some additional information, on how to create and use a toolbar in your own addin. This article assumes some basic understanding of addins. However, once you've created the basic setup, adding additional commands will be quite easy.

I'll start by creating a simple addin step by step, and show you how to create a toolbar and add some buttons linked to functionality provided in the addin.

I'll use the builtin project template provided by VS2008. An alternative is to use the Visual Studio SDK, but this is not the scope of this article.

You start with File/New project, then choose Other Project Types, and finally choose the Visual Studio Add-in project template. Type the name of your addin you want to create, eg. MyAddin. This will start a wizard which will allow you to set some options on how the addin will be created.

The first option is to choose the Programming Language. I'll choose c# as language.
The next option, determines what applications will host your addin. The options available here, will depend on your installation, but basically there will be at least 2 options:
  • Microsoft Visual Studio 2008
  • Microsoft Visual Studio 2008 Macros
For the example I'm building, I will only select Visual Studio 2008.

Next you need to give a name and description of the addin. I'll just name it MyAddin and as description MyAddin - VS2008 extension.

The next page of the wizard will ask you whether you want:
  • to create command bar ui for your addin (it will create a tools menu item), so check this
  • to load the addin when VS2008 starts ( we'll check this one also)
  • if the addin will never put up modal ui (we'll leave this one unchecked)
Next you can add about box information if you want. I'll leave this one unchecked.
Finally, you'll get a summary of all the options you've selected and you can finish the wizard.

When you'll look at the files created by the wizard, you'll find as most important files
  • Connect.cs, which is the file we're going to work with most.
  • MyAddin - For Testing.Addin which is a XML file
  • MyAddin.Addin another XML file
  • CommandBar.resx a resource file containing some language dependent resource strings.
The files with the extension .Addin are configuration files for VS2008, which determine how your plugin will be loaded. There's one used for debugging purposes and one for deployment.

Let's look at the code generated in connect.cs. First we'll look at the OnConnection method, and make some changes to it, so we can create our toolbar, instead of adding an menu item to the tools menu (the default created by the wizard).

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            _applicationObject = (DTE2)application;
            _addInInstance = (AddIn)addInInst;
            if(connectMode == ext_ConnectMode.ext_cm_UISetup)
            {
                object []contextGUIDS = new object[] { };
                Commands2 commands = (Commands2)_applicationObject.Commands;
                string toolsMenuName;

                try
                {
                    //If you would like to move the command to a different menu, change the word "Tools" to the
                    //  English version of the menu. This code will take the culture, append on the name of the menu
                    //  then add the command to that menu. You can find a list of all the top-level menus in the file
                    //  CommandBar.resx.
                    string resourceName;
                    ResourceManager resourceManager = new ResourceManager("MyAddin.CommandBar", Assembly.GetExecutingAssembly());
                    CultureInfo cultureInfo = new CultureInfo(_applicationObject.LocaleID);

                    if(cultureInfo.TwoLetterISOLanguageName == "zh")
                    {
                        System.Globalization.CultureInfo parentCultureInfo = cultureInfo.Parent;
                        resourceName = String.Concat(parentCultureInfo.Name, "Tools");
                    }
                    else
                    {
                        resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Tools");
                    }
                    toolsMenuName = resourceManager.GetString(resourceName);
                }
                catch
                {
                    //We tried to find a localized version of the word Tools, but one was not found.
                    //  Default to the en-US word, which may work for the current culture.
                    toolsMenuName = "Tools";
                }

                //Place the command on the tools menu.
                //Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
                Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];

                //Find the Tools command bar on the MenuBar command bar:
                CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
                CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

                //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
                //  just make sure you also update the QueryStatus/Exec method to include the new command names.
                try
                {
                    //Add a command to the Commands collection:
                    Command command = commands.AddNamedCommand2(_addInInstance, "MyAddin", "MyAddin", "Executes the command for MyAddin", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

                    //Add a control for the command to the tools menu:
                    if((command != null) && (toolsPopup != null))
                    {
                        command.AddControl(toolsPopup.CommandBar, 1);
                    }
                }
                catch(System.ArgumentException)
                {
                    //If we are here, then the exception is probably because a command with that name
                    //  already exists. If so there is no need to recreate the command and we can
                    //  safely ignore the exception.
                }
            }
        }
The OnConnection is called when the addin is loaded. This will allow you to setup the addin and is also the place where our toolbar will be created. We'll remove the code marked by the dark yellow background, as we don't want to create a menu item in the tools menu. We'll replace it with code which will create our toolbar.

Replace the code with :

                        AddTemporaryUI();

There are two ways to create toolbars, permanent toolbars and temporary toolbars. From what I've read in other blogs, mostly you'll use temporary toolbars, which are created when you're addin loads.
Now add the following code to the class  Connect:

        private CommandBar myTemporaryToolbar;


        private void AddTemporaryUI()
        {
            CommandBars commandBars = null;
            CommandBarButton myToolbarButton = null;
            Command myCommand = null;

            try
            {
                Commands2 commands = (Commands2)_applicationObject.Commands;

                commandBars = (CommandBars)_applicationObject.CommandBars;
                object[] contextGUIDS = new object[] { };
                string progid = _addInInstance.ProgID;

                myTemporaryToolbar = commandBars.Add("MyAddIn.Connect.Toolbar", MsoBarPosition.msoBarTop, false, true);

                foreach (var item in Actions)
                {
                    myCommand = null;
                    try
                    {
                        myCommand = _applicationObject.Commands.Item(item.Key, -1);
                    }
                    catch
                    {
                    }
                    if (myCommand == null)
                    {
                        myCommand = commands.AddNamedCommand2(_addInInstance, item.Value.Name, item.Value.Text, item.Value.Description,true, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
                    }

                    myToolbarButton = (CommandBarButton)myCommand.AddControl(myTemporaryToolbar, myTemporaryToolbar.Controls.Count + 1);
                    myToolbarButton.Caption = item.Value.Text;
                    myToolbarButton.Style = MsoButtonStyle.msoButtonCaption;
                }
                myTemporaryToolbar.Visible = true;
            }
            catch
            {
            }

        }
This code will create the toolbar for all commands you want to provide. As you will see next, I will store all available commands in a dictionary. But first we'll create our ExtCommand class:

Add a new class to the project, and call it ExtCommand.cs, which is defined as follows:
    public class ExtCommand
    {
        public string Name { get; set; }
        public string Text { get; set; }
        public string Description { get; set; }
        public Func<bool> Action { get; set; }
    }

  • The Name property will determine the name of the command used by VS2008 to call your addin.
  • The Text property will determine the text of the toolbar button
  • The Description property will show up as tooltip explaining what the command does.
  • The Action property is a delegate returning a bool, linking the toolbar button to the code which you want to excute when the button is pressed.
 Now lets create our dictionary. Add a property Actions to the Connect class as follows:

        private Dictionary<string, ExtCommand> _actions;

        public Dictionary<string, ExtCommand> Actions
        {
            get
            {
                if (_actions == null)
                    _actions = new Dictionary<string, ExtCommand>
                    {

                    };

                return _actions;
            }
        }

As we create new commands in our addin, we'll add them to the dictionary (which is empty to start with).
We create now our first method, eg. SurroundWithBraces. This already exists in VS2008, but just to have a simple example, we'll create one ourselves.

        private bool SurroundWithBraces()
        {
            try
            {
                TextSelection sel = (TextSelection)_applicationObject.ActiveDocument.Selection;
                sel.Text = "{" + Environment.NewLine + sel.Text + Environment.NewLine + "}";
                return true;
            }
            catch (Exception)
            {
                return false;
            }

        }


This will take the current selected text and replace it with the same text, but surrounded with braces. Notice the try catch, which will ensure our addin will not cause VS2008 to crash.

Now we need to link the commandName to our private method. Create an entry in the dictionary for this command. Just add a dictionary entry as follows:

                    _actions = new Dictionary<string, ExtCommand>
                    {
                        {"MyAddIn.Connect.Braces",new ExtCommand
                           {
                              Name="Braces",
                              Text="ExtBraces",
                              Description="Surround selected text with braces",
                              Action=SurroundWithBraces
                            }
                         }

                    };


MyAddIn.Connect.Braces is the string which VS2008 will send as commandname parameter to the Exec method. Commandnames will alway start with MyAddIn.Connect follow by the name of your command. So if the name property of our ExtCommand object is Braces, the commandName will be MyAddIn.Connect.Braces. It's important that they are the same.

Next we have to change the QueryStatus method. This method will be called by VS2008 to query if a command with a specific commandName is supported by our addin. Initialy it uses an if structure, to compare the commandName to available commands, but because we've used a dictionary, the code can be replaced by:

        public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
        {
            if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {

                if (_actions.ContainsKey(commandName))
                {
                status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported |                                             vsCommandStatus.vsCommandStatusEnabled;
                        return;
                }

            }
        }

We just have to check if the commandName exists in our dictionary, to determine if our addin supports the commandName VS2008 is querying. Any commands added to the dictionary will automatically be returned as supported.

Executing a command is done inside the Exec method, called by VS2008 when the user clicks a button on the toolbar. Again, initially, the code generated by VS2008 uses an if structure, to determine the method to execute. Our dictionary simplifies this code considerably:

        public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
        {
            handled = false;
            if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
            {
                if (_actions.ContainsKey(commandName))
                {
                    _actions[commandName].Action.Invoke();
                    handled = true;
                    return;
                }
            }
        }


_actions.ContainsKey, checks if the commandname exists in our dictionary. If this is true, we'll invoke the Action (a delegate to our private method), associated to the commandName  (_actions[commandName].Action.Invoke()). It looks up the entry in the dictionary, returns the ExtCommand object. The Action property of our ExCommand object contains a delegate to our private method. Invoke just calls this method.

Almost there. We need to add another call to AddTemporaryUI() inside the method OnStartupComplete :

        public void OnStartupComplete(ref Array custom)
        {
            AddTemporaryUI();
        }


And finally, the OnDisconnection method has to be implemented, to remove our toolbar, when the addin is removed :

        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            try
            {
                switch (disconnectMode)
                {
                    case ext_DisconnectMode.ext_dm_HostShutdown:
                        break;
                    case ext_DisconnectMode.ext_dm_SolutionClosed:
                        break;
                    case ext_DisconnectMode.ext_dm_UISetupComplete:
                        break;
                    case ext_DisconnectMode.ext_dm_UserClosed:
                        if (myTemporaryToolbar != null)
                            myTemporaryToolbar.Delete();
                        break;
                    default:
                        break;
                }
            }
            catch
            {
            }
        }



Adding additional commands, is very simple from here on... create a private method implementing the command. Add an entry to the dictionary and you're done. The rest is taken care of automatically. Remember the Name property of your ExtCommand object, will determine the commandName VS2008 will use. Just prefix it with MyAddin.Connect where the commandName is used as the key in the dictionary.

I want to give credit to Carlos J. Quintero (Microsoft MVP), who wrote an article Howto: adding buttons, commands and toolbars to Visual Studio .NET from an addin providing for the base of the AddTemporaryUI method. It's is certainly worth reading!!