ServicesResourcesConferencesOur TeamWeblogsAboutContact
   

Subscriptions

Post Categories

Affiliations

Archives

Generating async WCF OperationContract signatures with a T4 template

From time to time it happens that people want to use the async programming model in WCF based on the IAsyncResult approach - either on the client or the service side. Writing all the asynchronous operation contract signatures is quite a tedious and error-prone task. Given this fact, design-time code generation with a T4 template may come in very handy for this purpose.
The following is my first try to create such a T4 template and it seems to work for the scenarios I need it for. Please refer to code below to see how to use the template: it is easy and straight-forward.

<#
/*
   Copyright (c) 2009, thinktecture (http://www.thinktecture.com).
   All rights reserved.

   Permission is hereby granted to use this software, for both commercial
   and non-commercial purposes, without limitations and free of charge.
   Permission is hereby granted to copy and distribute the software for
   non-commercial purposes. A commercial distribution is NOT allowed without
   prior written permission of the authors.

   This software is supplied "AS IS". The authors disclaim all warranties,
   expressed or implied, including, without limitation, the warranties of
   merchantability and of fitness for any purpose. The authors assume no
   liability for direct, indirect, incidental, special, exemplary, or
   consequential damages, which may result from the use of this software,
   even if advised of the possibility of such damage.
*/
#>
<#@ template debug="true" hostspecific="true" #>
<#@ output extension="cs" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Collections.Generic" #>
<#   
    // USAGE:
    // 1. Drop this file into your VS project
    // 2. Rename this file to match this pattern: {YOUR_SERVICECONTRACT_FILE}Async.tt
    // 3. The async version of your original service contract gets generated as
    //    {YOUR_SERVICECONTRACT_FILE}Async.cs
   
    EnvDTE.DTE dte = GetEnvDTE();

    string sourceFileName = dte.Solution.FindProjectItem(Host.TemplateFile).Name;
    sourceFileName = sourceFileName.Replace("Async.tt", ".cs");
  
    ProjectItem enumProjectItem = dte.Solution.FindProjectItem(sourceFileName);
    FileCodeModel codeModel = enumProjectItem.FileCodeModel;

    CodeNamespace codeNamespace = FindNamespace(codeModel.CodeElements);
    CodeInterface codeInterface = FindInterface(codeModel.CodeElements);
    List<CodeFunction> codeFunctions = FindMethods(codeInterface.Children);
       
    //System.Diagnostics.Debugger.Break();
#>
using System;
using System.ServiceModel;

namespace <#= codeNamespace.Name #>
{
    [ServiceContract]
    public interface <#= codeInterface.Name #>Channel :
        <#= codeInterface.Name#>
    {                   
        <#
            PushIndent("        ");
           
            int methodCount = 0;
           
            foreach (CodeFunction method in codeFunctions)
            {
                if(methodCount > 0)
                {
                    WriteLine(String.Empty);
                    WriteLine(String.Empty);
                }
               
                WriteAsyncOperationContract(method);
                WriteLine(string.Empty);
               
                methodCount ++;
            }
           
            ClearIndent();
        #>
    }
}

<#+
    private void WriteAsyncOperationContract(CodeFunction method)
    {
        string operationContractValue = TryGetOperationContractValue(method);
       
        WriteLine("[OperationContract(");
       
        if(String.IsNullOrEmpty(operationContractValue))
        {           
            Write("    Action = \"");
            Write(method.Name + "\",");
            WriteLine(String.Empty);
            Write("    ReplyAction = \"");
            Write(method.Name + "Reply\",");
            WriteLine(String.Empty);
        }
        else
        {
            ClearIndent();
            WriteLine("            " + operationContractValue + ",");
            PushIndent("        ");
        }
       
        WriteLine("    AsyncPattern = true)]");
       
        Write("IAsyncResult Begin");
        Write(method.Name);
        Write("(");
               
        foreach(CodeElement element in method.Parameters)
        {
            int count = 0;           
            CodeParameter parameter = element as CodeParameter;
       
            if (parameter != null)
            {
                Write(parameter.Type.AsString + " ");
                Write(parameter.Name);
               
                if(count < method.Parameters.Count)
                    Write(", ");
               
                count++;
            }
        }
       
        Write("AsyncCallback callback, object asyncState);");
       
        WriteLine(String.Empty);
        WriteLine(String.Empty);
       
        Write(method.Type.AsString + " ");
        Write("End");
        Write(method.Name);
        Write("(IAsyncResult result);");       
    }
   
    private string TryGetOperationContractValue(CodeFunction method)
    {
        string attributeValue = String.Empty;
       
        foreach(CodeElement attributeElement in method.Attributes)
        {
            CodeAttribute attribute = attributeElement as CodeAttribute;
           
            if(attribute != null)
            {       
                if(attribute.Name == "OperationContract" || attribute.Name == "OperationContractAttribute")
                {
                    attributeValue = attribute.Value;
                    break;
                }
            }
        }
       
        return attributeValue;
    }
   
    private CodeNamespace FindNamespace(CodeElements elements)
    {
        foreach (CodeElement element in elements)
        {
            CodeNamespace ns = element as CodeNamespace;
       
            if (ns != null)
                return ns;
        }
   
        return null;
    }
   
    private CodeInterface FindInterface(CodeElements elements)
    {
        foreach (CodeElement element in elements)
        {
            CodeInterface codeInterface = element as CodeInterface;
       
            if (codeInterface != null)
                return codeInterface;
   
            codeInterface = FindInterface(element.Children);
   
            if (codeInterface != null)
                return codeInterface;
        }
   
        return null;
    }
   
    private List<CodeFunction> FindMethods(CodeElements elements)
    {
        List<CodeFunction> methods = new List<CodeFunction>();
       
        foreach (CodeElement element in elements)
        {
            CodeFunction method = element as CodeFunction;
       
            if (method != null)
                methods.Add(method);           
        }
   
        return methods;
    }
   
    private EnvDTE.DTE GetEnvDTE()
    {
        IServiceProvider hostServiceProvider = (IServiceProvider)Host;
       
        if (hostServiceProvider == null)
               throw new Exception("Host property returned unexpected value (null)");
       
        EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
       
        if (dte == null)
               throw new Exception("Unable to retrieve EnvDTE.DTE");
   
        return dte;
    }
