Welcome to MSDN Blogs Sign in | Join | Help

It's been a while since my last post, and for good reason. The whole team has had their heads down and has been working very hard towards the completion of an internal milestone. Now I get the chance to take a brief breather and tell the world about what we've been so busy doing. I can't tell you how proud I am of the work we've done. Here's a quick list:

- Ship DSL Tools within VSSDK Feb CTP.
- Release first draft of DSL Tools documentation.

- Add support for 'port' shapes
- A new and vastly improved model (and associated xml format) for the definition of all aspects of a DSL (domain model, shapes, mappings, etc), and some of the code-generation from this model.

- Clean, domain-specific, and customizable serialization of models.
- And last but not least, vast improvements to the Modeling API.

I was most directly involved in the work on the Modeling API and code-generation work, and I'm excited to share the details. This post will be the first in a series that will cover these areas (and possibly other areas). Given the breadth of customizations that will be allowed by the upcoming DSL Designer (a designer for the DSL definition), it may not be common to have to use the modeling API. Nevertheless, for advanced customizations, and for understanding what the generated code does, it will be necessary to understand the modeling API.

Now where shall I start?

First of all, there are a bunch of naming changes to make things flow better. Here are a few of the biggest ones. I'll add to the list in future postings:

"MetaX" --> "DomainX" (Eg, MetaClass becomes DomainClass).
"SubStore" or "MetaModel" --> "DomainModel"
"XAttribute" --> "XProperty" (Eg, MetaAttribute becomes DomainProperty).

I'll be using the new names from now on.

In this post, I'll assume that you have a domain model defined using the new format, and the code for it generated using the new generators (I'll cover these in a later post). Let's look at how to create the Model Store, and create a couple of domain-classes and relationships?:

To create a store, use one of the following 2 constructors:

public Store(params Type[] domainModelTypes)
public Store(IServiceProvider serviceProvider, params Type[] domainModelTypes)

For the domainModelTypes parameter, provide a list of the of your 'DomainModels' (the classes in the generated code that used to be derived from Microsoft.VisualStudio.Modeling.SubStore, but are now derived from Microsoft.VisualStudio.Modeling.DomainModel). The serviceProvider is used by the Store's implementation of IServiceProvider.

For example,

Store store = new Store();

Store store = new Store(typeof(ActivityDomainModel));

Multiple domain models can be loaded into the store at once. In the example below, a base domain model and an extended domain model are loaded. When there are dependencies between domain models (as in the example below), the domain models should be specified in dependency-order.

Store store = new Store(typeof(BaseActivityDomainModel), typeof(ExtendedActivityDomainModel));

Domain models can also be loaded into the store after construction. For example,

Store store = new Store();
store.LoadDomainModels(typeof(ActivityDomainModel));

Make sure you call store.Dispose() once you are done with it.

Let's say you have a domain class called 'Person' and another one called 'Activity' and a domain relationship called 'PersonPerformsActivities' (a relationship from one person to many activities)  in your domain model. How would you go about creating instances of these classes and relationships?

Simple, you just use 'new':

Person person = new Person(store);
Activity activity = new Activity(store, new PropertyAssignment(Activity.NameDomainPropertyId, "Post On Blog"));

// Now to create the link between person and activity, we have a few ways of doing it
person.Activities.Add(activity);
// or
activity.Person = person;
// or
PersonPerformsActivities relationship = new PersonPerformsActivities(person, activity);
// There are a few more varieties of the constructor for more complex cases, but these
// are the simplest and most common ways to create a link

