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 also extended the DSL framework with a mechanism to generate code 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 3. 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).

Ff650851.05a62a20-bd92-474c-8d01-7320e0a557d7(en-us,PandP.10).png

Figure 3
Artifact links

The ArtifactLink object contains information that is used to generate one code artifact. Artifact link objects are dynamically created at the time they are used 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(@"TextTemplates\WCF\CS\ServiceImplementation.tt", TextTemplateTargetLanguage.CSharp )]
[AssemblyReference("System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[AssemblyReference("System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[TypeConverter(typeof(ArtifactLinkConverter<ServiceLink>))]
[CodeGenerationStrategy(typeof(TextTemplateCodeGenerationStrategy))]
public sealed class ServiceLink : ArtifactLink
{
}

The following are the four properties on the class:

TextTemplate. The T4 template that will be used to generate the code artifact (in most cases a class). An artifact link may 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 where 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 introduces the project mapping table. A project mapping table maps from solution projects 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 for 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 it can be shown and used to generate code.
  2. It “walks” the model and collects artifact links.
  3. It 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 where 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 following is some additional information about these:

  • 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.

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 a model, it may visit model elements that have artifact links associated with them. This method is used to add a project reference to the project the “found” artifact link is contained in.

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