Creating a Custom Schema Provider

You can integrate your own data with SchemaExplorer by building a custom schema provider. To create your own schema provider simply create a new assembly which includes a public class that implements the SchemaExplorer.IDbSchemaProvider interface. Also, the assembly name must end with SchemaProvider.dll (for example, SchemaExplorer.CustomSchemaProvider.dll). All of the CodeSmith Generator Schema Providers are prefixed with "SchemaExplorer." (E.G., SchemaExplorer.SqlSchemaProvider.dll). It is recommended that you also choose to follow this naming convention.

It is recommended to follow the naming pattern defined above as it will ensure that an assembly is compiled that follows our naming conventions. Please note that when looking at other provider source code, a default namespace SchemaExplorer will be used. It is not required that your SchemaProvider reside in a namespace named SchemaExplorer. 

Creating a new Schema Provider

The next step is to create a new Schema Provider by opening up Visual Studio and add a new CSharp or Visual Basic Class Library named SchemaExplorer.CustomSchemaProvider. Please note that this can be any name that you choose as long as you follow the naming criteria specified above.

Once the project has been created, we will want to rename the Class1.cs file to CustomSchemaProvider.cs and rename the class name to CustomSchemaProvider.

Adding CodeSmith Generator References

We will now add references to our new Class Library project so we can start implementing the SchemaExplorer Interfaces that allows CodeSmith Generator to consume our new Schema Provider. Note: To add a project reference, please see this guide. You will need to navigate to the CodeSmith Generator Program Files folder and add a reference to the following two assemblies: AddIns\SchemaExplorer.dll and bin\CodeSmith.Core.dll. The references should now show up in the Visual Studio Solution Explorer Tool Window.

Inheriting the SchemaExplorer Schema Provider Interfaces

Now it is time to implement the SchemaExplorer Interfaces so CodeSmith Generator can talk to the new provider. The main Interface that is required is called SchemaExplorer.IDbSchemaProvider. This interface implements the core functionality for populating the SchemaExplorer objects (E.G., TableSchema, ColumnSchema, etc...). There is a second interface that you can implement called SchemaExplorer.IDbConnectionStringEditor. When this interface is implemented, it tells CodeSmith Generator that there is an available ConnectionString designer and allows you to show a designer when the user clicks on the designer button.

You can find the source code for all of CodeSmith Generators' Schema Providers in your extracted templates folder. The default template folder is located in the My Documents folder. You can find all of the extracted Schema Provider source code in the following directory: Documents\CodeSmith Generator\Samples\<Version>\Projects\CSharp\

It is highly recommended to take a look at the existing Open Source Schema Provider source code for all of the CodeSmith Generator Schema Providers as a reference when building a new Schema Provider. This can be found in your My Documents folder as described in the tip above. After we have implemented the two interfaces above, our new CustomSchemaProvider class should look like this:

using System;

namespace SchemaExplorer.CustomSchemaProvider
{
    public class CustomSchemaProvider : SchemaExplorer.IDbSchemaProvider, SchemaExplorer.IDbConnectionStringEditor
    {
    }
}

The next step is to implement the interfaces defined above. I told Visual Studio to implement the interfaces to save me from writing a lot of the simple implementation details. Below is what the default implementation looks like after it has been created by Visual Studio.

#region Implementation of IDbSchemaProvider

/// <summary>
/// Gets the name of the schema provider (E.G. SqlSchemaProvider).
/// </summary>
public string Name { get; private set; }

/// <summary>
/// Gets the description for the schema provider (E.G. SQL Server Schema Provider)..
/// </summary>
public string Description { get; private set; }

/// <summary>
/// Gets the name of the database.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <returns>The name of the database</returns>
public string GetDatabaseName(string connectionString)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the extended property collection for a given schema object.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="schemaObject">Any type that derives from SchemaObjectBase. (E.G. DatabaseSchema, TableSchema, ColumnSchema, ViewSchema, ViewColumnSchema, IndexSchema, CommandSchema, ParameterSchema, PrimaryKeySchema, TableKeySchema)</param>
/// <returns>An array of ExtendedProperties for a specific SchemaObjectBase.</returns>
public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
{
    throw new NotImplementedException();
}

