Sunday, January 31, 2010

Add-In Pipeline Development.

Recently I was on a project related to developing an extensible application.
.Net Framework provide many programming models for creating an extensible applications , some of them are Managed Extensibility Framework, Visual Studio Tools for Applications and Add-in Pipeline Development.

Visual Studio Tools for Application and Addin-Pipeline development leverages the Add-in development model whereas MEF uses the Dipendency Injection to extend application through extension compostion. The project I worked on was related to Visual Studio Tools for Application development. Major part of pipeline development for Host and Add-In is automated in VSTA and pipeline components are automatically managed by VSTA.

Other then VSTA we can develop the pipline for Add-In framework to work in our project from scratch. Extensible application are called Host that uses the service of Add-In's to extend themself. Add-In's are activated in Host application and extends the features or services of the Host application. So , there are two parts ,first the Add-In that provides the services to the Host and the Host application that consumes the services of Add-In.

The communication between the host and the Add-In is carried out by the pipeline that has to be created manually , although tools are available to achive this (VsPipeLine Builder). The pipeline is implemented by using the types in the System.AddIn, System.AddIn.Hosting, System.AddIn.Pipeline, and System.AddIn.Contract namespaces. The Host and Add-In are at the two end of the pipeline. Host application exposes the Object model that Add-In will use to extend the Host. So, both the Host and Add-In should share a comman Object model .
This is achived by a Contract , an interace that contains the method that both Add-In and Host will use . Contract is the abstraction between Host and Add-In through which both exchange 'types' for communication. Types that are communicated between both of them should be Contracts or Serializable .

Lets see the components of the pipeline between Host and the Add-In. We have seen the Contract that is the centeral component of the pipeline. Next there are abstract classes or Interfaces that defines the views of object model used to communicate ( As defined by Contract ), as seen by Add-In and the Host. Both these views are identical , having same members but differs in Attributes applied to them (we will see them later) .

These views represent object types and methods used to communicate as seen by the Add-In and Host. Now we have the Contract that define the protocol of communication between the Add-In and Host, we have the views that Add-In and Host have of Object Model.



The components that are missing are the components responsible for the conversion of the view to contract and contract to view.These component are called the Adapters , Host side adapter and Add-In side adapter. Lets see the communication from Add-In to Host . First the Add-In view of types are converted into contracts to pass to Host by Add-In side adapter .After the contracts are made by the Add-In side adapter , the host side adapter takes on and converts these contracts to the Host side view .In this way the serialized types are passed to the Host by Add-in.
That was the theory part , in next blog we will see the practical implementation.

Saturday, January 30, 2010

Linq-2-DataSet

In the previous blog I looked into the Linq-2-Sql , this time its Linq-2-DataSet. In .Net 3.5 Linq-2-DataSet support is fully implemented in the assembly System.Data.DataSetExtensions.dll .

To take advantage of this we have to include this assembly into our project. Filling up dataset can be done by any method , most frequently SqlDataAdapter is used .
While querying DataSet with Linq , we query the DataRow collection in the DataTable. Like other datasources that we query through linq , in Linq-2-DataSet we actually enumerate over the collection of DataRow object, so we have all the member of DataRow available for query expression.

Lets assume that we have DataSet filled with the Customers table data objects. From this dataset we actually enumerate over the table Customers.
So the first step is to make this DataTable enumerable, there are extention methods that helps us to achive this - ToQueryable() / AsEnumerable().

var query = _dsCustomers.Tables[0].ToQueryable();
var query = _dsCustomers.Tables[0].AsEnumerable();

These methods convert the DataTable as the datasource for the Linq.Lets see an example.

var custRow = (from cust in _dsCustomers.Tables[0].ToQueryable()
where cust.Field<string>("CustName") = = "Amy"
select cust).SingleOrDefault();


Here we used the Field method to access the DataColumn in the DataRow of Customers table , we could have also used default accessor cust["CustName"].
But with the default column accessor we would have to cast the column value into appropriate datatype and check for the null if the column is nullable. The Field method as we can see is generic type, we do not have to cast it and it also supports the nullable types.

Lets look at more complex one :-