#>

This is it - T4 programming reminds me of my very old days as a classical COM and ASP programmer... :)


posted Wednesday, June 24, 2009 12:01 PM with 0 Comments

Custom TraceListener writing trace messages to the .NET Services Service Bus

Dominick challenged me the other day...
For being able to better log information, warning and error messages in a truly distributed development, testing and operation environment, I built a sample custom TraceListener which leverages the Service Bus to pump tracing messages into the cloud.

Currently I am using the message-buffer-based volatile queuing mechanism in the Service Bus, but will move on to the Queue features introduced in the March 2009 bits soon.

There is a very simple ServiceContract I am using:

[ServiceContract(ConfigurationName = "Thinktecture.ServiceBusTraceListener")]
public interface IMessageTracing
{
    [OperationContract(IsOneWay = true)]
    void WriteMessage(string message);
}

All the magic is done in my custom TraceListener implementation. Here is a snippet of the relevant boilerplate code:

public class ServiceBusTraceListener : TraceListener
{
    ...
    
    public ServiceBusTraceListener()
        : base("Thinktecture.ServiceBusTraceListener")
    {
        CreateInMemoryQueue();
        SpawnWorkerThread();
    }

    ...

    public override void Write(string message)
    {
        WriteLine(message);
    }

    public override void WriteLine(string message)
    {
        traceMessagesQueue.Enqueue(message);
    }

    ...
}


This simple implementation uses a thread-safe in-memory queue data structure which is filled from within the TraceListener's WriteLine method. On 'the other side' of the queue there is a consuming thread which reads the messages from the queue (the in-memory one) and sends them to the Service Bus via a NetEventRelayBinding-enabled channel.
The background thread doing the Service Bus communication picks up all relevant WCF configuration from the config file (convention-based).

Download the sample solution.


posted Wednesday, June 24, 2009 10:24 AM with 0 Comments

thinktecture Security Token Service Starter Kit - or: "Look ma: even *I* can have a STS!"

We are happy to announce the thinktecture Security Token Service (STS) Starter Kit. It shows how to build a basic yet powerful STS based on Geneva Framework (Beta 2) which integrates with all the nice and powerful ASP.NET-isms like membership, roles and profiles.

thinktecture STS Starter Kit
thinktecture STS Starter Kit IIS config
thinktecture STS Starter Kit

The heart of the STS is configured with a simple web.config entry like this:

<starterSTS siteName="thinktecture Security Token Service Starter Sample"
              issuerUri="http://sample.thinktecture.com/trust"
              claimsBaseUri="http://sample.thinktecture.com/claims"
              requireEncryption="false"
              requireSSL="false"
              enableMessageWSTrust="true"
              enableMixedWSTrust="false" />

Read Dominick's blog post for more details and please make sure to watch the Setup & Overview screencast.
Any feedback is highly appreciated!


posted Tuesday, May 26, 2009 9:01 AM with 0 Comments

Geneva-based WS-Federation metadata document generation wizard (or: "Oops, I did it again!")

Starting with Beta 2 of the Geneva Framework there is nice support of metadata-driven behavior and code generation. We (Mr. Security himself and me) came across some situations where one wants to generate manually the WS-Federation metadata document and then use this XML e.g. with the fedutil.exe tool or the integrated Geneva tooling inside Visual Studio.
I couldn't resist and build a wizard which helps generating the metadata document... sorry :) Feels like Groundhog Day.

Here we go.

WS-Federation Metadata document generator - page 1

WS-Federation Metadata document generator - page 2

WS-Federation Metadata document generator - page 3

WS-Federation Metadata document generator - page 4

WS-Federation Metadata document generator - page 5

WS-Federation Metadata document generator - page 6

WS-Federation Metadata document generator - page 7

WS-Federation Metadata document generator - page 8

WS-Federation Metadata document generator - page 9

Note: I am using the DevExpress wizard control and dependent assemblies. Therefore the size of the ZIP is rather big (too big, IMHO) - sorry.

For whom it may help: Download.


