How to: Recipe to Update both Service and Data Contract Models?

Topics: Service Factory Modeling Edition Forum
Jul 29, 2008 at 10:13 AM
I'm writing a recipe that needs to update both a service and a data contract model, and I need some help doing it.

The silly thing is that I wrote this using Test-Driven Development, and my unit tests work just fine. That is, they work just fine updating a Store that is provisioned for both model types. But reality involves actual models om actual disks, and I realized that I don't know how to do this. I think I need to add a Field of type ProjectItem to the wizard page, and use it to select the desired data contract model file to update. However, I don't know how to load in the existing model, or to save it afterwards.

I could also use an example of how to programmattically connect a DataContractMessagePart to its corresponding DataContract. I can see how to do this in the UI, but I need to understand how to call on this functionality from an Action.

Any direction would be welcome.
Jul 29, 2008 at 4:50 PM
Hi John, most of the tools required for interacting with models are provided in the assembly Microsoft.Practices.Modeling.Dsl.Integration which you can find in the Libraries directory of your Service Factory Solution. Below you will find some guidance on how to use it. As a reference scenario you can look at the ImportWsdl recipe, which programatically creates shapes in the Service Contract Model based on an input wsdl.

You would basically need to add an argument to your recipe and set it using the value provider called StoreProvider as per the snippet bellow:

<

 

Argument Name="ServiceContractStore" Type="Microsoft.VisualStudio.Modeling.Store, Microsoft.VisualStudio.Modeling.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <
ValueProvider Type="StoreProvider"/>
</
Argument>

 

This provider will return a reference to the current store, which you can then use to get a reference to the model, create linked elements, find cross model references, etc. by using the DomainModelHelper static class: 

  • ServiceContractModel model = DomainModelHelper.GetElement<ServiceContractModel>(this.scStore);
  • DomainModelHelper.AddLinkedElement<Operation>(model.Operations, operationContract);

    Note that the StoreProvider will return the selected store in the Solution, in case you would like to a get another one you should write a custom value provider to get it and of course use it to feed another argument.

    Thanks

     

  • Jul 29, 2008 at 10:27 PM
    Thanks for the reply. However, I've already started from the ImportWsdl example. My problem is that, unlike ImportWsdl, I need to update both a service and a data contract model.

    I could start with the Service Contract model, as per your example, but I then need to be able either to open an existing Data Contract model, or to create one, save it, and add it to the model project.

    An ideal example for me would be a recipe that starts off like ImportWsdl, but then creates one Message element with a DataContractMessagePart in the Service Model, adds a DataContract element (with PrimitiveDataType member) to the Data Contract Model, then sets the Type of the message part to point to the newly-created Data Contract element.

    Of course, that's the ideal - reality need not go so far. But any help in that direction would be welcome.
    Aug 5, 2008 at 9:03 PM
    I've solved most of this problem. My recipe now permits the optional selection of an existing, empty data contract model from the project, and loads it into the store. It's then possible to create elements in both models, and to save the data contract model back to the store.

    I have a couple of issues left:
    1. I still need to figure out the code to programatically set the Type property of a DataContractMessagePart to the proper moniker of a data contract element. It's easy enough to do with the editor, but I need to do it directly in code.
    2. I believe I've found the code to dereference the moniker once it's set, so I'm ok there
    3. I need to be able to fix up and/or automatically lay out the diagram on the new data contract model. I don't know how to instigate the DSL to create a diagram. Once it creates the diagram (and returns me a reference to it), I could then call the recipe to do the autolayout.

     

    Aug 6, 2008 at 10:01 PM

    Sounds like good news, you are almost there!

    You can split the task of programatically setting a DataContractMessagePart into two main codeblocks:

      • Find the DataContract to reference in the DataContractModel based on the operation parameter type name. Assuming you already have a reference to the DataContract Store as you mentioned in your post, this is how you could search for a DC: 

                                private DataContractElement FindDataContract(string name) 
                                {
                                    if (string.IsNullOrEmpty(name))
                                    {
                                        return null;
                                    }

                                    DataContractModel model = DomainModelHelper.GetElement<DataContractModel>(
    this.dcStore);
                                    DataContractElement found = model.Contracts.Find(
    delegate(Contract element)
                                   {
                                        
    return element.Name == name;
                                   })
    as DataContractElement;

                                    return found;
                             }

      •  Build the element moniker based on the DataContract found. You can do this using a simple function that returns the string with the corresponding mel uri. The only thing that may need to be clarified is that the dataContractModelProjectName and dataContractModelFileName represent the file name without the extension of the Model Project and DC Model files respectively: 

                            private string BuildMoniker(Contract element)
                            {
                                //Moniker format:
                                //mel://[DSLNAMESPACE]\[MODELELEMENTTYPE]\[MODELELEMENT]@[PROJECT]\[MODELFILE]
                                return string.Format(CultureInfo.InvariantCulture, @"mel://{0}\{1}\{2}@{3}\{4}"
                                element.GetType().Namespace, 
                                element.GetType().Name, element.Name, 
                                dataContractModelProjectName,
                                dataContractModelFileName);
                            }

     

    Regarding the diagram generation, you can try creating the model first by invoking the CreateModelAction with the corresponding parameters and then you can execute the AutoLayoutShapeElementsAction. If you set the modelingDocDataFileName and modelProject parameters, the action takes care of getting a reference to the diagram for you.

    Hope this helps! Cheers!

    Aug 9, 2008 at 5:06 PM
    Diego,

    I'm doing some work in this area now, and I wonder: how would one use the DSL Integration Service from within a unit test? All the unit test usages that I see in SF are using a mock version in ModelFixture. What if I'd like to create my elements in both models, then assert that I can walk from one to the other? I would need a real implementaion of the DIS, not just a mock that only implements one method anyway.

    Any ideas? I've been using TDD for my customizations, and can't write code until I get the test failing (as opposed to merely crashing).
    Aug 12, 2008 at 9:41 PM
    Diego, thanks for all of your help. I got this working without a "real" unit test.
    Aug 13, 2008 at 2:32 PM
    You are welcome! Please let us know your feedback when you are done customizing the factory. It would be really helpfull for us.

    Thanks!