var query = from cust in _dsCustomers.Tables[0].AsEnumerable()
join ord in _dsCustomers.Tables[1].AsEnumerable()
on cust.Field<int>("CustiId") equals ord.Field<int>("Ord_CustId")
where ord.Field<string>("Ord_OrderItem") == "NetBook" &&
ord.Field<datetime>("OrderDate").Month == 8
select new
{
CustName = cust.Field<string>("CustName"),
OrderId = ord.Field<int> ("Ord_OrderNo"),
CustId = cust.Field<int> ("CustId"),
OrderItem = ord.Field<string> ("Ord_OrderItem")
};

If we have the relationship defined between the tables we can use it as :

ds.Relations.Add("OrderRelation",dsCustomers.Tables[0].Columns["Ord_CustId"], dsCustomers.Tables[1].Columns["CustId"]);

var query = from cust in _dsCustomers.Tables[0].AsEnumerable()
from ord in _dsCustomers.Tables[1].GetChildRows("OrderRelation")
where ord.Field<string>("Ord_OrderItem") == "NetBook" &&
ord.Field<datetime>("OrderDate").Month == 8
select new
{
CustName = cust.Field<string>("CustName"),
OrderId = ord.Field<int>("Ord_OrderNo"),
CustId = cust.Field<int> ("CustId"),
OrderItem = ord.Field<string> ("Ord_OrderItem")
};

In the above queries we reterived the filtered datarows in the varirable 'query' , now we can iterate through these rows or query them. Previously there was the method that allowed us to convert these anonymous type datarow collection in to datatable ( ToDataTable(), another one to load query data into datatable LoadSequence(), now removed ) , but now we only have CopyToDataTable() method that converts the strongly typed DataRow collection into datatable. Here we must know the type of datarow in the collection to convert them into datatable.

var query = from cust in _dsCustomers.Tables[0].AsEnumerable()
where cust.Field<string>("CustName").StartsWith("A")
select cust;

DataTable newDataTable = query.CopyToDataTable()

We can also convert the query to a DataView and bind that to any control of WPF (ListBox, WpfToolKit Grid etc..). Here also the type of the DataRow should be known , as the method AsDataView() is generic method same as CopyToDataTable().

dataGrid1.DataSource = query.AsDataView() .

We can use other extension methods to compute the datarow collection. We have reterived our rows from the above linq queries in 'query' vairable , now lets perform some of computation on these rows. Almost all the computation extension method takes a delegate as a parameter to perform computaion on. Lets start with Max method.

int lowestRank = query.Where(r => r.CustName.StartsWith("A")).Max( r => r.CustRank);

Sum for a particular Datacolumn.

int sumTotalSalary = query.Where(r => r.DeptId == 10).Sum(r => r.CustSalary);

Average :-

double averageSalary = query.Where(r => r.DeptId == 10).Average(r => r.CustSalary);

GroupBy:-

var grpRows = query.GroupBy(r => r.DeptId);

OrderBy:-

var grpRows = query.OrderBy(r => r.DeptId);

We can futher explore all the posibilities that exists with Linq-2-DataSet.

Tuesday, January 26, 2010

LINQ 2 SQL

Linq has been introduced with the release of .Net 3.5 . Its has changed the way how we code against various data sources. It comes with full type-safety, intellisense support, compile-time checking and various other tools like visualizers for expression trees, orm's etc. Linq is fully extensible , beside the datasources that Microsoft lets you to query with linq , linq has many extended versions like Linq to Amazon, Linq to Google etc.


Linq to Xml, Linq to Objects, Linq to Sql, Linq to Ado.Net, Linq to Entities are some of the example of Linq implementation. Linq query are supported by the collections that implement's IEnumerable and IQueryable interfaces. IEnumerable is basically used to work with in-memory data collections like Linq to Objects, Linq to Sql etc.


IQueryable is used where we want to run a query against a data provider.Here we can pass a structure of query expression to data provider over the network which may in turn convert it into Sql or any other language to execute. Example's are Linq to Sql , Linq to Entities.


