Code Generation Extensions

Retired Content

The Web Service Software Factory is now maintained by the community and can be found on the Service Factory site.

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Retired: November 2011

The Service Factory extends the DSL framework with a mechanism to generate code by using recipes and easily replaceable T4 templates. The mechanism is based on a few concepts:

  • The artifact link
  • The project mapping table
  • Code generation strategies

Artifact Links

The logical view of the ArtifactLink is shown in Figure 1. An ArtifactLink is an object associated either with a model element that implements the IArtifactLinkContainer interface or with a model element extender (all extenders implement the IArtifactLinkContainer interface).

Ff699451.ffd66157-b01e-4238-b0b8-8e800797e1d7(en-us,PandP.10).png

Figure 1

Artifact links

The ArtifactLink object contains information that is used to generate one code artifact. At the time that they are used, ArtifactLink objects are dynamically created from their class attributes and the information in model element they are associated with. The following code example is the ServiceLink class, which describes artifact links that will be associated with the Service model element extender.

[TextTemplate(@"Lib\TextTemplates\WCF\CS\ServiceImplementation.tt", TextTemplateTargetLanguage.CSharp )]
[AssemblyReference("System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[AssemblyReference("System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[TypeConverter(typeof(ArtifactLinkConverter<ServiceLink>))]
[CodeGenerationStrategy(typeof(TextTemplateCodeGenerationStrategy))]
public sealed class ServiceLink : ArtifactLink
{
}

The class has the following properties:

TextTemplate. The T4 template that will be used to generate the code artifact (in most cases, a class). An artifact link might have multiple T4 templates associated with it. The second argument of the attribute is an Enum that indicates the language of the code generated by the template.

AssemblyReference. The assemblies that should be added to the project in which the code artifact will be placed.

TypeConverter. The type converter that will be used to display the artifact link in the Properties window when the model element is selected.

CodeGenerationStrategy. The code generation strategy that will be used to handle the link (in this case, it is the code generation strategy that unfolds T4 templates).

Artifact links are created by the ArtifactLinkFactory, which is a class in the Microsoft.Practices.Modeling.CodeGeneration project in the Libraries solution folder. When the Service Factory constructs the object, it calculates two important properties:

  • ItemName. This is the name of the item that will be generated. This property is calculated based on the name of the model element that contains the artifact link.
  • Container. This is the GUID of the project where the generated code will be placed. This property is calculated using the project mapping table described in the next section.

Project Mapping Table

To have more flexibility about which projects the generated code should be added to, the Service Factory includes a project mapping table. A project mapping table maps solution project elements to a set of predefined roles. A project mapping table is represented as a <ProjectMappingTable> element of the XML file named ProjectMapping.xml, and is stored in the Solution Items folder. The following is an example of a fragment of the project mapping table named GlobalBank.

<?xml version="1.0"?>
<ProjectMappingInformation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" FileName="ProjectMapping.xml" xmlns="http://schemas.microsoft.com/pag/project-mapping">
  <ProjectMappingTables>
    <ProjectMappingTable Name="GlobalBank">
      <ProjectMappings>
        <ProjectMapping ProjectId="5c02a790-18ba-484f-a05d-a4d872c3001f" ProjectPath="\GeneratedCode" ProjectName="GlobalBank.BusinessEntities">
          <Roles>
            <Role Name="BusinessEntityRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="496c1206-f159-41f1-8d8b-5cd5a7603309" ProjectPath="\GeneratedCode" ProjectName=" GlobalBank.BusinessLogic">
          <Roles>
            <Role Name="BusinessLogicRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="2be8657f-9684-495e-a8ad-0d838bac768c" ProjectPath="\GeneratedCode" ProjectName=" GlobalBank.DataContracts">
          <Roles>
            <Role Name="DataContractRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="28482aa8-549b-4251-b227-4f6c537a5d81" ProjectPath="\GeneratedCode" ProjectName="GlobalBank.FaultContracts">
          <Roles>
            <Role Name="FaultContractRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="79bc2fe0-7fe5-43c8-845e-66d78a549b43" ProjectPath="\GeneratedCode" ProjectName=" GlobalBank.MessageContracts">
          <Roles>
            <Role Name="MessageContractRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="dcb0e8a5-abbb-4684-9998-ec39b235b016" ProjectPath="\GeneratedCode" ProjectName=" GlobalBank.ServiceImplementation">
          <Roles>
            <Role Name="ServiceRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="f63b598a-9e77-4ffe-8e88-2b3640123922" ProjectPath="\GeneratedCode" ProjectName=" GlobalBank.ServiceContracts">
          <Roles>
            <Role Name="ServiceContractRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="721b6835-1170-4540-b8c6-502b713cca11" ProjectPath="\GeneratedCode" ProjectName="C:\...\ GlobalBank.Host\">
          <Roles>
            <Role Name="HostRole" />
          </Roles>
        </ProjectMapping>
        <ProjectMapping ProjectId="4e636940-217f-4dc7-b3ab-b64080faa098" ProjectPath="\GeneratedCode" ProjectName="GlobalBank.Client">
          <Roles>
            <Role Name="ClientRole" />
          </Roles>
        </ProjectMapping>
      </ProjectMappings>
    </ProjectMappingTable>
  </ProjectMappingTables>
</ProjectMappingInformation>

The roles referenced in the project mapping table correspond to custom attributes used on model elements. The following example shows the first two attributes of the Service model element class generated by the DSL tools. The first attribute states that this model element is in the role ServiceFactoryRoleType.ServiceRole.

The PMT <ProjectMapping> elements have both ProjectId and ProjectName attributes. The ProjectName attribute was added solely to make the file more readable. Mapping entries are actually keyed off the ProjectId GUID.

[Microsoft.Practices.Modeling.CodeGeneration.Metadata.ProjectMappingRoleAttribute(Microsoft.Practices.ServiceFactory.RecipeFramework.Extensions.Enums.ServiceFactoryRoleType.ServiceRole)]
[DslDesign::DisplayNameResource("Microsoft.Practices.ServiceFactory.ServiceContracts.Service.DisplayName", typeof(global::Microsoft.Practices.ServiceFactory.ServiceContracts.ServiceContractDslDomainModel), "Microsoft.Practices.ServiceFactory.ServiceContracts.GeneratedCode.DomainModelResx")]
…
public partial class Service : DslModeling::ModelElement
{ …

The following table lists the roles the Service Factory uses:

Role

Description

DataContractRole

Maps target project for data contracts,

FaultContractRole

Maps target project for fault contracts,

MessageContractRole

Maps target project for message contracts,

ServiceContractRole

Maps target project for service contracts,

ServiceRole

Maps target project for service implementation,

HostRole

Maps target project for the host,


The project mapping file allows multiple project mapping tables to coexist, which makes it possible to generate code from the same model to multiple target-projects by using a different project mapping table.

Code Generation

The Service Factory uses the GenerateCode recipe to generate all code. The recipe can be invoked from any model element that implements the IArtifactLinkContainer interface, including the diagram surface. It has one argument and one action. The argument is the selected model element. The action is named GenerateArtifactAction and it works in the following way:

  1. The recipe reference validates the model to make sure that it can be shown and used to generate code.
  2. The recipe reference steps through the model and collects artifact links.
  3. The recipe passes the artifact links to the code generation service that implements the ICodeGenerationService interface.

The code generation service is not aware of where the artifact links came from. It passes them to the appropriate code generation strategies. The Service Factory includes two code generation strategies:

  • Strategy to generate code using T4 templates
  • Strategy to generate fragments of XSD files

Other strategies can be added. A code generation strategy must implement the ICodeGenerationStrategy interface shown in the following code. As the interface implies, a strategy can return, in addition to the generated code, a list of projects and assemblies that should be added to the project in which the code is placed.

public interface ICodeGenerationStrategy
{
CodeGenerationResults Generate(IArtifactLink link);
IList<Guid> ProjectReferences { get;}
IList<string> AssemblyReferences { get;}
IList<Logging.LogEntry> Errors { get; }
}

The TextTemplateCodeGenerationStrategy that ships with the Service Factory runs the T4 template specified by the artifact link that is passed to it. To allow those templates full access to the models, the Service Factory comes with a custom text templating engine host and a directive processor.

  • The host is implemented by the TextTemplateHost class, which is in the Microsoft.Practices.Modeling.CodeGeneration.Strategies project in the Libraries solution folder.
  • The directive process is implemented by the ModelInjectorDirectiveProcessor class and it can be used from within a text template by adding the following line to the list of the directives.
    <#@ ModelInjector processor="ModelInjectorDirectiveProcessor" #>
    

The processor makes the following methods and properties available to the template.

Methods and Properties

Description

Model {get;}

A reference to the model that was used to generate code from.

RootElement {get;}

The root element of the model that was used to generate code from.

CurrentElement {get;}

The element that was used to generate code from.

CurrentExtender {get;}

The ObjectExtender of the element that was used to generate code from, if available.

ResolveModelReference(string)

Takes a ModelElementMoniker and returns the referenced ModelElement from a different model.

IsValid(ArtifactLink)

Verifies that the project associated with the artifact link argument is a valid solution project.

CancelOutput(ArtifactLink)

Tells the processor engine to ignore all generated output and return no results, so a file is not generated. This is useful when a condition in a template stops code generation. For example, the template associated with the Service Contract models in ASMX\CS\ XsdMessageContract.tt.

AddProjectReference(IArtifactLink)

When a template logic navigates through a model, it might visit model elements that have artifact links associated with them. This method is used to add a project reference to the project that the found artifact link is contained in.


The T4 templates are in the TextTemplates folders in the DSL designer projects.

Show: