Sep 18, 2007

Model Driven Software Development with openArchitectureWare

MDSD and code generation is an interesting topic for a couple a years now.
As Microsoft is pursuing an Visual Studio integrated approach with DSL (domain specific languages) and Software Factories (like the Web Client, Web Service, etc.) there are other approaches following the UML and the OMG more closely.
Yesterday I had the chance to join an interesting session with Ueli Brawand generating C# code with the Java MDA/MDD code generation framework openArchitectureWare.
In a tutorial we were first creating a static class model with EA (Sparx Enterprise Architect). oAW is an Eclipse add-in and I was creating a workflow in a special ANT/MSBUILD/MAKEFILE related language:

<?xml version="1.0" encoding="UTF-8"?>

<workflow>

 

    <bean class="oaw.uml2.Setup" standardUML2Setup="true" />

 

    <component class="oaw.uml2.toolsupport.ea.EA_Xmi2Exporter" >

        <EapFile value="Model/MDSD.eap" />

        <PackageName value="Models/Project Model/MDSD.Tutorial" />

        <ModelFile value="" />

        <OutputSlot value="model" />

 

        <Profile value="Profile/oa.profile.uml" />

        <StereotypeProfile name="root" value="oa" />

        <Cleanup value="true"/>

    </component>

 

    <component class="oaw.emf.XmiReader">

        <modelFile value="tutorial.uml" />

        <outputSlot value="model"/>

    </component>

 

    <component class="oaw.check.CheckComponent">

        <metaModel id="EmfMM" class="oaw.type.emf.EmfMetaModel">

            <metaModelPackage value="org.eclipse.emf.ecore.EcorePackage"/>

        </metaModel>

        <metaModel id="UmlMM" class="oaw.uml2.UML2MetaModel"/>

        <metaModel id="oaMM" class="oaw.uml2.profile.ProfileMetaModel">

            <profile value="Profile/oa.profile.uml" />

        </metaModel>

 

        <checkFile value="check::MyCheck" />

        <expression value="model.eAllContents" />

    </component>

 

    <component id="dirCleaner"

          class="oaw.workflow.common.DirectoryCleaner"

        directories="src-gen"/>

 

    <component id="generator" class="oaw.xpand2.Generator" skipOnErrors="true">

        <fileEncoding value="ISO-8859-1" />

 

        <metaModel id="EmfMM" class="oaw.type.emf.EmfMetaModel">

            <metaModelPackage value="org.eclipse.emf.ecore.EcorePackage"/>

        </metaModel>

        <metaModel id="UmlMM" class="oaw.uml2.UML2MetaModel"/>

        <metaModel id="oaMM" class="oaw.uml2.profile.ProfileMetaModel">

            <profile value="Profile/oa.profile.uml" />

        </metaModel>

 

        <expand value="xpand::Root::Root FOR model"/>

 

        <outlet path="src-gen/">

            <!--postprocessor class="oaw.xpand2.output.JavaBeautifier"/-->

            <postprocessor class="oaw.xpand2.output.XmlBeautifier"/>

        </outlet>

 

    </component>

 

</workflow>


We wanted to generate code for ORM (OpenAccess) business object classes. Therefore we wrote an .xpt file defining the code generation process:

«EXTENSION oaw::uml2::support::UMLSupport»

 

«DEFINE Root FOR uml::Model»

«EXPAND OA_Gen FOREACH ownedElement»

«ENDDEFINE»

 

«DEFINE OA_Gen FOR uml::Package»

«EXPAND OA_Gen FOREACH ownedElement»

«ENDDEFINE»

 

«DEFINE OA_Gen FOR oa::BusinessObject»

«FILE name+".cs"»

using System;

using System.Collections.Generic;

using System.Text;

 

namespace BusinessObjects

{

    [OpenAccess.Persistent()]

    public class «name»

    {

«EXPAND OA_Gen_Attribute FOREACH ownedAttribute»

«EXPAND OA_Gen_Property FOREACH ownedAttribute»

    }

}

«ENDFILE»

«ENDDEFINE»

 

«DEFINE OA_Gen_Attribute FOR uml::Property-»

        private «type.name» «name»;

«ENDDEFINE»

 

«DEFINE OA_Gen_Property FOR uml::Property»

        public «type.name» «name.toFirstUpper()»

        {

            get { return «name»; }

            set { «name» = value; }

        }