posted Friday, May 22, 2009 1:24 PM with 1 Comments

Axum and the CCR: what and how?

This is copied verbatim from a MSDN Forums post about how Axum uses parts of the CCR:

Here's what we did:

1. We took the CCR sources, changed most of the names, slightly refactored the interfaces and added a few things.
2. We built it into Microsoft.Axum.Runtime.dll
3. We built channel ports on top of CCR Ports (renamed OrderedInteractionPoints).
4. We exposed OIP to programmers (see the WebFetcher sample).
5. We built 'async,' 'sync,' and 'const' empty/full storage capabilites on some additions we made to CCR.
6. The 'receive' expression utilizes a Receiver to hook into the source.

One reason for the rename is that in the CTP, you really need to use the Axum capabilities (data-flow networks, receives, etc.) to program the local (within-domain) message-passing capabilites, and we didn't want to create another distribution of the CCR. If you want to use CCR, please get it separately, as it is not currently safe to use with Axum unless you go through the language capabilities. It is likewise not generally safe to create your own threads from within an Axum domain, and there is no need to.
Source


posted Monday, May 11, 2009 5:33 PM with 0 Comments

Information Card Foundation DACH-Initiative: kein Gremium, sondern eine Plattform

Wir hoffen, dass sich durch diese Initiative viele Unternehmen inspirieren lassen, Identitäts-Management im Allgemeinen und Authentifizierung mit Information Cards im Speziellen genauer unter die Lupe zu nehmen.

PDF-Flyer in deutsch als Download.


ICF DACH Initiative
posted Monday, May 11, 2009 5:08 PM with 0 Comments

Axum - a service-oriented programming language(?)

The more I read about Axum and hack the first lines of code, the more I feel there will be something that could make my life easier.
In the past years I tried to advocate the idea of service-orientation (and no: I am *not* talking about SOA - if you ever attended a session of mine you know that I am more than explicit about this point).

I like the idea of explicit boundaries, description via interfaces and contracts and definition of policies for runtime information. It goes that far that I try to follow the service-orientation principles wherever it makes sense (usually being a bit weak on the policies side).
Please note that I am not talking about WCF, I am talking about service-orientation. Yes, WCF is quite a nice framework (read: tool) to realize service-oriented systems. But then it is also a communication foundation which means it can be used to accomplish a lot more than the prototypical thinking around service-orientation.

Service-orientation is an attitude.

Now with Axum I can smell service-orientation in my language.

In service orientation there are services. In service orientation data is exchanged via channels and messages. In service orientation there are message handlers. In service orientation there are interfaces and contracts to describe the boundary.

In Axum there are domains for isolation. In Axum information is passed via channels and messages. In Axum there are agents for handling communication (either in a domain or between domains). In Axum there is schema to describe the exchanged information.

Pure joy (there seem to be more equivalent ideas, but this is good enough for starters).
We will see how this all turns out. On one hand, I am still starting to understand Axum. On the other hand, Axum is currently an incubation project, nothing more.

P.S.: the last Microsoft incubation project I was working on/with was code-named "Biztalk Services". This is now known as .NET Services as part of the Azure Services Platform...


BTW: I am *not* advocating that every class should be a service (at least there is no concept of a class in Axum ;)).


posted Monday, May 11, 2009 1:56 PM with 0 Comments

I *think* I see the future: Axum (or is it just Erlang for .NET?)

Holy cow. There have been a lot of announcements recently in the space of parallel programming, language- and tool-wise (just look at what happened at PDC08). And I must admit I could not keep up with researching each and every announcement.

I played around a bit the other day (OK, the other year...) with the Concurrency & Coordination Runtime (CCR) from the Microsoft Robotics team - but I could not really get convinced that this is what we are supposed to do in the future when planning, architecting and writing highly distributed, concurrent applications (or actually algorithms or 'pieces of code'). No, this just feels too clumsy, too much tool- and library-heavy.
And no, I did not yet look in depth into the new stuff that .NET 4.0 will bring us. Just a matter of time, I guess.

Then, on Friday, I stumbled over something that looks promising: Axum.
And the more I read about it and the more I play around (it is really just playing, trying to grok, to understand, to learn) the more I *think* this *could* be the future of parallel programming and processing. One nice thing is that Axum builds on top of some of the CCR features, but gives us a language and not a lib and tool feeling.

Browsing the web I can already see discussions how Axum relates and compares to Erlang. I not really such a big language expert, but borrowing from a very successful language (which solves exactly the problems it was invented for) is nothing to trash :)

Just a note, though.


posted Monday, May 11, 2009 11:01 AM with 2 Comments

[What's new in WCF4] Protocol bridging & fault tolerance with the Routing Service - or: "Look ma: Really just one service to talk to!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

Let's look at some more features of the new RoutingService in WCF4.
We are going to expose our RoutingService via an basicHttpBinding-based request-reply endpoint:

<service behaviorConfiguration="routingData"
  name="System.ServiceModel.Routing.RoutingService">
    <host>
      <baseAddresses>
        <add  baseAddress="http://localhost:7777/Services/Universal"/>
      </baseAddresses>
    </host>

    <endpoint address=""
              binding="basicHttpBinding"
              name="requestReplyEndpoint"
              contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>

Then 'internally' we have two business services, HelloService1 and HelloService2 :)
One of them is exposed via a basicHttpBinding-based endpoint, the other one uses netTcpBinding.

