Microsoft Visual C# Starter Kit (Visual Studio 2010)

Starter Kit: ADO.NET Entity Data Model Designer Extension

Contents:

Introduction
Goals
Building the Project and Deploying the Extension
Testing the Extension
Modifying the Extension
Debugging the Extension
Un-Installing the Extension
How an ADO.NET Entity Data Model Designer Extension Works
Ideas for More Extensions
Resources

Introduction

This Visual C# Starter Kit is a complete ADO.NET Entity Data Model Designer (Entity Designer) extension. Building the project "as is" will produce a Visual Studio extension (a .vsix file) that extends the functionality of the Entity Data Model Designer in the following ways:

  • The Entity Data Model Wizard adds a custom property to each generated entity type and displays a message box with relevant information about the model generation process.
  • The Update Model Wizard adds a custom property to each generated entity type and displays a message box with relevant information about the model update process.
  • The Entity Designer adds custom properties to entity types when they are selected in the Entity Designer or Model Browser.
  • This starter kit also contains placeholder classes for transformation and conversion extensions. By writing code for these classes you can do the following:

  • Modify the way the Entity Designer loads and saves .edmx files.
  • Enable the Entity Designer to load custom files and convert them to .edmx files.
  • Enable the Entity Designer to save files in a custom format.
  •    

    Note: The functionality described above can be implemented to work together in a Visual Studio extension. For example, a conversion extension could load a custom file which could then be modified by a transformation extension. Then, the conversion extension could convert the file back to the custom format when it is saved.

    You can customize this functionality further by modifying the source code and rebuilding the project. (For more information, see Modifying the Extension and Ideas for More Extensions.) You are free to use this project's source code as the basis for your own extension projects. You are also free to share your work with others or upload it to the Internet.

       Note: This documentation assumes that you are familiar with the following technologies:

    Goals

    This starter kit helps you understand how an Entity Data Model Designer extension works provides you with a Visual Studio 2010 project that you can use as the basis for your own extensions.

    This starter kit demonstrates the following features:

    Building the Project and Deploying the Extension

    Building the Project

    Building this starter kit project creates a Visual Studio extension that can be deployed to any Visual Studio 2010 installation.

    To build the project:
    1. Open the project in Visual Studio 2010.
    2. Press Ctrl+Shift+B to build the project.

    Building the project creates a .vsix file in the output directory (typically the bin/debug or bin/release directory in the project directory). A .vsix file is a Visual Studio extension that can be deployed to a Visual Studio installation.

    Deploying the Extension
    After you create the .vsix file by building the project, you can deploy the extension by performing the following steps:
    1. Open Visual Studio if it is not already open.
    2. Locate and double-click the Microsoft Visual Studio Extension file (the the .vsix file).
    3. Follow the instructions in the Visual Studio Extension Installer to install the extension.
    4. Exit and restart Visual Studio to load the extension.
    5. After restarting Visual Studio, click Tools in the main menu and then click Extension Manager to show the Extension Manager dialog box. Ensure that the extension you just installed is visible under Installed Extensions.

    Testing the Extension

    To test the model generation extension...
    1. Open Visual Studio if it is not already open.
    2. Create a new C# Console Application project.
    3. Add a new ADO.NET Entity Data Model item to the project by choosing Add New Item... from Project in the main menu.
    4. In the Entity Data Model Wizard, select Generate from Database, choose a connection, select some tables, and then click Finish.

      Code in the model generation extension executes a simple message box with an OK button appears.

    5. Click OK to continue and to add the generated model to the project.
        A new property (My New Property) has been added to each entity type in the conceptual model. The new property is visible in the Properties window when an entity type is selected in the Entity Designer.
    To test the property extensions...
    1. Click an entity type on the Entity Designer surface and press F4 to show the Properties window.

      Two new properties are available in the Properties window: a boolean property called My New Property and an Int32 property called My New Property 2. Note that these properties are only available when an entity type is selected on the Entity Designer surface or in the Model Browser window. My New Property was added by the model generation extension and has a corresponding element in the .edmx document. My New Property 2 is visible in the Properties window, but does not have a corresponding element in the .edmx document until the property value is changed and the .edmx document is saved.

    2. Change the value of My New Property 2 to 1 in the Properties window and note that the .edmx file has been modified (as indicated by the * next to the file name).
    3. Save the .edmx file.
    4. Right-click the .edmx file in Solution Explorer, click Open With..., and then select XML Editor in the Open With dialog.
    5. Locate the entity type that has the newly modified property value in the <edmx:ConceptualModels>  element and note that My New Property 2 is saved as a new XML element under the <EntityType> node:
    6.         <EntityType Name="Entity1">
               <Key>
                 <PropertyRef Name="Id" />
               </Key>
               <Property Type="Int32" Name="Id" Nullable="false" />
               <a:MyNewProperty2 xmlns:a="http://schemas.tempuri.com/MyNewProperty2">1</a:MyNewProperty2>
              </EntityType>
              
         Note: This XML element is a structured annotation and can be accessed with public Entity Framework metadata APIs at design time and runtime.
    To test the update model extension...

    1. Right-click an empty area on the Entity Designer surface and choose Update Model from Database
    2. .
    3. Select a table and click Finish.

      Code in the update model extension executes and a simple message box with an OK button appears.

    4. Click OK to continue.
        A new property (My New Property) has been added to each new entity type in the conceptual model. The new property is visible in the Properties window when an entity type is selected in the Entity Designer.

    Modifying the Extension

    You can edit the source code to change the functionality of the extension. The example below makes the My New Property property available when an EntityType or a NavigationProperty is selected.  

    To make a property available when an entity type or a navigation property is selected...

    The Entity Designer calls the CreateProperty() method of a property extension depending on values specified in the EntityDesignerExtendedProperty attribute in the class that implements the IEntityDesignerExtendedProperty interface. A property extension can specify a variety of selection combinations depending on the scenario. 

    1. Open the file MyNewPropertyFactory.cs
    2. Change the line:
      [EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)]

      to:

      [EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType | EntityDesignerSelection.ConceptualModelNavigationProperty)]
    3. Press Ctrl+Shift+B to build the project.
    4. Uninstall the extension as described below in UnInstalling the Extension.
    5. Reinstall and test the extension as described above in Building the Project and Deploying the Extension and Testing the Extension.
    6. Note that the new boolean property My New Property is now available in the Properties window when an Entity or a NavigationProperty is selected in the designer canvas or the Model Browser. Note also that a corresponding MyNewProperty element is not added to the .edmx document until the property value has been changed and the .edmx document saved.

    Debugging the Extension

    You can debug an installed extension in Visual Studio 2010 as follows:

    1. Ensure that the extension is installed as described in the section Deploying the extension.
    2. Start Visual Studio 2010 if it is not already running.
    3. Open the extension project and set breakpoints as desired. For example, open the file MyNewPropertyFactory.cs and set a breakpoint on the CreateProperty() method.
    4. Press F5 to start debugging.
    5. A second instance of Visual Studio 2010 is started.

    6. Test your extension as described in the section Testing the Extension in the second instance of Visual Studio 2010.
    7. Breakpoints in the first instance of Visual Studio 2010 are hit when an EntityType is selected in the the second instance of Visual Studio 2010.

    UnInstalling the Extension

    To uninstall the extension...
    1. Start Visual Studio 2010 if it is not already running.
    2. In Visual Studio 2010, click Tools in the main menu, and then click Extension Manager to show the Extension Manager dialog box.
    3. Click the extension you wish to uninstall and click Uninstall.
    4. Click Restart to restart Visual Studio 2010.

    How an Entity Designer Extension Works

    This starter kit project contains six C# source-code files in the project root folder that make up the extension and three files in the VSIX folder that are needed to package the extension into a Visual Studio extension (a .vsix file). The source code files perform the following functions:

    Property extension

    MyNewPropertyFactory.cs and MyNewProperty2Factory.cs

    These two files contain the MyNewPropertyFactory and MyNewProperty2Factory classes that implement the IEntityDesignerExtendedProperty interface.

    • The MyNewPropertyFactory and MyNewProperty2Factory classes have the [PartCreationPolicy] and [Export] attributes required by MEF.
    • The [EntityDesignerExtendedProperty] attribute on the MyNewPropertyFactory and MyNewProperty2Factory classes tells the Entity Designer when to call the CreateProperty() method. The method is called when any one of the object types that are listed as parameters for the attribute are selected in the Entity Designer or Model Browser.

      For example:
      [EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)] causes the designer to call the CreateProperty() method only when an entity type in the conceptual model is selected in the Entity Designer or Model Browser.

      While:
      [EntityDesignerExtendedProperty(EntityDesignerSelection.StorageModelEntityType)] causes the Entity Designer to call the CreateProperty() method only when an entity type in the storage model is selected in the Model Browser. (Storage model entity types cannot be selected in the Entity Designer.)

         Note: You can bitwise OR EntityDesignerSelection enumeration values so that custom properties are available in the Properties window when more than one type of object is selected.

    • When the selected object changes in the Entity Designer, the CreateProperty() method is called for all extensions whose [EntityDesignerExtendedProperty] attribute specification matches the selected object.
    • The CreateProperty() method receives two parameters:
      1. The XElement from the .edmx document that corresponds to the selected object in the Entity Designer.
      2. A PropertyContext that can be used to add, modify, or delete child XElements in an transaction. The transaction can be undone and redone with the Undo and Redo options in Visual Studio.
    • Each time the CreateProperty() method is called, it returns a new instance of MyNewProperty or MyNewProperty2.

    MyNewProperty.cs and MyNewProperty2.cs

    Contains the MyNewProperty and MyNewProperty2 classes whose public properties are shown in the Visual Studio Properties window. These classes use attributes in System.ComponentModel (such as DisplayName, DefaultValue, Description, Category, etc.) to control appearance in the Properties window.

    • The property getter reads the property value from the .edmx document (typically from a child element of the XElement in the .edmx document that corresponds to the selected object in the Entity Designer.)
    • The property setter writes the property value to the .edmx document (typically from a child element of the XElement in the .edmx document that corresponds to the selected object in the Entity Designer.). All modifications to XML content are done within an EntityDesignerChangeScope obtained from the PropertyContext. This puts changes in a transaction that is managed by the Entity Designer, and thus allows the user to undo or redo the operation in Visual Studio.

    Model Generation extension

    ModelGenerationExtension.cs

    This file contains the ModelGenerationExtension class that implements the IModelGenerationExtension interface.

    • The extension's implementation of OnAfterModelGenerated() is called by the Entity Designer after a model is generated or modified by the Entity Data Model Wizard or the Update Model Wizard. The method displays a message box to show that the method was called.
    • The extension's implementation of OnAfterModelUpdated() is called by the Entity Designer after a model is updated by the Update Model Wizard. The method displays a message box to show that the method was called.
    • Both methods call a helper method that adds a child XElement to every EntityType element in the generated conceptual model. This new child XElement is in the same format as the XElement added by the property extension described in Testing the Extension. Thus, a model generation extension can annotate the generated model with a new property that can be read, displayed and edited later by a property extension.
    • You can use classes int the EnvDTE Namespace to obtain a project's target framework version and make changes to the generated model accordingly.

    See the starter kit source code for more details about the ModelGenerationExtensionContext and UpdateModelExtensionContext classes.

    VSIX extension manifest

    extension.vsixmanifest
    This XML file is required to package your Entity Designer extension as a .vsix package and has information about the extension such as Author, Supported VS editions, and MEF component name. Double-click extension.vsixmanifest to open it in XML Editor and change it as necessary for your extension. Specifically, if you change the Assembly Name in Project Properties also remember to change at least the following lines in extension.vsixmanifest:
    <Identifier ID="your-new-extension-identifier-name-goes-here">
    <Content>
      <MEFComponent>your-new-assembly-name-goes-here</MEFComponent>
    </Content>

    Ideas for More Extensions

    Category

    Description

    End-to-End Scenarios

    • Property extensions working in concert with customized code generation. For example, a property extension could let users specify CLR attributes or client-side Range constraints to apply to generated classes.
    • Property extensions working in concert with customized DDL generation. For example, a property extension could let users specify server-side Range constraints that are turned into CHECK constraints during DDL generation.
    • Visual Studio 2010 add-ins working in concert with Entity Designer extensions to influence .edmx file open/close/save operations, custom build-time validation, shape adornments, context menus, tool windows, etc.
    • Publish Model To Astoria.
    • Create Database or Data-tier Application Component (DAC) projects from the Entity Designer.
    • Property extension let users specify which objects to generate code for and customized code generation that generates code accordingly.

    Property Extensions

    • Properties that implement ICustomTypeDescriptor for advanced control over what is displayed.
    • Properties that use UITypeEditor to present domain-specific user interfaces for property editing. For example, a numeric up/down control for a Range constraint.
    • EntityConnection string editor available as a property from the Entity Designer surface.
    • Exclude user-specified objects from a generated model.
    • Preserve user-specified SSDL elements during the "update model from database" process.
    • Validation (PEM) annotations (such as Range, Required, Inclusive/Exclusive/Pattern) on properties and entity types.
    •  UI annotations on properties and entity types. For example, determine whether a checkbox or drop down should be shown, whether the UI should be linked to or expanded inline, how errors should be shown, whether a type or property should be scaffolded.
    • Rich DB annotations such as indexing, file groups, and triggers.
    • Service generation and other codegen annotations.
    • Code generation annotations, such as CLR attributes.
    • Velocity annotations (see codegen for velocity below) such as which objects represent reference data.
    • Annotations for reporting services support.
    • Schema history annotations that capture deletes, renames and adds, so that rich migration scripts can be written.
    • Security data.
    • Pre-loaded reference data.
    • Review/commenting data.
    Model Generation
    • A model generation extension that enables advanced naming tasks like: add/remove  a prefix, add/remove a suffix, RegEx based name find & replace, etc.
    • Include or exclude user-specified objects from a generated model.
    • Display an advanced GUI that lets users fine tune the .edmx file. For example, let users resolve tables that were skipped because they do not have keys.
    • Generation of a model from code classes.
    • Generation of a model from VS UML artifacts.
    • Generation of a model from a set of remote services, such as enabling a dynamically created local cache.
    • Generation of a model from an XSD to enable storage of incoming XML documents.
    • Intelligent reverse engineering wizard.
    • Automatic detection of model subsets (using aggregate roots, or schemas, or other approaches) to generate multiple models from a large database.
    • Batch create complex types for report-like stored procedures.