In this blog I will be focusing on the Linq to Sql and Linq to DataSet. Linq to Sql in Visual Studio is an ORM .It models the relational database and creates the classes based on that.These are the classes that you will be going to run your query against.All the transactions going between the actual database and your modeled classes are wrapped, so you could simply execute and query against these classes. To create Linq to Sql project we have to:



  • Create a new Project of a type that you want to implement Linq to Sql into.

  • Open the Database that you want to model in the Server explorer window.

  • Select Add New Item to open New Item Dialog box. Select linq to Sql classes from dialog.

  • Name the class and select ok. A dbml file with three other file will be created in solution explorer.

  • A ORM designer will be now opened in Visual Studio.Drag and Drop the tables from database opened in the Server Explorer to the ORM designer.


This is the basic setup for the creation of a Linq to Sql project. Lets see the files created along with .dbml file , they are .Designer.cs , .dbml.layout, .dbml.diagram. Out of these files .Designer.cs files which is a partial class, is most important to us. This is the file that contains the modeled relational database, we can see the main class that inherits the System.Data.Linq.DataContext class and other classes that maps to our tables in the database .These mapped classes implements INotifyPropertyChanged and INotifyPropertyChanging interface for property change tracking. WPF developers will be quite familiar will property changed tracking mechanism.

Lets see how to use these classes for our transaction with DB.
We can query databases for the records with all kind of filters and aggregations .The method here queries the database for the list of customers who ordered a particular item.

public IEnumerable GetCustomerByOrderId(int itemsId)
{
using (DataClasses1DataContext cntx = new DataClasses1DataContext())
{
IEnumerable customerCollection =
from cust in cntx.Customers
from ord in cntx.Items
where cust.CustiId == ord.Items
_CustId && ord.Items_OrderNo == itemsId
select cust;
return customerCollection;
}
return null;
}

We can insert records in the database.Here we insert a single customer record in Customers table.

public void AddCustomers(Customer customer)
{
using(DataClasses1DataContext cntx = new DataClasses1DataContext())
{
cntx.Customers.InsertOnSubmit(customer);
cntx.SubmitChanges();
}
}

Delete the record from database .Here we delete the record from the database.

public void DeleteCustomer(int custId)
{
using (DataClasses1DataContext cntx = new DataClasses1DataContext())
{
Customer objCustomer = (from cus in cntx.Customers
where cus.CustiId == custId
select cus).SingleOrDefault();

//We can use Lambda
//objCustomer = cntx.Customers.Where(c => c.CustiId ==
//custId).SingleOrDefault();

cntx.Customers.DeleteOnSubmit(objCustomer);
}
}

Update the database. Here we update the customers table.

public void UpdateCustomer(Customer customer)
{
using (DataClasses1DataContext cntx = new DataClasses1DataContext())
{
Customer objCustomer = (from cus in cntx.Customers
where cus.CustiId == customer.CustiId
select cus).SingleOrDefault();

// We can use Lambda
// objCustomer = cntx.Customers.Where(c => c.CustiId ==
// custId).SingleOrDefault();

//Update Address and the City
objCustomer.CustAddress = customer.CustAddress;
objCustomer.CustCity = customer.CustCity;
cntx.SubmitChanges();
}

}

Besides these all, we can directly execute a command or a query against the database thanks to the ExecuteCommand and ExecuteQuery methods of DataContext class. We can simply pass string command and parameters to these methods.By default the query-string is Sql-Injection proof as it uses the exec_sql on server.

using (DataClasses1DataContext cntx = new DataClasses1DataContext())
{
cntx.ExecuteQuery("Select * from Customers where custId = '{0}'","11");
cntx.ExecuteCommand("Update Customers set CustName = '{0}' where CustId = '{1}'", "MyName","22");
}

In the next post we will look into Linq to DataSet.Happy coding.

Sunday, January 24, 2010

Visual Studio CommandBars and Commands

This blog is about Visual Studio Extensibility. Recently I was at the task of providing my own menuitems in the Visual Studio and catching the events generated by default Visual Studio toolbar buttons.

In Visual Studio Extensibility api DTE / DTE2 are the application objects through which we can access the Visual Studio CommandBars like Tools,File, Edit etc. Add-In,Vba, Vsta developers are probably familar with the DTE/DTE2 application object. DTE not only provide access to the commandbars but whole set of Visual Studio features.