Seems obvious, but you could not do this with the old Modeling API. Using new() would not work. Instead you had to call Activity.CreateActivity(..) or store.ElementDirectory.CreateElement(typeof(Activity)). We still support the reflective mechanism of creating elements (I'll cover that in a different post), but 90% of cases will probably use new(). I think this is a great improvement in the API and I hope you agree.

I'll stop for now. There is so much to cover, but I'll leave the rest for future posts. As always, comments and feedback are welcome and appreciated.

Thanks,
-George

I'll be in India next week for Visual Studio launch events in 3 cities (itinerary below). If you're interested in DSL Tools and you're in the area, I'll be more than happy to give a presentation/demo and chat about DSL Tools.  Please let me know if you want to arrange a meeting, or just come find me at the launch events in Mumbai, Pune, or Chennai.

My itinerary is as follows:
Mumbai:    12th night to 13th morning
Pune:        13th morning to 13th evening
Chennai:    14th morning to 15th morning
Bangalore: 15th morning to 15th evening

The November CTP of DSL Tools is now available for download at http://msdn.microsoft.com/vstudio/teamsystem/workshop/DSLTools/default.aspx. New features in this release include:

- A validation framework for validating the model on save, open, using a menu item, and at other custom points.
- The ability to add a DSL Setup project to your DSL solution that builds a deployable MSI for your designer.

These features are explained better in Stuart's post here. The release also includes some bug fixes.

Try it out, and let us know what you think.

Thanks,
-George

Gareth posted an entry in June (with links to previous postings on the same subject) about Text Templating code generation engine. Pleas refert to it for background information. After hearing feedback from customers and from our own use of the feature, we recently made some improvements to it that we hope you'll like.

Previously, if you wanted to append to the output text from within a method in a class-feature block, you would have to use clumsy Write() and WriteLine() statements. For example:

<# PrintPowersOfTwo(1,5); #>
<#+
private void PrintPowersOfTwo(int i, int j)
{
   for(;i<j;i++)
   {
      WriteLine("2 to the power {0} is:", i);
      WriteLine(Math.Pow(2,i).ToString());

   }
}
#>

This could get clumsy quickly, especially if you have methods that output large amounts of text.

To help the situation, we added a new feature to allow boilerplate and expression blocks to be embedded within class-feature blocks. For example, the same PrintPowersOfTwo() function above could look like this:

<#+
private void PrintPowersOfTwo(int i, int j)
{
   for(;i<j;i++)
   {
#>
2 to the power <#= i #> is:
<#= Math.Pow(2,i) #>
<#+
   }
}
#>

We feel this helps conform better to the users instinctive expectation of what the above template should do. It is a very natural way to use class-feature blocks to spit up code-generation into different methods. I've used it myself for some of my code-generation tasks and find it tremendously useful, and I hope you find the same.

With this change, no statement blocks will be allowed after the first class-feature block within a file. And all boilerplate or expression blocks found after the first class-feature block will be treated as embedded within the class-feature. So doing something like this will cause a compiler error:

<#+
private void DoNothing() {}
#>
boilerplate text
<#+
private void DoNothingAgain() {}
#>

The restrictions above don't affect the code-generation functionality of Text Templates in any way, however. And as I mentioned earlier, the outcome does feel more natural once you've tried it.

Another feature we've added, that goes hand in hand with the above feature, is three methods and one property in the base code-generation class to manage indents:

public void PushIndent(string indent);
public string PopIndent();
public void ClearIndent();
public string CurrentIndent { get; }

PushIndent adds the provided indent to the current indent. PopIndent removes the previously indend added through PushIndent, and does nothing if there is no indent. ClearIndent clears the current indent. And CurrentIndent gets the current indent string. The current indent is applied after every newline that is ouput (even if it's output using the Write() or WriteLine() functions). For example, using the PrintPowersOfTwo() function provided earlier:

<#
PrintPowersOfTwo(1,3);
PushIndent("    ");
PrintPowersOfTwo(4,6);
PushIndent("indent>");
PrintPowersOfTwo(7,9);
PopIndent();
WriteLine("Test Indent");
WriteLine("Current Indent is \""+CurrentIndent+"\"");
ClearIndent();
#>

Produces the following output:

2 to the power 1 is:
2
2 to the power 2
is:
4
    2 to the power 4
is:
    16
    2 to the power 5
is:
    32
    indent>2 to the power 7
is:
    indent>128
    indent>2 to the power 8
is:
    indent>256
    Test Indent
    Current Indent
is " "

I hope you like these improvements. Any comments, suggestions, or other feedback would be very much appreciated.

Unfortunately, this will not be in the November CTP, and I don't know the exact dates for our next release. Sorry to get you all excited and then tell you you can't have it yet. But it is worth the wait :). And this gives us a chance to gather some early feedback on the feature (so please spill your thoughts).

Thanks,
George

I am a software developer in the Visual Studio Team System group, specifically in the DSL Tools team, which is a framework for building graphical designers for Domain Specific Languages. For Visual Studio 2005, I worked on the much loved Class Designer. In the DSL Tools team, I work mainly on the modeling data store infrastructure (which we fondly call the IMS), and on the the Text Templating code generation infrastructure (which we call T4 because it rolls off the tongue better).

I started this blog to follow the lead of other great bloggers from my team (Gareth Jones, Steve Cook, Stuart Kent, Pedro Silva, Jochen Seemann, Jack Greenfield etc) and from Microsoft in general, who have used blogs as a very effective means of communicating with our customers. I hope to use this as a means of gathering feedback for design decisions and the product in general, sharing interesting news and information about DSL Tools and Model-Driven-Development. I will also be using this as a spot for collecting ramblings about various other technical fields that interest me.

Hope you enjoy the read. It goes without saying that any comments and feedback are welcome and appreciated.

Thanks,
George Mathew

 
Page view tracker