«ENDDEFINE»

 

«DEFINE Root FOR uml::Element»«ENDDEFINE»

«DEFINE OA_Gen FOR uml::Element»«ENDDEFINE»

«DEFINE OA_Gen_Attribute FOR uml::Element»«ENDDEFINE»

«DEFINE OA_Gen_Property FOR uml::Element»«ENDDEFINE»


Resulting in the following .cs file:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace BusinessObjects

{

    [OpenAccess.Persistent()]

    public class Order

    {

        private DateTime shippingDate;

        private string customer;

        private OrderItem orderItems;

 

 

        public DateTime ShippingDate

        {

            get { return shippingDate; }

            set { shippingDate = value; }

        }

 

        public string Customer

        {

            get { return customer; }

            set { customer = value; }

        }

 

        public OrderItem OrderItems

        {

            get { return orderItems; }

            set { orderItems = value; }

        }

 

    }

}



In my opinion oAW makes sense:
- for (bigger) "Product Line Architecture" - like projects
- to generated entity/business object/data layer code (20 and more BOs)
- only for parts of an application
- to come around shortcomings of EA concerning code generation

Aug 20, 2007

Software Configuration Management / Branching & Merging Guidance

There is more reading material from Microsoft, especially dedicated to branching and merging of codelines and artifacts:

Microsoft Team Foundation Server Branching Guidance

and a book from Stephen P. Berczuk:

Software Configuration Management Patterns

Allow me these posts - even if they are not directly related to .NET development :-)

TFS Guide Final Release


Microsoft's patterns & practices group recently uploaded the final release of the Team Development with Visual Studio Team Foundation Guide to codeplex.

This almost 500 pages 'book' provides a lot of very detailed guidance for development teams starting to use TFS as well as for team optimizing their work with the tools.

The How-To section in the appendix provides step-by-step instructions about:

- Add a New Developer to Your Project in Visual Studio 2005 Team Foundation Server
- Automatically Run Code Analysis with Team Build in Visual Studio Team Foundation Server
- Create a Custom Report for Visual Studio Team Foundation Server
- Create a “Risk over Time” Report for Visual Studio Team Foundation Server
- Create Custom Check-in Policies in Visual Studio Team Foundation Server
- Create Your Source Tree in Visual Studio Team Foundation Server
- Customize a Process Template in Visual Studio Team Foundation Server
- Customize a Report in Visual Studio Team Foundation Server
- Manage Projects in Visual Studio Team Foundation Server
- Migrate Source Code to Team Foundation Server from Visual Source Safe
- Perform a Baseless Merge in Visual Studio Team Foundation Server
- Set Up a Continuous Integration Build in Visual Studio Team Foundation Server
- Set Up a Scheduled Build in Visual Studio Team Foundation Server
- Structure ASP.NET Applications in Visual Studio Team Foundation Server
- Structure Windows Applications in Visual Studio Team Foundation Server
- Structure Your Source Control Folders in Team Foundation Server

All in all a very recommending piece of reading.

Aug 15, 2007

System.IO.Compression in .NET 2.0

I just realized that .NET 2.0 introduced compression/zipping functionality:

using System.IO.Compression;

MemoryStream ms = new MemoryStream();
GZipStream compressedzipStream = new GZipStream(ms , CompressionMode.Compress, true);
compressedzipStream.Write(buffer, 0, buffer.Length);
compressedzipStream.Close();

Jul 27, 2007

Simple animated WPF application - with no line of code

Playing around with Microsoft Expression Blend 2 May CTP I noticed that this tool got much better since my last trial in September 2006. There is even already an August CTP ready for download.

So let's create a simple WPF application without writing one line of code. After starting or when the "Hello World" text is clicked, it should turn around it's upper x axis.


- color the window Background with a red-to-black gradient brush
- add a StackPanel to the default Grid type LayoutRoot under window
- add a Rectange below the Stackpanel that is filled with a black-to-white gradient brush (with a 35% opacity)
- also add a label to the LayoutRoot with the "Hello World" Content
- in the "Objects and Timeline" window add a new timeline "TurnLable"
- select the label and move the timeline to 1 second where you modify the RenderTransform property to translate in the Y direction (-48) and scale Y (-1)
- select the lable and move the timeline to 2 seconds where you set the RenderTransform translation Y back to 0 and the scale Y to 1
- in the Triggers window add a Window.Loaded trigger that Begins a TurnLable
- in the Triggers window add a Window.MouseDown trigger that does the same