We can access the solution opened in the VS, we can access projects in the solution and there properties.We can set debug paths, reference paths , project types and all lots of thing.

But this blog is about CommandBars and Commands. CommandBar object is the main menu that is in VS like Tools, Debug, File etc, then there is CommandBar Controls and CommandBar buttons which are the menuitem for the main menu. To access the CommandBars we should have the application object DTE. It is provided as a parameter (object application) in OnConnection method of the Add-In project.

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
}

It can also be accessed in VSTA through :

IDTEProvider provider = (IDTEProvider)new VSTADTEProviderClass();
EnvDTE.DTE _dte = (EnvDTE.DTE)provider.GetDTE("HostName", 0);

Now we have our DTE object , we can start accessing the CommandBars of Visual Studio. DTE object exposes the CommandBars property that contains the list of all avialable Command Bars within the VS. Lets get the Tools Command Bar.

CommandBars commandBars = this._dte.CommandBars as CommandBars;
CommandBar toolsMenuBar = ((CommandBars)this._dte.CommandBars)["Tools"];

Adding the Command Bar button to the Tools CommandBar is simple , just call the CommandBar.Controls.Add method with right parameters, this will return CommandBarControl object and now cast the CommandBarControl in the CommandBarButton. CommandBarButton have many properties that we can set, some of useful ones are set in the following code.

Where to set the CommandBar Button, is it temporary, its type (PopUp, DropDown) all can be set by the parameters passed on to the Add method.

CommandBarControl myControl = toolsMenuBar.Controls.Add (MsoControlType.msoControlButton, 1, "", 4, true);
CommandBarButton myButton = reloadControls as CommandBarButton;
myButton ols.Caption = "My Button"; // Menuitem name
myButton .Visible = true; //Visible property
myButton .BeginGroup = true; // Gets the seperator for menuitem
myButton .FaceId = 0319; // icon to show
myButton .Enabled = false; // Enabled
property.

Now we can bind a event handler to this custom CommandBar Button and perform our custom action.
myButton.Click += new _CommandBarButtonEvents_ClickEventHandler(myButton_Click);

The default buttons of VS, on there click perform certain actions like opening New Project Dialog, Open Dialog etc. These actions are invoked by the Visual Studio Commands which are in turn invoked by click event of CommandBarButtons.
Commands are not the UI elements but way by which VS execute particular action.
To get the events of these commands we should know the GUID and ID of the VS Commands.