We can now configure our router in such a way that it still accepts incoming messages via basicHttpBinding (actually we just did that and do not need to change anything) but can route messages to the netTcpBinding-based service.

<client>
  <endpoint name="HelloService1"
            address="net.tcp://localhost:7778/Services/Hello"
            binding="netTcpBinding"
            contract="*" />
  <endpoint name="HelloService2"
            address="http://localhost:7777/Services/Hello"
            binding="basicHttpBinding"
            contract="*" />
</client>

OK, great.
Our routing table looks like this, which means we will always (try to) route to the netTcpBinding-based service.

<routingTables>
    <table name="mainRoutingTable">
      <entries>
        <add filterName="xPath1" endpointName="HelloService1" />
      </entries>
    </table>
</routingTables>

But what happens if *** happens?
We can specify alternate endpoints which will be called when a CommunicationException or TimeoutException occurs in the RoutingService while calling the original target endpoint.

<routingTables>
    <table name="mainRoutingTable">
      <entries>
        <add filterName="xPath1" endpointName="HelloService1" alternateEndpoints="endpointsList" />
      </entries>
    </table>
</routingTables>
<alternateEndpoints>
<list name="endpointsList">
    <endpoints>
        <add endpointName="HelloService2" />
        <!--<add endpointName="HelloService3" />-->
    </endpoints>
</list>
</alternateEndpoints>

We can have as many alternate endpoints as we like, in this sample it is just one active one, namely our HelloService2 which is exposed via a basicHttpBinding endpoint.

That's it: protocol bridging & fault tolerance with the Routing Service in WCF4.


posted Friday, May 08, 2009 3:33 PM with 2 Comments

[What's new in WCF4] Routing Service - or: "Look ma: Just one service to talk to!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

The Intermediate Routing pattern is a well understood pattern. Some people apply it to have just one service entry point with a universal contract and then route incoming messages to the appropriate business services.
Others use it to determine the path of a message within a system, which means there can be a cascade of routers each responsible for different aspects of routing messages.
WCF was always a bit short in this respect. Sure, there are numerous implementations based on WCF 3.x (just Google...), just recently Dominick and myself implemented something like this for a customer. But there is nothing that came straight in the core platform. This now changes with WCF4.

There is a generic routing service in WCF4 which enables routing for diiferent message exchange patterns (MEPs). The responsible class is System.ServiceModel.Routing.RoutingService.

WCF4 Routing Service

As we can see this service implements four different contracts to fulfill different MEPs and session semantics. If we want to host a routing service we do not need a lot of work, just host it (like this for a self-hosted case):

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

try
{
    serviceHost.Open();
    Console.WriteLine("WCF Routing Service running...");
    Console.WriteLine("Press <ENTER> to terminate router.");

    Console.ReadLine();
    serviceHost.Close();
}
catch (CommunicationException)
{
    serviceHost.Abort();
}

        
OK, easy.
Each of the contracts RoutingService implements represent the universal contract pattern (Message in, Message out, or just Message in for the one-way case). WCF4 always uses the async operation pattern, which totally makes sense as we have bound I/O happening in the routing service:

[ServiceContract(SessionMode=SessionMode.Allowed)]
public interface ISimplexDatagramRouter
{
    [OperationContract(AsyncPattern=true, IsOneWay=true, Action="*")]
    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
    void EndProcessMessage(IAsyncResult result);
}

[ServiceContract(SessionMode=SessionMode.Required)]
public interface ISimplexSessionRouter
{
    [OperationContract(AsyncPattern=true, IsOneWay=true, Action="*")]
    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
    void EndProcessMessage(IAsyncResult result);
}

[ServiceContract(SessionMode=SessionMode.Allowed)]
public interface IRequestReplyRouter
{
    [OperationContract(AsyncPattern=true, IsOneWay=false, Action="*", ReplyAction="*"), GenericTransactionFlow(TransactionFlowOption.Allowed)]
    IAsyncResult BeginProcessRequest(Message message, AsyncCallback callback, object state);
    Message EndProcessRequest(IAsyncResult result);
}

[ServiceContract(SessionMode=SessionMode.Required, CallbackContract=typeof(IDuplexRouterCallback))]
public interface IDuplexSessionRouter
{
    [OperationContract(AsyncPattern=true, IsOneWay=true, Action="*"), GenericTransactionFlow(TransactionFlowOption.Allowed)]
    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
    void EndProcessMessage(IAsyncResult result);
}

[ServiceContract(SessionMode=SessionMode.Allowed)]
internal interface IDuplexRouterCallback
{
    [OperationContract(AsyncPattern=true, IsOneWay=true, Action="*"), GenericTransactionFlow(TransactionFlowOption.Allowed)]
    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
    void EndProcessMessage(IAsyncResult result);
}

Pure love :)

