Create Custom Features for Database Projects
You can extend existing database project types by adding your own features. For example, you can create a feature that does something every time that a database project is loaded or saved. You can also create your own database schema provider and supporting project system. However, that type of extensibility is not covered in this content.
Learn more about the extensibility points: You can read about the design of database project extensibility.
Create a sample project feature: Learn the steps that are required to create a custom project feature that displays a dialog box when a database project is loaded. If you follow these walkthroughs, you will:
Install a custom project feature: After you create and build a project feature, you must install it before Visual Studio will recognize it.
Goals of Project Extensibility
The major goals for the database project extensibility features in Visual Studio 2010 are as follows:
Expose major components through interfaces
This approach keeps the project system consistent with the schema model, by using interfaces instead of abstract classes. A single concrete class is expected to implement many interfaces.
Features are created by the extensibility manager
Features are responsible for major parts of the system including Solution Explorer, Schema View, project upgrade, and project properties.
Features can be extended
Features can use the extensibility manager, XML files, registry or other approaches to provide that extensibility.
Services are exposed through their own interface
DataPackage implements IServiceProvider. Any cross-talk between features should be handled through servicing at these levels. You should not expose your feature as the service. Instead, create a new interface, a wrapper class, and then expose the wrapper as the service.
Events drive the project system
The DataPackage and the ProjectNode() offer events that enable features to drive the project system. In addition, features can provide events through their service interfaces. In some cases, you might decide to use a delegate. To decide which feature handles the action, consider using an event approach where the features could interact, based on priority.
Do not rely on the ordering of listeners
If the order of listeners to an event is important, then consider creating a Pre or Post event or consider adding a priority property to the class derived from EventArg.
Component Model Assemblies
The following assemblies provide the database project system in Visual Studio.
The base project system and provides for feature bootstrapping and eventing. This includes database-agnostic features, such as scripts.
The satellite assembly for the database-agnostic package.
The SQL Server-specific features, editors, and tool windows for Visual Studio.
The satellite assembly for the SQL Server-specific features, editors, and tool windows.
You can extend the follow points of the database project system:
IDatabaseProjectFeature (AllowMultipleExtensions =true)
This is the primary extension point for the project system. Features are designed to control the project and contribute. There are several interfaces that they can optionally implement: IOleCommandTarget, IDatabaseProjectPriorityCommandTarget, IDatabaseProjectPropertyPageContributor, IDatabaseProjectExtenderContributor<TExtendee>, IDatabaseProjectAddNewItemParticipant, IDatabaseProjectIdleProcessor, and IDatabaseProjectPartialProjectParticipant.
IDatabaseProjectBuildActionContributor (AllowMultipleExtensions =false)
Contributes BuildAction strings to the list of possible build actions in the project system For example, the SQL Server project system contributes Predeploy and Postdeploy.
IDatabaseProjectUserFileContributor (AllowMultipleExtensions =false)
Specifies which properties should be routed to the .user file.
IDatabaseSchemaViewController (AllowMultipleExtensions =false)
Populates the schema view and responds to events from that view.
IDatabaseProjectFileUpgradeController (AllowMultipleExtensions =false)
Upgrades the project file as an XML document. This process occurs before the Visual Studio project system tries to load the project instance through the project factory.
IDatabaseProjectReferenceController (AllowMultipleExtensions = false)
Controls project references
IDatabaseProjectPartialProjectParticipant (AllowMultipleExtensions = true)
Enables a feature to filter out files that should not be exported as a partial project.
Provides the project system Help keyword that is used when the customer presses F1.
Database Project Lifecycle
Every database project file (.dbproj) contains a property named "DSP" indicating the specific DatabaseSchemaProvider that handles this project when it is opened in Visual Studio. The project system creates an extension manager by using this DSP and from that constructs all the project system contributors and project features. Each feature receives an Initialize event so that it can initialize and root itself into the project system by listening to events.
The following events are raised during project open/close and save:
This event occurs when a project is first created. You can handle this event to display wizards or setup dialog boxes.
The project is opening. You can handle this event to add any services to the IDatabaseProjectNode.
This event occurs when all services were added and the project has completed opening. However, project will not yet have completed deserializing its previous state. The TaskHost and the DataSchemaModel will be NULL until the ProjectLoaded event is sent.
The project is closing. This is a good opportunity to persist any state information that is outside the project file.
The project is closed.
The project is performing a save operation. You can use this as an opportunity to make sure that your feature is in a state for its persistence to be stored.
The project has been saved.
Every project has one ErrorManager. Some errors are persisted to the .dbmdl file and other errors are not. This is controlled through the AddPersistedCategory class. By default these categories are persisted: ModelCategory, ValidationAtBuildCategory, and ValidationOnIdleCategory. If you add another persisted category you will have to handle the project reload and verify and manage your errors. Remember that although the project was closed, the user could have edited the .dbproj file to remove a file for which you are reporting an error. It would be very confusing to users to report an error in the project when no such file exists.
Database error objects are added to the ErrorManager in specific categories. The idea is that project features can manage the lifetime of their errors through the lifetime of their category. If you are concerned about category names conflicting with other features then use a GUID as the name. The ErrorManager defines several built-in categories including:
This category is designed for you to use for errors whose lifetimes are equal to the lifetime of the project. Therefore, for example, errors which occur during project load are added into this category.
This category should be used by the schema manager when it encounters errors such as parser errors.