Introduction
Whenever I'm developing an application, I always find it easier to use a control or library that someone else has already written rather than to try to do it myself. That's why I, and no doubt many of you, come to the Code Project - because it's a fantastic resource for ready made components. However, when you get here, you have to trawl through to find what your looking for, download the source and the demo project, build them to make sure they work, then copy them somewhere useful, then add them to your project and then you can start to use it.
This is where Code Store comes in. Code Store is an add-in providing you with instant integrated access to an online repository of .NET components. All of the components are already built and ready to use; all Code Store does is download the ones you ask for and then automatically adds them to the toolbox ready for you to use in your project.
History
- Version 1.0 (25th June 2003): Initial release.
- Version 1.1 (25th June 2003): Fixes a few bugs with regard to startup.
- Update (27th June 2003): .NET Framework 1.0 version. Full setup available from here.
- Update (27th June 2003): Article updated with more information about the VS.NET integration and the XML file.
- Version 1.2 (30th June 2003): Added proxy server support (many thanks to Alex Kucherenko for his help).
- Version 2.0 (9th July 2003): Complete revamp of everything (see below).
- Version 2.0 SP1 (11th July 2003): Fixed download path bug (thanks to Matt Dixon).
- Version 2.0 SP2 (11th July 2003): Fixed startup exception bug (thanks to Marc Merritt). Full version number is 2.0.1287.27032.
- Version 2.1 (15th July 2003): Added support for non-UI components and a custom uninstall action.
- Version 2.1.1298 (22nd July 2003): Added support for compressed files and components that are dependent on other libraries. Also included support for multi-project solutions. Full version number is 2.1.1298.15694.
Announcements
16th September 2003
Having rethought my earlier statement (below) and my current circumstances, I have decided that I do not have the financial resources to be able to support such a venture. I am therefore offering CodeStore to CodeProject as a free and exclusive service to all CodeProject members. I am currently waiting to hear from Chris Maunder, which has caused delays to the development. Development has now restarted as I am keen to be able to provide something to the #Develop team as soon as possible.
The web site design has been revamped, courtesy of Movable Type (back-end) and Paul Watson (new layout). The RSS feed has changed to this.
16th July 2003
I am currently considering the possibility of leaving my job and concentrating on the development of Code Store. I believe that it has real potential, especially once we have reached the stage where UI and non-UI components are supported as well as ASP.NET Web Controls. In order to make this happen, I would need to make some kind of charge. I don't think selling the software itself is the way to go, I think that having a subscription based service that allows users to download components is a better approach. I am currently thinking of somewhere in the region of £10 per year as the subscription fee at the entry level to allow access to free components (like those available here at the Code Project). Later, higher level subscriptions could be introduced that provide access to professional components like those produced by Dundas.
In order to protect Code Store, updates to the source code will no longer be made available for download. The source for version 2.0 is (and will remain) available for download. Updates and new releases to the software will continue to be made available here.
Getting Started
To get started, just download one of the setup projects (see links at the top of the article), and install Code Store. Once installed, go to the Tools menu and choose "Code Store". This will download an XML file that lists the available components, which is then parsed to display a list to you. Select the components you want and click on download. After each component has completed, it is added to a tab called "Code Store" in the toolbox.
How It Was Done
As with most of my work of this sort of scale, I started off with some design. I always start off with a Use Case diagram as I find it a good, clear way of representing the requirements from a user's point of view and I can always keep referring back to it to check I'm still going the right way.
Figure 1 - Use Case Diagram Showing Add-in Use
Having developed Code Store to its initial release and on to version 1.2 in order to meet the competition deadline, it was then time to learn from what I had done and designed, then re-write it all. This gave rise to version 2.0, which is separated into three areas: interaction with Visual Studio, file downloads and the user interface. This structure is illustrated in the following package diagram:
Figure 2 - Package Diagram Showing Overall Structure
The following set of diagrams present each of the packages in the add-in:
Figure 3 - Class Diagram for the Salamander.Addins.CodeStore Namespace
Figure 4 - Class Diagram for the Salamander.Addins.CodeStore.Engine Namespace
Figure 5 - Class Diagram for the Salamander.Addins.CodeStore.UserInterface Namespace
The add-in contains a single command that when executed first downloads the component list XML file from the server. This XML file is parsed and then the details are added to a ListView
control and displayed to the user with checkboxes. The user ticks the checkbox for each component they want to download and then, in turn, each component is downloaded. The progress event is used to display current download progress.
The download complete event is then used to add the control to the CodeStore tab on the toolbox (see Points of Interest below).
There are essentially two parts to the add-in: the first is the interaction with Visual Studio and the second performs the file downloads.
Visual Studio Interaction
The add-in is setup and configured during the OnConnection
event. The command is only added to the menu during UI setup (connectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup
), which occurs the first time the add-in is loaded after installation to enable users to customize their user interface without having it reset each time the add-in loads. This UI setup phase is determined for each add-in based on a value for each add-in in the HKCU\Software\Microsoft\VisualStudio\7.1\PreloadAddinState\
key. If the value (e.g. Salamander.Addins.CodeStore.Connect
) is '1
', then the user interface has yet to be initialized, if it is '0
', then user interface initialization has already occurred.
Having added the command to the Tools menu, the add-in then looks to see if the Code Store tab already exists in the toolbox; if it doesn't, then one is created. All user interface components downloaded by Code Store are added to the Code Store tab on the toolbox. This occurs even if no solution is loaded.
ToolBoxTab toolBoxTab = null;
try
{
Window win =
applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindToolbox);
ToolBox toolBox = (ToolBox)win.Object;
ToolBoxTabs toolBoxTabs = toolBox.ToolBoxTabs;
for (int i = 1; i < toolBoxTabs.Count; i++)
{
if ("Code Store" == toolBoxTabs.Item(i).Name)
{
toolBoxTab = toolBoxTabs.Item(i);
break;
}
}
if (null == toolBoxTab)
{
toolBoxTab = toolBoxTabs.Add("Code Store");
}
The remaining interaction with Visual Studio comes once a component has been downloaded. Once the file has been downloaded, that component is added to the CodeStore tab on the toolbox. This is done as follows:
this.toolBoxTab.ToolBoxItems.Add(comp.Name, strPath,
EnvDTE.vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
comp.Name
is the name of the component, defined by the Name
item in the XML file, which is the label displayed in the toolbox;
strPath
is the path to the downloaded file, which uses the FileName
item in the XML file;
- The final parameter determines what is being added to the toolbox, in this case, a .NET Component. According to the documentation, this will add "all classes within the library" to the toolbox.
For a non-user interface component (supported since version 2.1), an assembly reference is added to the first project in the solution, if one is currently loaded.
File Downloads
The process involved in downloading the files is very simple, performing each download, one after the other in a separate thread to keep the user interface responsive. The download classes were originally Ray Hayes' WebDownload class. Though these have been re-written from scratch, they are still fairly similar. Ray's article describes the download process and so I have not reproduced it here. The class diagram for the Salamander.Net
namespace containing the WebDownload
class is as follows:
Figure 6 - Class Diagram for the Salamander.Net Namespace
The XML File
A very simple XML file is used to transfer the component information. It is simply stored on the CodeStore web server and downloaded by the add-in each time the components list is displayed. My original hope was that MySQL (the current database of components) would be able to export the table contents in well-formed XML. Unfortunately, it incorrectly closes each tag (it does not include the '/') and there is no container for each row, so some manual editing is required first. My hope is that in time the back-end could be ported over as some kind of web service running off SQL Server, so hopefully those XML export issues will go away.
The file itself simply contains a "codestore
" element, which then contains a "component
" element for each of the components. The Component
element consists of the following items:
ID
- the database file identifier. Will probably use internally in the future for referencing components;
Name
- the 'friendly' name of the component;
FileName
- the actual file name of the component. Used to actually load the component into the toolbox.
Version
- the version number of the component. A future version of the back-end could determine this automatically as part of the upload process. This field could also be used in a future version to provide users with a "New Version Notification" service so they get told when a new version of an existing component is available'.
Description
- a description of the component and its purpose;
Author
- the component author;
Email
- the email address of the component author. A future version will display this as a clickable link in the components list to allow users to contact authors with questions;
DateSubmitted
- the date the component was submitted to the repository. The web page adds this field automatically. A future version will use this field to inform users when new components have been added to the repository;
MoreInfo
- this field is currently intended to be a link to some documentation or more information about the component. Typically, this will be a link to the relevant page at CodeProject.
A sample of the XML file is as follows:
="1.0"
<codestore>
<component>
<ID>1</ID>
<Name>Browse For Folder</Name>
<FileName>Salamander.Windows.Forms.BrowseForFolder.dll</FileName>
<Version>1.0.1221.24682</Version>
<Description>Managed wrapper around the
BrowseForFolder function.</Description>
<Author>Derek Lakin</Author>
<Email>derek.lakin@salamandersoftware.biz</Email>
<DateSubmitted>2003-06-24 10:28:50</DateSubmitted>
<MoreInfo>NULL</MoreInfo>
</component>
<component>
<ID>2</ID>
<Name>Collapsible Panel Bar</Name>
<FileName>CollapsiblePanelBar.dll</FileName>
<Version>1.4.1059.25679</Version>
<Description>Panel and panel bar class that
imitate Windows XP collapsible panels.</Description>
<Author>Derek Lakin</Author>
<Email>derek.lakin@salamandersoftware.biz</Email>
<DateSubmitted>2003-06-24 10:28:50</DateSubmitted>
<MoreInfo>http://www.salamandersoftware.biz/
products/collapsiblepanelbar.htm</MoreInfo>
</component>
</codestore>
Proxy Server Support
Since version 1.2, proxy server support has been added (due to the help and support of Alex Kucherenko). Since version 2.0, the proxy server settings have been editable from the 'Options' section.
The proxy settings are applied in the ApplySettings
method in the Engine
class:
internal void ApplyOptions()
{
WebProxy proxy = GlobalProxySelection.GetEmptyWebProxy() as WebProxy;
try { proxy = WebProxy.GetDefaultProxy(); } catch (System.Exception exc)
{
System.Diagnostics.Trace.WriteLine(exc.Message, "Engine.ApplyOptions");
}
try
{
if (true == this.options.UseProxy)
{
proxy = new WebProxy(this.options.ProxyAddress
+ ":" + this.options.ProxyPort,
this.options.BypassProxyOnLocal);
if (true == this.options.ProxyAuthorisation)
{
if (this.options.ProxyUser != null &&
this.options.ProxyUser.Length > 0)
proxy.Credentials = new NetworkCredential(
this.options.ProxyUser, this.options.ProxyPassword);
}
else
{
proxy.Credentials =
System.Net.CredentialCache.DefaultCredentials;
}
}
}
finally
{
this.webProxy = proxy;
}
this.formCodeStore.userControlOptions.ApplyOptions(ref this.options);
}
The Web Site
In addition to the add-in itself, there is a web site (http://codestore.salamandersoftware.biz/) that also allows you to browse the available components and allows component developers to add information about their components into the database. For several reasons, there is no live component upload feature. The major reason is time and my inability to get it to work :/. But another reason is security. I want to be able to check components before they are made available, to stop malicious code getting into other people's systems.
The web site hosts a MySQL database, which is used to display the component list on the site and also to generate the XML file that is downloaded by the add-in. But, mainly the purpose of the site is to host the actual components themselves.
Limitations
Version 1.2 is available for .NET 1.1 and 1.0, but the new version 2.0 (and later) is currently only available for .NET 1.1. If anyone can provide some useful insight into converting from VS.NET 7.1 to 7.0, especially with regard to Deployment Projects and resx files, I would like to hear from you.
Currently, only independent UI and non-UI components are supported, i.e. components that are not dependent on additional libraries (other than the standard .NET Framework libraries). In time, support for compressed archives and dependent files as well as support for ASP.NET Web Controls will be added.
Other forthcoming features are detailed in the "Future Features" section below.
Points of Interest
There are two bugs that I am aware of that relate specifically to this add-in and they are both to do with adding things to the toolbox. The first requires the Property Window to be opened before you can successfully add a control to the toolbox and the second requires the tab to have focus.
Despite numerous rumors and attempts in different threads in different newsgroups, the most reliable solution to these bugs is as follows. Firstly, you need to call:
applicationObject.ExecuteCommand("View.PropertiesWindow");
Then, before you call ToolBoxItems.Add()
, you need to call:
myTab.Activate();
Call for Code
This add-in has the potential to be enormously useful and to save time for developers like you and me. However, it is nothing if there are only a few components to download. So, if you are a .NET developer and you have a UI control, a library of them or some other code library, then go here and register the details, then send me the release build DLL to codestore@salamandersoftware.biz.
If anyone feels that they have something they could add to the Code Store development or can provide the implementation for any of the "future features" below, then you can register and join in at the GotDotNet Code Store Workspace.
Credits
Many thanks to Paul Watson and Alex Kucherenko for their testing effort prior to release as well as Matt Dixon and Marc Merritt for their assistance with the post-release bugs in version 2.0.
Thanks also to Furty for his Collapsible Splitter control.
Many thanks to all those authors who have contributed their work to the initial repository of components.
Future Features
The current development plan is detailed below. The timescales are estimates and could easily slide if Real Life™ gets in the way. The plan includes features that have definitely made the cut; additional features may also be added, especially if enough people ask for it.