EnvDTE.CommandEvents newProjectEvents = this._dte.Events.get_CommandEvents("{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 216);

How to get these Guid's and Id's ?. We can loop through DTE.Commands collection to find our Command and Guid,Id associated with it.

internal void FindGuid()
{
string commandName = String.Empty;
string commandGuidNewProject = String.Empty;
string commandGuidOpenProject = String.Empty;
int commandIdOpenProject = 0;
int commandIdNewProject = 0;
EnvDTE.Command command;
for(int i = 1; i < m_dte.Commands.Count; i++)
{
command = m_dte.Commands.Item(i, i);
commandName = command.Name;
if(commandName == "File.NewProject")
{
commandGuidNewProject = command.Guid.ToString();
commandIdNewProject = command.ID;
}
if(commandName == "File.OpenProject")
{
commandGuidOpenProject = command.Guid.ToString();
commandIdOpenProject = command.ID;
}
}
}

The CommandEvents that we accessed through the Guid /Id of VS command have many events with which we can bind our event handlers. Events which we are interested in are AfterExecute and BeforeExecute, these are fired after and prior to the execution of the Command action.

newProjectEvents.BeforeExecute+= new _dispCommandEvents_BeforeExecuteEventHandler(newProjectEvents_BeforeExecute);

newProjectEvents.AfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(newProjectEvents_AfterExecute);

We have seen how to add our cutom command bar button , bind its click event and how to bind to the events of VS Commands.Hope you will find something useful out of this blog.


Friday, January 15, 2010

Creating Project Template in Visual Studio

Visual studio provides us with option to create Project template and show them in the New Project Template Dialog Box.In addition we can define our own logic on opening these templates with help of wizard interface ( IDTWizard ).
In this post i will be showing steps to make it happen.

Staring point for creating our project template is VSDIR and VSZ files .VSDIR is a text file that tells the New Project Dialog box how to display our project template , its display name,order in dialog box and the icon associated with it.VSZ files define the wizard class to invoke for logic and parameters to provide to the wizard class.Relative path of these vsz files are defined in the VSDIR file along with other parameters.
Lets look at the conent of VSDIR file:-


Template.vsz|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|My Template|70|Template CS|D:\Helper Projects\Helper Projects\SatelliteAssembly\IconResourceDll.dll|102||


All the parameters are seperated by pipe (|).

  • First parameter define the vsz file , in this case it is in the same folder as the VSDIR file.

  • Next is the product GUID (vc++,c# etc) containing localized resources for the product.

  • Display name of the template as it will be shown in New Project Dialog.

  • Sort priority , 1 being the highest.(Template be shown next to all the template with same priority)

  • Discription of the Template.

  • Path of the associated Icon resource dll.

  • Icon resource Id.

  • Flags

  • Suggested Base name.
We have to create satellite assembly for icon resources and our project template that will open on New Project item in invocation.

Lets see VSZ file.


VSWIZARD 7.0
Wizard={BAA02C12-00F5-4e74-A6AF-AEC6930AC067}
Param="TemplateCS"

First parameter in VSZ file defines the Visual Studio Enviroment template version, next is the guid of the wizard class containg the logic for opening the template, then the parameters to pass to the wizard class.

Now after creating these files we have to put them in specific location , the path is

[WinDrive]:\Program Files\Microsoft Visual Studio 10.0\VC#\CSharpProjects

OR

[WinDrive]::\Program Files\Microsoft Visual Studio 10.0\VB\CSharpProjects

Now if we check by opening the visual studio and opening the new project dialog box , we will find our template there. Next step is to create the wizard class that will handle our project opening logic , remember we have put the guid of this class in the VSZ file. Creating the wizard class start's with adding reference to the Envdte from Envdte.dll that contains the IDTWizard interface .Create a new class library project and define your wizard class.Now we add envdte namespace to our class and implement the IDTWizard .IDTWizard is the interface that makes our class a wizard.There is single method to implement Execute, this is the method that is called when our template is invoked from the New Project Dialog box .

[ComVisible(true)]
[Guid("BAA02C12-00F5-4e74-A6AF-AEC6930AC067")]
public class TemplateWizard : IDTWizard
{

[ComVisible(true)]
public void Execute(object Application, int hwndOwner, ref object[] ContextParams, ref object[] CustomParams, ref wizardResult retval)
{

}

}

We have marked our class ComVisible so that com clients can access our managed class , we have also defined the guid attribute with a guid that we have referenced in the VSZ file.This guid is the way how the VS know which class to call when the template is selected.

Execute method have parameters that define :-

  • The Visual Studio Automation Model object .(DTE)

  • Parent handle of the wizard class.

  • Context parameters array .

  • Custom parameters array.The array of the parameters that we have defined in the vsz file.

We can use the EnvDte.Dte object passed on as parameter to open our project (.csproj / .vbproj)in VS . Method provided by the DTE is AddFromTemplate that takes on parameters

DTE.Solution.AddFromTemplate( param1 , param1,param1 ,param1 )

  • Filename and full path of the template file with extension .(vstemplate file)

  • Destination path where to create this project.

  • Project Name

  • Bool describing whether to open the project in current or new solution.

We can also define logic to find out that if the project already happens to be at destination path and open that project instead of creating new one.

DTE.Solution.AddFromFile(openProjectPath, true);

Now before adding our project to the VS we can define whole set of logic to happen.Most comman of all is altering our class files in project that we are about to open. We can define namespace , class names and all other kind of custom code depending on certain criteria prior to opening the project in VS . We can do a lot of things based on our project need , like call some service, open a dilog box (WPF), add references to project , load controls to the toolbox in VS etc.

After we have created our wizard class , we have to register the assembly so that VS could locate our class when our template is invoked from the New Project Dialog. The way to do this is through Regasm utility with codebase option.

:> Regasm /codebase [path of our wizard dll]

After our type is registered we are all set to create new project from our project template.