So, that was for the WCF infrastructure geek - but how do we actually route? What do we route?
Enter message filters.
The routing service in WCF4 uses message filters in order to route messages. Message filters have always been in WCF since the first version and just now have a prominent role and also got some new filters. This is the list of available message filters:

WCF4 Message Filters

For a first rendezvous with routing we will just use the MatchAllMessageFilter. This filter just returns true and does not do any logic in the Match() method and thus is a pass-through filter.
Message filter will be used inside entries in a RoutingTable. These entries specify which endpoint to call from the RoutingService when the given MessageFilter returns true. The routing table is configured as a service behavior.
Here is a sample config implementing the just explained stuff:
        
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="routingData"
          name="System.ServiceModel.Routing.RoutingService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:7777/Services/Universal"/>
          </baseAddresses>
        </host>

        <endpoint address=""
                  binding="basicHttpBinding"
                  name="requestReplyEndpoint"
                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>        
        <behavior name="routingData">
          <serviceMetadata httpGetEnabled="True"/>          
          <routing routingTableName="mainRoutingTable" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <client>
      <endpoint name="HelloService" address="http://localhost:7777/Services/Hello" binding="basicHttpBinding" contract="*" />
    </client>
    
    <routing>
      <filters>
        <filter name="MatchAllFilter" filterType="MatchAll" />
      </filters>      
      <routingTables>
        <table name="mainRoutingTable">
          <entries>
            <add filterName="MatchAllFilter" endpointName="HelloService" />
          </entries>
        </table>
      </routingTables>
    </routing>

  </system.serviceModel>
</configuration>

This means we expose an IRequestReplyRouter with basicHttpBinding at http://localhost:7777/Services/Universal to the consumers. As a final target service we just have one service (our beloved HelloService) and its endpoint is defined in the <client> section.
Based on the message filter which is referenced through an entry in the routing table the messages being sent to our routing endpoint will be routed through to our HelloService.
Admittedly, this sample is not really real-worldish :) But it should give a first understanding of the RoutingService in WCF4.

To make the whole picture complete, we will let our client/consumer just talk to the routing endpoint - the client does not know anything about the HelloService (besides the contract of course).

<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="http://localhost:7777/Services/Universal"
                binding="basicHttpBinding"
                contract="IHelloService" />
    </client>   
  </system.serviceModel>
</configuration>

Please note that until now we just do plain routing in the sense of message dispatching. We can not do message transformations (yet). This should be covered in a future post, though.

But let's look at two more message filters, the ActionMessageFilter and the XPathMessageFilter, which both come in very handy for typical routing scenarios.
The ActionMessageFilter checks whether a given action value is fulfilled for the incoming message. Likewise, the XPathMessageFilter checks whether a given XPath expression is true for an incoming message. Usually, the XPath filter needs namespace table entries for managing XML namespaces.
In order to use either of these filters to route our client messages to the HelloService we can change the filters and routing table configuration like this:

<routing>
  <filters>
    <!--<filter name="action1" filterType="Action" filterData="http://tempuri.org/IHelloService/SayIt" />-->
    <filter name="xPath1" filterType="XPath" filterData="/s:Envelope/s:Header/wsa:Action = 'http://tempuri.org/IHelloService/SayIt'" />
  </filters>
  <routingTables>
    <table name="mainRoutingTable">
      <entries>
        <!--<add filterName="action1" endpointName="HelloService" />-->
        <add filterName="xPath1" endpointName="HelloService" />
      </entries>
    </table>
  </routingTables>
  <namespaceTable>
    <add prefix="s" namespace="http://schemas.xmlsoap.org/soap/envelope/" />
    <add prefix="wsa" namespace="http://schemas.microsoft.com/ws/2005/05/addressing/none" />
  </namespaceTable>
  <alternateEndpoints>        
  </alternateEndpoints>
</routing>

The two filter configurations are equivalent in their functionailty based on the given filter data values.
Pretty straight.forward, IMO.

One more thing: if the originally specified endpoint in a routing table entry cannot be reached then the list of alternate endpoints is checked (OK, in our sample it is empty, but you get the idea) and the routing service logic tries to call them.

Honestly, I can see a number of customers embracing this new feature (and in this post I was just scratching the surface).

OK; that's it for now for a first introduction to the routing capabilities in WCF4.
Stay tuned for more.


posted Friday, May 08, 2009 1:47 PM with 4 Comments