/// <summary>
/// Sets the extended properties.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="schemaObject">Any type that derives from SchemaObjectBase. (E.G. DatabaseSchema, TableSchema, ColumnSchema, ViewSchema, ViewColumnSchema, IndexSchema, CommandSchema, ParameterSchema, PrimaryKeySchema, TableKeySchema)</param>
public void SetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets all of the tables available in the database.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="database">The database schema.</param>
/// <returns>An array of tables for a specific database.</returns>
public TableSchema[] GetTables(string connectionString, DatabaseSchema database)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets all columns for a given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>An array of view columns for a specific table.</returns>
public ColumnSchema[] GetTableColumns(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets all the views available for a given database.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="database">The database schema.</param>
/// <returns>An array of views for a specific database.</returns>
public ViewSchema[] GetViews(string connectionString, DatabaseSchema database)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the columns for a given view.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="view">The view schema.</param>
/// <returns>An array of view columns for a specific view.</returns>
public ViewColumnSchema[] GetViewColumns(string connectionString, ViewSchema view)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the definition for a given view.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="view">The view schema.</param>
/// <returns>The definition of a view.</returns>
public string GetViewText(string connectionString, ViewSchema view)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the primary key for a given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>An the primary key for a specific table.</returns>
public PrimaryKeySchema GetTablePrimaryKey(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets all of the table keys for a given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>An array of keys for a specific table.</returns>
public TableKeySchema[] GetTableKeys(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gats all of the indexes for a given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>An array of indexes for a specific table.</returns>
public IndexSchema[] GetTableIndexes(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the data from the given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>A DataTable containing the data of the specific table.</returns>
public DataTable GetTableData(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the data from a given view.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="view">The view schema.</param>
/// <returns>A DataTable containing the data of the specific view.</returns>
public DataTable GetViewData(string connectionString, ViewSchema view)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets all commands for the given database.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="database">The database schema.</param>
/// <returns>An array of commands.</returns>
public CommandSchema[] GetCommands(string connectionString, DatabaseSchema database)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the parameters for a given command.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="command">The command schema.</param>
/// <returns>An array of parameters.</returns>
public ParameterSchema[] GetCommandParameters(string connectionString, CommandSchema command)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets the definition for a given command.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="command">The command schema.</param>
/// <returns>The definition of a command.</returns>
public string GetCommandText(string connectionString, CommandSchema command)
{
    throw new NotImplementedException();
}

/// <summary>
/// Gets schema information about the results of a given command.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="command">The command schema.</param>
/// <returns>An array of command results.</returns>
public CommandResultSchema[] GetCommandResultSchemas(string connectionString, CommandSchema command)
{
    throw new NotImplementedException();
}

#endregion
#region Implementation of IDbConnectionStringEditor

public bool ShowEditor(string currentConnectionString)
{
    throw new NotImplementedException();
}

public string ConnectionString { get; private set; }
public bool EditorAvailable { get; private set; }

#endregion

Implementing the SchemaExplorer Interfaces

It is highly recommended that you implement all of the methods and properties that were created. It is recommended to implement the ExtendedProperty methods but it isn't required. In the future, we may provide a new abstract base class implementation which implements Extended Property support for you using a in memory database, but as of this time this is not on the official road map.

The first section to implement would be the Name and Description properties which display the name and description of the Schema Provider in CodeSmith Generator.

/// <summary>
/// Gets the name of the schema provider (E.G. SqlSchemaProvider).
/// </summary>
public string Name { get { return "CustomSchemaProvider"; } }

/// <summary>
/// Gets the description for the schema provider (E.G. SQL Server Schema Provider)..
/// </summary>
public string Description { get { return "A Custom Schema Provider"; } }

Next, the GetDatabaseName method returns the name of a Database that is retrieved by the DataSource specified in the connection string (E.G., the Database name or a file name). From this point on, all of the methods are really important like the GetTables method

/// <summary>
/// Gets all of the tables available in the database.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="database">The database schema.</param>
/// <returns>An array of tables for a specific database.</returns>
public TableSchema[] GetTables(string connectionString, DatabaseSchema database)
{
    throw new NotImplementedException();
}

which returns all of the tables in this custom DataSource or the GetTableColumns which returns a list of columns for a specified table.

/// <summary>
/// Gets all columns for a given table.
/// </summary>
/// <param name="connectionString">The connection string used to connect to the target database.</param>
/// <param name="table">The table schema.</param>
/// <returns>An array of view columns for a specific table.</returns>
public ColumnSchema[] GetTableColumns(string connectionString, TableSchema table)
{
    throw new NotImplementedException();
}

Download Custom Schema Provider Source

Click here to download the source code above.