Et voilĂ !

Here's the XAML for reference:

<Window

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    x:Class="BookCover.Window1"

    x:Name="Window"

    Title="Window1"

    Width="640" Height="480" Background="{DynamicResource BlackRedGradient}">

 

    <Window.Resources>

        <LinearGradientBrush x:Key="BlackRedGradient" EndPoint="1,0.5" StartPoint="0,0.5">

            <GradientStop Color="#FF000000" Offset="0"/>

            <GradientStop Color="#FF790606" Offset="1"/>

        </LinearGradientBrush>

        <Storyboard x:Key="TurnLable">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="-48"/>

                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">

                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="-1"/>

                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="1"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

    </Window.Resources>

 

    <Window.Triggers>

        <EventTrigger RoutedEvent="FrameworkElement.Loaded">

            <BeginStoryboard x:Name="TurnLable_BeginStoryboard" Storyboard="{StaticResource TurnLable}"/>

        </EventTrigger>

        <EventTrigger RoutedEvent="Mouse.MouseDown">

            <BeginStoryboard Storyboard="{StaticResource TurnLable}"/>

        </EventTrigger>

    </Window.Triggers>

 

    <Grid x:Name="LayoutRoot">

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"/>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition Height="0.29*"/>

            <RowDefinition Height="0.389*"/>

            <RowDefinition Height="0.321*"/>

        </Grid.RowDefinitions>

        <Label RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Left" Margin="161,52.08,0,0" x:Name="label" VerticalAlignment="Top" Content="Hello WPF" FontFamily="Verdana" FontSize="48" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" Grid.Row="1">

            <Label.RenderTransform>

                <TransformGroup>

                    <ScaleTransform ScaleX="1" ScaleY="1"/>

                    <SkewTransform AngleX="0" AngleY="0"/>

                    <RotateTransform Angle="0"/>

                    <TranslateTransform X="0"/>

                </TransformGroup>

            </Label.RenderTransform>

        </Label>

        <StackPanel Margin="0,129.92,0,0" Grid.RowSpan="2">

            <Rectangle Opacity="0.35" Stroke="#FF000000" Width="633.6" Height="174.272">

                <Rectangle.Fill>

                    <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">

                        <GradientStop Color="#FF000000" Offset="0"/>

                        <GradientStop Color="#FFFFFFFF" Offset="1"/>

                    </LinearGradientBrush>

                </Rectangle.Fill>

            </Rectangle>

        </StackPanel>

        <ToolBarPanel Opacity="1" Margin="0,0,0,61.92">

            <StackPanel Height="100">

                <ToolBar Width="100" Height="100">

                    <Button Width="100" Height="100" Content="Button" Foreground="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>

                </ToolBar>

                <Label ToolTip="This is my toolbars tool tip!" Width="100" Height="100" Content="Hello Markus" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" Panel.ZIndex="0"/>

            </StackPanel>

        </ToolBarPanel>

    </Grid>

</Window>

Namespace Naming

Just came across an MSDN article talking about namespace naming guidelines under http://msdn2.microsoft.com/en-us/library/893ke618(VS.71).aspx

In summary:

namespace <companyname>.<product>.<feature>.<sub-feature>


So think twice when your namespaces should fit for the next ten years.

Where custom Exceptions should derive from?

A common question is whether your application specific exceptions should base on System.ApplicationException or from System.Exception?

I stick to Cwalina/Abrams (Framework Design Guidelines/Addison Wesley) position to use System.Exception as a base class.

The reason for this is that ApplicationException was indeed once thought as a base for all custom application exceptions, but was misused in some .NET framework exceptions as well.

Jul 18, 2007

1 host, 2 services, 1 endpoint each, but only 1 port ?

The question came up, if it would be possible to host two or more WCF services (in the same executable to be precise) on the same port using the WSHttpBinding binding?

I wrote a little test and the question is: Yes. I'm guessing this is due to the fact that WCF only uses one listener here and there is no port conflict. Using WSDualHttpBinding would probably cause conflicts on the callback ports (if there is more than one client executable (WCF listener) implementing the callback service).

Port sharing also works for the TCP binding. However, throws an exception when bindings are mixed (one service to use HTTP and the other TCP)

Jul 17, 2007