[What's new in WCF4] Discovery announcements - or: "Look ma: I can see when my service goes online or offline!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

We already talked about some basics of discovery support in WCF4. Another nice feature in this area are announcements.
If you as a service consumer are interested when service endpoints go on- and offline you can get notified. The only thing to do is to host an AnnouncementService (provided by WCF4) on the consuming side and subscribe to the OnlineAnnouncementReceived and OfflineAnnouncementReceived events.

For this work the service needs to send out announcements messages in the first place. This can be achieved by adding
an announcement endpoint:

<configuration>
  <system.serviceModel>
    <services>
      <service name="HelloService"
               behaviorConfiguration="serviceBehavior">
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="IHelloService" />        
        <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceDiscovery>
            <announcementEndpoints>
              <endpoint name="udpAnnouncement" kind="udpAnnouncementEndpoint"/>
            </announcementEndpoints>
          </serviceDiscovery>
        </behavior>
      </serviceBehaviors>      
    </behaviors>
  </system.serviceModel>
</configuration>

This is all that needs to be done on the service host side. Remember that the udpAnnouncementEndpoint is one of the new standard endpoints in WCF4.

Consumers can then use the approach outlined in the introduction of this post. I.e. creating an AnnouncementService:

var announcementService = new AnnouncementService();
announcementService.OnlineAnnouncementReceived +=
    new EventHandler<AnnouncementEventArgs>(announcementService_OnlineAnnouncementReceived);
announcementService.OfflineAnnouncementReceived +=
    new EventHandler<AnnouncementEventArgs>(announcementService_OfflineAnnouncementReceived);

announcementServiceHost = new ServiceHost(announcementService);
announcementServiceHost.AddServiceEndpoint(new UdpAnnouncementEndpoint());
announcementServiceHost.Open();

In the registered event handlers we can then check whether this is actually an announcement for the contract we are interested in:

private void announcementService_OnlineAnnouncementReceived(object sender, AnnouncementEventArgs e)
{
    var contractXQN = GetContractXmlQualifiedName();

    if (e.AnnouncementMessage.EndpointDiscoveryMetadata.ContractTypeNames.Contains(contractXQN))
    {
        FireOnlineEvent();
    }
}

private void announcementService_OfflineAnnouncementReceived(object sender, AnnouncementEventArgs e)
{
    var contractXQN = GetContractXmlQualifiedName();

    if (e.AnnouncementMessage.EndpointDiscoveryMetadata.ContractTypeNames.Contains(contractXQN))
    {
        FireOfflineEvent();
    }
}

private static XmlQualifiedName GetContractXmlQualifiedName()
{
    var contract = ContractDescription.GetContract(typeof(IHelloService));
    var contractXQN = new XmlQualifiedName(contract.Name, contract.Namespace);

    return contractXQN;
}

If we now combine online/offline announcements with full metadata-driven discovery we can build sophisticated service-oriented peer solutions.
This is very powerful stuff!

That's it for now for a first introduction to discovery announcements in WCF4.
Stay tuned for more.


posted Friday, May 08, 2009 12:08 PM with 2 Comments

[What's new in WCF4] Standard endpoints - or: "Look ma: streamlined infrastructure and system endpoints!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

As indicated in my post about discovery features there is a new feature in WCF4 called standard endpoints. The purpose of standard endpoints in WCF config is to allow for reusable pre-configured endpoints.
We all know that endpoints in WCF have many moving parts (address, binding, contract, behaviors). In some cases some of these parts are constrained. This is most common with infrastructure or system endpoints where the contract is fixed and provided externally to the service. Examples include MEX, discovery, WF instance control endpoints, etc.

To specify a standard endpoint we configure a normal endpoint and then specify its "kind" attribute:

<system.serviceModel>
    <services>
        <service name="HelloService">
            <endpoint kind="udpDiscoveryEndpoint" />
        </service>
    </services>
    <behaviors>
        <behavior>
            <serviceDiscovery />
        </behavior>
    </behaviors>
</system.serviceModel>

These are the pre-defined standard endpoints (screenshot from Visual Studio's XML Schema explorer):

WCF4 standard endpoints

We can also optionally specify a reusable endpointConfiguration for the endpoint using the new standardEndpoints section in config. This is similar to how one would specify a bindingConfiguration for a binding:

<system.serviceModel>
    <services>
        <service name="HelloService">
            <endpoint
                kind="udpDiscoveryEndpoint"
                endpointConfiguration="udpDiscoveryEndpointSettings"/>
        </service>
    </services>
    <standardEndpoints>
          <udpDiscoveryEndpoint>
              <standardEndpoint
                name="udpDiscoveryEndpointSettings"
                multicastAddress="soap.udp://239.255.255.252:3704"
                maxResponseDelay="00:00:02">
                <transportSettings
                    duplicateMessageHistoryLength="2048"
                    maxPendingMessageCount="5"
                    maxReceivedMessageSize="8192"
                    maxBufferPoolSize="262144"/>
            </standardEndpoint>
        </udpDiscoveryEndpoint>
    </standardEndpoints>
    <behaviors>
        <behavior>
            <serviceDiscovery />
        </behavior>
    </behaviors>
</system.serviceModel>

Not a very big but surely a convenient addition to WCF's feature set.
 
That's it for now for a first look into standard endpoints in WCF4.
Stay tuned for more.


posted Friday, May 08, 2009 11:31 AM with 3 Comments

[What's new in WCF4] Dynamic service and endpoint discovery - or: "Look ma: I just need the contract to talk to my service!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

"WCF is so easy, easy as ABC!" I am sure we all can still hear this marketing sentence echoing down the halls of building 42 on Redmond campus.

For exposing WCF services we need endpoints and endpoints need A, B, and C - yeah, you know that.
For consuming WCF services we need the endpoint information from the service, the A(ddress), the B(inding), and the (C)ontract - yeah you know that.

But wait...
What if the endpoints change frequently? What if the actual binding information is changed from time to time? We always need to make sure that all the consumers have the same exact updated endpoint configuration. Tedious, error-prone, often unnecessary.

Hm, what if I have a closed environment where I could use something like dynamic discovery of available endpoints? Something like a UDP-based multicast message exchange which receives the endpoint information from an available service. Based on the discovery information (which is the endpoint address and some more information not that necessary for now) sent back by this service I as a consumer can then go ahead and talk to this service.
It turns out there is something called WS-Discovery and WCF in .NET Framework 4 supports this standard.

The service discovery feature enables client applications to dynamically discover service addresses at runtime in an interoperable way using WS-Discovery. The WS-Discovery specification outlines the message exchange patterns required for performing light-weight discovery of services, both by multicast (ad hoc) and unicast (utilizing a dedicated network resource, often referred to as a proxy).
I will be talking about the ad-hoc approach in this post.

How does it work?
The following is the config file for a sample Hello service. Nothing needs to be done or changed in code, so you can use your very own common WCF services from yesterday.

<configuration>
    <system.serviceModel>
      <services>
        <service name="HelloService"
                 behaviorConfiguration="serviceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:7777/Services/Hello"/>
            </baseAddresses>
          </host>
          <endpoint address=""
                    binding="basicHttpBinding"
                    contract="IHelloService" />
          <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
        </service>
      </services>
      <behaviors>
        <serviceBehaviors>
          <behavior name="serviceBehavior">
            <serviceDiscovery />
          </behavior>
        </serviceBehaviors>        
      </behaviors>
    </system.serviceModel>
</configuration>

With this basic configuration for a service host we enable service and endpoint discovery for our service. Here we use a new feature of WCF4 called standard endpoints (by specifiying the "kind" attribute on the udpDiscovery endpoint). Some more information on standard endpoints in a later post.

If now a consumer wants to talk to a service which supports endpoints for IHelloService she can use the client-side discovery API like this:

DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");
FindCriteria findCriteria = new FindCriteria(typeof(IHelloService));
FindResponse findResponse = discoveryClient.Find(findCriteria);

if (findResponse.Endpoints.Count > 0)
{
    EndpointAddress address = findResponse.Endpoints[0].Address;
    ChannelFactory<IHelloServiceChannel> factory = new ChannelFactory<IHelloServiceChannel>(
        new BasicHttpBinding(), address);
    IHelloServiceChannel client = new factory.CreateChannel();
    
    client.SayIt("Hello from WCF4!");
    
    client.Close();
    factory.Close();
}

Pretty easy, eh? We need the contract, the binding and get the actual endpoint address as a result from the discovery process. Cool!

But wait...
I still need to know about the binding. I still need to kn ow that here we need a basicHttpBinding. But what if the binding changes? I mean not something dramatic like from a session-less to a session-bound binding (which most probably would also mean changing parts of at least the consuming code) - more something like moving from basicHttpBinding to a custom binding with binary-over-http.

There is rescue. And this rescue has been in the WCF stack from the very first version on and is nothing new in WCF4. It is called MetadataResolver.
We can pass a MEX (MetadataExchange, based on WS-MetadataExchange) address to the static Resolve method. The MetadataResolver will then look for the service's MEX endpoint and retrieve metadata for a given contract (in our case this would be IHelloService).
First we need to add a MEX endpoint to our service:

<endpoint address="mex"
  binding="mexHttpBinding"
  contract="IMetadataExchange" />

Then the consumer can act like this:

ServiceEndpointCollection endpoints = MetadataResolver.Resolve(typeof(IHelloService), mexAddress);

We then have a collection of endpoints matching the contract criteria in our hands.
Now let's take one step further and combine the two ideas:
  • Expose the MEX endpoint of a service with discovery.
  • Let the consumer discover the MEX endpoint via DiscoveryClient (and just this one).
  • Let the consumer obtain endpoint information via the MEX endpoint by using the MetadataResolver.
  • Let the consumer call the service, with A,B, and C - but originally (read: at compile time) the consuming code only needs to know about the contract, the functional interface.
For convenience I wrapped this code into a custom ChannelFactory<TChannel> implementation which can be used in the described scenario.

public class SimpleDiscoveryChannelFactory<TChannel> : ChannelFactory<TChannel>
{
    private bool initialized;

    protected override void ApplyConfiguration(string configurationName)        
    {
        if (!initialized)
        {
            base.ApplyConfiguration(configurationName);

            var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
            var fc = FindCriteria.CreateMexEndpointCriteria();
            fc.MaxResults = 1;
            var fr = dc.Find(fc);

            if (fr.Endpoints.Count > 0)
            {
                var eps = MetadataResolver.Resolve(typeof(TChannel), fr.Endpoints[0].Address);

                if (eps.Count > 0)
                {
                    initialized = true;
                    this.InitializeEndpoint(eps[0]);
                }
                else throw new MetadataException("Could not find appropriate endpoint for contract.");
            }
            else throw new DiscoveryException("Could not find appropriate MEX endpoint.");
        }
    }
}

Note: it is not really recommended to do network calls before Open() is called, so this is just for illustration purposes here.

I use ad-hoc discovery here through UDP and tell the client API to stop discovering when one matching MEX service endpoint was found based on the FindCriteria.
Then the consumer just has some few lines of actual code to call a service based on the contract at hand:

var cf = new SimpleDiscoveryChannelFactory<IHelloServiceChannel>();
var client = cf.CreateChannel();

Console.WriteLine(client.SayIt("Hello from WCF4!");

client.Close();
cf.Close();

Yes, it works :)
There you are: "Look ma: I just need the contract to talk to my service(s)!" We get the current binding and endpoint address dynamically.

Note:
We can only use on the consuming side what is actually exposed via metadata. As you all know the throttles and quotas on the bindings are not exposed via metadata.

That's it for now for a first introduction to dynamic discovery in WCF4.
Stay tuned for more.


posted Friday, May 08, 2009 11:22 AM with 5 Comments

Manually deploying .NET Services Service Bus-enabled applications

If your application is using the Service Bus features from the .NET Services offerings in the Azure Services platform then you are most likely using config settings for certain relay bindings and the like.
When you want to deploy your application to other machines - especially to web sites hosted with an ISP - you need to make sure that all the config entries are valid and thus need to make sure that all binding and binding elements and behavior extensions as well as policy and WSDL importers are registered. This is usually done by running either the .NET Services SDK installer or the .NET Services Redist installer. Both will add the necessary config section entries to your machine.config file.

But when hosting your web app you most probably just have access to the ISP's space via an FTP connection. No problem: just add the necessary registrations in your app.config or web.config. This is kind of a template for the current .NET Services build which you can add to your config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>    
    <extensions>
      <behaviorExtensions>
        <add name="connectionStatusBehavior" type="Microsoft.ServiceBus.Configuration.ConnectionStatusElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </behaviorExtensions>
      <bindingElementExtensions>
        <add name="tcpRelayTransport" type="Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="httpRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpRelayTransportElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="httpsRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpsRelayTransportElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="onewayRelayTransport" type="Microsoft.ServiceBus.Configuration.OnewayRelayTransportElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </bindingElementExtensions>
      <bindingExtensions>
        <add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="basicHttpRelayContextBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayContextBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="webHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WebHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="wsHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WSHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="wsHttpRelayContextBinding" type="Microsoft.ServiceBus.Configuration.WSHttpRelayContextBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="ws2007HttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WS2007HttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="ws2007FederationHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WS2007FederationHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netTcpRelayContextBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayContextBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netOnewayRelayBinding" type="Microsoft.ServiceBus.Configuration.NetOnewayRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netEventRelayBinding" type="Microsoft.ServiceBus.Configuration.NetEventRelayBindingCollectionElement, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </bindingExtensions>
    </extensions>
   
    <client>
      <metadata>
        <policyImporters>
          <extension type="Microsoft.ServiceBus.Description.TcpRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <extension type="Microsoft.ServiceBus.Description.HttpRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <extension type="Microsoft.ServiceBus.Description.OnewayRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </policyImporters>
        <wsdlImporters>
          <extension type="Microsoft.ServiceBus.Description.StandardRelayBindingImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <extension type="Microsoft.ServiceBus.Description.TcpRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <extension type="Microsoft.ServiceBus.Description.HttpRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <extension type="Microsoft.ServiceBus.Description.OnewayRelayTransportBindingElementImporter, Microsoft.ServiceBus, Version=0.15.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </wsdlImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>


The rest is easy then. Just add your service and client configuration as you need. Obviously the .NET Services DLLs (which can be found in the SDK) need to be in the web project’s bin folder and the project needs to reference them.
Done.


posted Friday, May 08, 2009 9:04 AM with 1 Comments

[What's new in WCF4] .svc-less Activation - or: "Look ma: my [REST] URLs look good!"

[Note: all the information was gathered based on a close-to-Beta 1 build of .NET Framework 4.0 and Visual Studio 2010. Details may vary and change]

Another interesting and most wanted feature in WCF4 is .svc-less activation when WAS-hosting WCF services. This essentially means that I do no longer need to have a physical .svc file for each of my services but just can specify the activation path in config.
So, with this simple WAS-hosted WCF project (without any .svc file)...

WCF4 .svc-less activation
...we can have this web.config section for WCF:

<system.serviceModel>
    <serviceHostingEnvironment>      
      <serviceActivations>
        <add relativeAddress="/Hello.svc" service="HelloService"/>
        <add relativeAddress="/Hello" service="HelloService"/>
      </serviceActivations>

    </serviceHostingEnvironment>
    <services>
      <service name="HelloService">
        <endpoint binding="webHttpBinding" contract="IHelloService" />        
      </service>
    </services>
[...]

This means that we now have one endpoint which can be activated (or 'addressed' in the first place) via two URIs, namely
  • http://myserver/myapp/Hello.svc and
  • http://myserver/myapp/Hello
Of course you can just omit the entry for Hello.svc and then you can activate your WAS-hosted service via
  • http://myserver/myapp/Hello.

Pure joy for the REST-afarians :)
(and yes: this also works with any other binding)

That's it for now for a first introduction to .svc-less activation in WCF4.
Stay tuned for more.


posted Friday, May 08, 2009 8:37 AM with 0 Comments


Powered by Community Server, by Telligent Systems