Manage the instance object for a WCF service

On certain occassions it may be necessary to control the creation and destruction of your WCF service instances (that may be create per call, per session or single).

Therefore you need to implement IInstanceProvider:

public class MyServiceInstanceProvider : IInstanceProvider

{

    public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)

    {

        object instance = null;

 

        instance = new MyService();

 

        return instance;

    }

 

    public object GetInstance(System.ServiceModel.InstanceContext instanceContext)

    {

        return GetInstance(instanceContext, null);

    }

 

    public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)

    {

        IDisposable disposableInstance = instance as IDisposable;

        if (disposableInstance != null) disposableInstance.Dispose();

    }

}


and IServiceBehavior (where the custom provider is attached to the endpoints)

public class MyServiceServiceBehavior : IServiceBehavior

{

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)

    {

        foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)

        {

            ChannelDispatcher cd = cdb as ChannelDispatcher;

            if (cd != null)

            {

                foreach (EndpointDispatcher ed in cd.Endpoints)

                {

                    ed.DispatchRuntime.InstanceProvider = new MyServiceInstanceProvider();

                }

            }

        }

    }

 

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { }

}


The service behavior is added in code here

ServiceHost serviceHost = new ServiceHost(typeof(MyService));

serviceHost.Description.Behaviors.Add(new MyServiceServiceBehavior());

serviceHost.Open();

Jul 16, 2007

WCF throttling and DoS prevention

To enable restrictions on the number of clients and the load they place on a WCF service the following options are available:
- limit the maximum number of concurrent sessions
- limit the number of concurrent calls
- limit the maximum number of concurrent instances
This is available in service haviour settings.

Furthermore there is TransportBindingElement.MaxReceivedMessageSize that
- limit the maximum received payload. This defaults to 64kB.

As Nicholas Allen points out there are even more settings possible, e.g. with Transport Quotas.

Jul 9, 2007

WCF error practices / Faults

I recently gave a half-day training for a group of Windows embedded developers and decided to talk about error handling practices in WCF services (beside the mandatory topics of Architecture, Contracts, Bindings, Hosting, Security and Versioning).

First of all, the contract needs to be decorated with a FaultContract definition to prepare clients about what to expect concerning SOAP exceptions (faults):

[ServiceContract(Namespace="http://www.mleder.blogspot.com/EES/WME/Camp2007/06/20")]

public interface IWmeService

{

    [OperationContract]

    [FaultContract(typeof(WmeFault))]

    WmeRes SayHello(WmeRequest req);

}


WmeFault is a simple custom DataContract class of ours

[DataContract]

public class WmeFault

{

    private string why;

    [DataMember]

    public string Why

    {

        get { return why; }

        set { why = value; }

    }

 

    public WmeFault(string why)

    {

        this.Why = why;

    }

}


In the service implementation you just throw an exception with this type

public class WmeService : IWmeService

{

    public WmeRes SayHello(WmeRequest req)

    {

        if (req.Text.Contains("Markus"))

        {

            throw new FaultException<WmeFault>(new WmeFault("no, Markus"));

            // throw new FaultException("no, Markus");

        }

 

        WmeRes wmeRes = new WmeRes();

        return wmeRes;

    }

}


And on the client side we catch our nicely-modeled SOAP fault message as we always do with regular System.Exception.

try

{

    WmeRequest req = new WmeRequest();

    req.Text = text;

    wmeService.SayHello(req);

}

catch (FaultException<WmeFault> fex)

{

    Console.WriteLine("Client fault FaultException<WmeFault> : " + fex.Detail.Why);

}

Jun 29, 2007

WCF Callback Port for WSDualHttpBinding

When using a callback contract and the WSDualHttpBinding WCF binding then port 80 is assigned per default. As this produces an obvious problem when IIS is installed, you have to configure another port for your callback service on the client side.

// set callback port for dual HTTP binding as another channel is required. Not for npipe, tcpip.

WSDualHttpBinding binding = cf.Endpoint.Binding as WSDualHttpBinding;

if (binding != null)

{

    int port = int.Parse((string)ConfigurationManager.AppSettings["DeviceServerCallbackPort"]);

    binding.ClientBaseAddress = new Uri(cf.Endpoint.Address.Uri.Scheme + "://"

        + System.Environment.MachineName + ":" + port + "/" + typeof(IDeviceServerService).Name);

}