• mwinkle.blog

    Advanced Workflow Services Talk (Demo 3 of 4)

    • 2 Comments

    So, we've seen in part 1 how to manage context, we saw in part 2 how we can take that basic knowledge to do duplex messaging.  Once we start doing duplex work, there are some interesting patterns, and the first one is one that we like to call "long running work".  Why are we interested in this?  Well, as you probably know, the execution of a workflow is single threaded (this is a feature, not a bug).  We also don't have a mechanism to force the workflow to be "pinned" in memory.  What this means is that things like the asynchronous programming model  (APM), can't be used, since there isn't a guarantee that there will be something to call back when we are done.  What this means is that the send activity can not take advantage of the APM to be more thread friendly.

    We may want to do things in parallel, like this

    image

    If each of these branches takes 3 seconds, the whole of this workflow will complete in about 9 seconds.  The general expectation is that in parallel, this would happen at the length of the longest branch + some minor delta for overhead.  The trouble is, APM programming is tricky, especially relative to the layout above.

    In order to model APM style service calls, but allowing for the service operations to be extremely long running, where extremely is defined as "long enough to where I would want to be able to persist."  The approach then is to model this as disjoint send and receive activities.

    image

    One intermediate step is to simply use one way messaging, but the problem there is that in a lot of cases, I'm looking for some information being sent back to me. 

    I'll hold off on the code for the above, the fact we are listening in parallel for the same operation requires us to be a little more clever.

    Let's look first at our contract, and then our service implementation:

       1:  namespace Long_Running_Work
       2:  {
       3:      [ServiceContract]
       4:      public interface ILongRunningWork
       5:      {
       6:          [OperationContract]
       7:          string TakeAWhile(int i);
       8:   
       9:          [OperationContract(IsOneWay = true)]
      10:          void OneWayTakeAWhile( int i);
      11:          
      12:          [OperationContract(IsOneWay = true)]
      13:          void TakeAWhileAndTellMeLater(IDictionary<string,string> contextToken, int i);
      14:      }
      15:   
      16:   
      17:      [ServiceContract]
      18:      public interface IReverseContract
      19:      {
      20:          [OperationContract(IsOneWay = true)]
      21:          void TakeAWhileAndTellMeLaterDone(string s);
      22:      }
      23:     
      24:  }

    And now for the implementation of these;

       1:  namespace Long_Running_Work
       2:  {
       3:     public class Service1 : ILongRunningWork
       4:      {
       5:   
       6:          public Service1()
       7:          {
       8:             
       9:          }
      10:   
      11:          #region ILongRunningWork Members
      12:   
      13:          public string TakeAWhile(int i)
      14:          {
      15:              Console.WriteLine("Starting TakeAWhile");
      16:              System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3));
      17:              return i.ToString();
      18:          }
      19:   
      20:   
      21:   
      22:          public void OneWayTakeAWhile( int i)
      23:          {
      24:              Console.WriteLine("Starting One Way TakeAWhile");
      25:              System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3));
      26:              Console.WriteLine("Ending One Way TakeAWhile");
      27:   
      28:   
      29:          }
      30:   
      31:   
      32:          public void TakeAWhileAndTellMeLater(IDictionary<string, string> context, int i)
      33:          {
      34:              Console.WriteLine("Received the context Token");
      35:              System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3));
      36:              Console.WriteLine("Need to Message Back Now {0}", i.ToString());
      37:              // could investigate a more useful pooling of these if we 
      38:              // really wanted to worry about perf
      39:              IReverseContractClient ircc = new IReverseContractClient(
      40:                  new NetTcpContextBinding(),
      41:                  new EndpointAddress("net.tcp://localhost:10003/ReverseContract")
      42:                  );
      43:              IContextManager icm = ircc.InnerChannel.GetProperty<IContextManager>();
      44:              icm.SetContext(context);
      45:              ircc.TakeAWhileAndTellMeLaterDone(i.ToString());
      46:          }
      47:   
      48:   
      49:   
      50:          #endregion
      51:      } 
      52:   
      53:     public class IReverseContractClient : ClientBase<IReverseContract>, IReverseContract
      54:     {
      55:          public IReverseContractClient() : base(){}
      56:          public IReverseContractClient(System.ServiceModel.Channels.Binding binding, EndpointAddress address) : base(binding, address) { }
      57:   
      58:  #region IReverseContract Members
      59:   
      60:   
      61:   
      62:         public void TakeAWhileAndTellMeLaterDone(string s)
      63:         {
      64:             base.Channel.TakeAWhileAndTellMeLaterDone(s);
      65:         }
      66:   
      67:         #endregion
      68:     }
      69:   
      70:  }

    Basically, we sit around and wait.  You'll also note in the TakeAWhileAndTellMeLater, we take in a context token (similar to our previous approach), and we will use that to new up a client at the end and call back in after setting the context.  Look at lines 39-44 above.  The nice thing about this is that my above workflow client can actually go idle, persist, and react to a message being delivered later on.

    One thing to note is that one should not place a delay between any of the Send and Receives.  This could cause the workflow to go idle, which may allow you to miss messages.  This is generally considered, a bad thing.  The reason this occurs is that the WorkflowOperationInvoker will use EnqueueOnIdle which means that when teh workflow goes idle, the message will be enqueued.  If the queue hasn't been created by the Receive activity, the message will not get delivered.

    For the final workflow above (the TakeAWhileAndTellMeLater workflow), I will need to spin this up in a WorkflowServiceHost (a la the Duplex Sample in part 2).

    using (WorkflowServiceHost wsh = new WorkflowServiceHost(typeof(CallLongRunningComponents.WorkflowWithmessaging)))
    {
        wsh.AddServiceEndpoint(
                typeof(Long_Running_Work.IReverseContract),
                new NetTcpContextBinding(),
               "net.tcp://localhost:10003/ReverseContract"
                );
        // don't forget to open up the wsh
        WorkflowRuntime wr = wsh.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime;
    
        wsh.Open();
    
    
        WorkflowInstance wi = wr.CreateWorkflow(
            typeof(CallLongRunningComponents.WorkflowWithmessaging));
        wr.WorkflowCompleted += ((o, e) => waitHandle.Set());
        wr.WorkflowIdled += ((o, e) => Console.WriteLine("We're idled"));
            
    
        wi.Start();
    
    
    
    
        waitHandle.WaitOne();
    
    }

    Why do I think this is cool?

    Two reasons:

    • If I assume that I can modify the called service to callback to me (or put such a wrapper at a runtime service level), this is easier to model than the APM (that code included at the end of this post)
    • This gives me a natural way to start exposing more advanced control over a service call.  Rather than just a send and receive, I can use a send and a listen, and in the listen have a receive, a cancel message receive, and a delay in order to expose more fine grained control points for my workflow, and model the way the process should work very explicitly and declaratively.

    image

     

    Code for APM approach:

    call some services and wait:

       1:  Console.WriteLine("Press <enter> to execute APM approach");
       2:  Console.ReadLine();
       3:  waitHandle = new AutoResetEvent(false);
       4:  Stopwatch sw = new Stopwatch();
       5:  sw.Start();
       6:  lrwc = new WorkflowHost.ServiceReference1.LongRunningWorkClient();
       7:  lrwc.BeginTakeAWhile(1, HandleClientReturn, "one");
       8:  lrwc.BeginTakeAWhile(2, HandleClientReturn, "two");
       9:  lrwc.BeginTakeAWhile(3, HandleClientReturn, "three");
      10:  lrwc.BeginTakeAWhile(4, HandleClientReturn, "four");
      11:  while (!areDone)
      12:  {
      13:      System.Threading.Thread.Sleep(25);
      14:  }
      15:  Console.WriteLine("APM approach compelted in {0} milliseconds", sw.ElapsedMilliseconds);
      16:  Console.WriteLine("All Done, press <enter> to exit");
      17:  Console.ReadLine();

    Ignore the busy wait on line 11, I should use a waithandle here but was having trouble getting it to work correctly (this is hard code).

    The callback and respective state:

       1:  static ServiceReference1.LongRunningWorkClient lrwc;
       2:  static Int32 countOfFinished = 0;
       3:   
       4:  static void HandleClientReturn(IAsyncResult result)
       5:  {
       6:      string s = (string)result.AsyncState;
       7:      string resultString = lrwc.EndTakeAWhile(result);
       8:      Console.WriteLine("received {0}", resultString);
       9:      if (Interlocked.Increment(ref countOfFinished) == 4)
      10:      {
      11:          areDone = true;
      12:      }
      13:  }

    I have had some people say that line 9 should use Interlocked.CompareExchange in order to do this correctly, but the point is that this is tricky code, that modeling in WF is pretty nice.  [ignoring for the moment the work required to realize the assumption that we can make the service message back.] 

  • mwinkle.blog

    Q & A on Advanced Workflow Services talk

    • 1 Comments

    Martin posted an interesting question here on my last post:

    <quote>

    The first thing that we need to do in order to enable this duplex messaging to occur is that the "client" workflow has to explicitly provide its context token to the service so that the service can address the appropriate instance of the client workflow.

    Note, in the real world, you'll probably need to supply more than just the context token, you will need some address and binding information.

    </quote>

    Shouldn't we have this built into a custom binding? (or an extra binding element) So with every call from the client the (WF)context information is included. And the developer is not required to follow a (artificial) state machine.

    Note, at the time, when the service calls back, the endpoint (and the binding) of the client may have changed... So we may need dynamic name-endpoint resolution (sounds like DNS?)

    Martin

    The question here is generally also asked as "wait, why do I need to explicitly provide a context token and change the contract to have this context thing?"  This is a common question, as changing the contract to reflect implementation details is generally a no-no.  There's one part I left out as well, so let me add that here:

    In the real world, one may also wish to not change the contract (or may not have the ability to).  In that case, we still need to explicitly provide the context token and endpoint information in order to allow me to call back.  There are a few ways to do this, of varying complexity and implication:

    • Put this into the message header and have the other side extract this information and use it the same way.
      • There are two downsides to this approach:
        • It still requires management of the other side to agree upon where the context token is being place.
        • The WF Messaging activities don't give me an easy way to reach in and get to header information, but one could certainly look at some infrastructure level extensions to manage this.  This idea of making duplex easier is one thing that Ed will be talking about in his Oslo workflow services talk at PDC
    • Create a custom binding element.
      • There is one downside with this approach:
        • You're creating a custom channel, custom binding element, and all the other stuff that goes along with creating a channel.  This is very hard work.  If the answer is "you've got to write a channel to do it," we need to do a better job making it easier (see earlier point about Ed's talk).
      • If that's the behavior that you want, you are certainly welcome do go down that path, it would be great to hear about your experiences doing it!
      • The upside to this approach:
        • You're creating a layer of near infinite extensibility, allowing you to handle simple things to the complex dynamic endpoint resolution behavior, once you invest the cost once to create the channel that would sit there and do that.

    This is also the same approach one could take with using an implicit, or content based correlation scheme.  In that case, you create an intermediary that is responsible for translating message contents into the "addressing" information for the instance.  That intermediary can be a service, it could be a channel, and once you put that intermediary in place, you are free to do as sophisticated or as simple work as possible.

  • mwinkle.blog

    Advanced Workflow Services Talk (Demo 2 of 4)

    • 2 Comments

    A continuation of my series of demos from my advanced workflow services talk.  Here we focus on duplex message exchange patterns.

    Duplex messaging is something that we model at the application level (as opposed to the infrastructure level) because we want to model that message exchange at the level of the application.  Here's some scenarios where I could use duplex messaging:

    • [concrete] I submit an order, and you tell me when it ships
    • [abstract] I ask you do to do some long running work, let me know when it is done
    • [abstract] I ask you to start doing something, you update me on the status

    One may ask the question, "But, what about the wsHttpDualBinding, or WCF duplex bindings."  That's a valid question, but it's important to point out that those bindings are really used to describe the behavior of a given proxy instance (and associated service artifacts).  When my proxy dies, or the underlying connection goes away, I lose the ability for the service to call back to me.  Additionally, this binds me to listen in the same way that I sent out the initial message. 

    By modeling this at the application layer, we do lose some of the "automagicity" of the WCF duplex behavior, but I get more flexibility, and I get the ability to sustain potentially repeated recycling of the services and clients.  Also, you could imagine a service that I call that turns around and calls a third party service.  That third party service could call back directly to the client that made the initial call.  Note, once we start doing duplex communication (and we'll encounter this in part 4, conversations), is that the definition of "client" and "service" become a bit muddier.

     

    So, to the code:

     

    Ingredients:

    • My service workflow, I listen for three different messages (start, add item, complete ), and then I will send the message back to the client:
    • image
      • You'll note that there is a loop so that we can keep adding items until we eventually get the complete order message and we then exit the loop.
    • A "client" workflow, which will call this service:
    • image
      • You'll note, some of the magic happens here.  After I start, add and complete the order, you'll see that instead of sending messages, I'll now flip around and wait on the receive in order to receive the shipping cost from the service.

     

    Details

    The first thing that we need to do in order to enable this duplex messaging to occur is that the "client" workflow has to explicitly provide its context token to the service so that the service can address the appropriate instance of the client workflow.

    Note, in the real world, you'll probably need to supply more than just the context token, you will need some address and binding information.

    Let's look at the contract of the service:

    [ServiceContract(Namespace ="http://microsoft.com/dpe/samples/duplex")]
    public interface  IOrderProcessing
    {
        [OperationContract()]
        void SubmitOrder(string customerName, IDictionary<string, string> context);
    
        [OperationContract(IsOneWay = true )]
        void AddItem(OrderItem orderItem);
    
        [OperationContract(IsOneWay = true )]
        void CompleteOrder();
    }

    You'll note that on the SubmitOrder method, I pass in a context token.  This is my callback correlation identifier, this is how I will figure out what instance on the client side I want to talk to.  Now, I need to do some work to get the context token in order to send, so let's look at how we do this:

    On the client side, on the first Send activity, let's hook the BeforeSend event.

    image

     

    Let's look at the implementation of GrabToken:

       1:  private void GrabToken(object sender, SendActivityEventArgs e)
       2:  {
       3:      ContextToSend = receiveActivity1.Context;
       4:      Console.WriteLine("Received token to send along");
       5:  }
       6:   
       7:  public static DependencyProperty ContextToSendProperty = DependencyProperty.Register("ContextToSend", typeof(System.Collections.Generic.IDictionary<string, System.String>), typeof(OrderSubmitter.Workflow1));
       8:   
       9:  [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
      10:  [BrowsableAttribute(true)]
      11:  [CategoryAttribute("Parameters")]
      12:  public System.Collections.Generic.IDictionary<string, String> ContextToSend
      13:  {
      14:      get
      15:      {
      16:          return ((System.Collections.Generic.IDictionary<string, string>)(base.GetValue(OrderSubmitter.Workflow1.ContextToSendProperty)));
      17:      }
      18:      set
      19:      {
      20:          base.SetValue(OrderSubmitter.Workflow1.ContextToSendProperty, value);
      21:      }
      22:  }

    First, note that on lines 7-22 we declare a dependency property call ContextToSend.  Think of this simply as a bindable storage space.  On line 3, we go and assign to that the value of receiveActivity1.Context.  "But Matt, couldn't I just build a context token off the workflow ID?"  You could, but you're only going to be correct in the "simple scenario."   You can see we then take that ContextToSend, and pass that into the context parameter for the service operation. Always walk up and ask a Receive activity for its context token, don't try to build one on your own.

    Now, on the service side, we need to extract that, and we need to apply the value to the send activity in the service workflow that needs to call back.  We basically can do the reverse:

    private void codeActivity1_ExecuteCode(object sender, EventArgs e)
    {
        //set callback context
        sendActivity1.Context = callbackContext;
    }

    This is inside a code activity in the first receive activity.  callbackContext is a dependency property that is bound to the inbound context on the Receive activity. 

     

    The final trick is that both workflows have to be hosted inside a WorkflowServiceHost.  This makes sense for the "service" workflow, since it will be message activated.  On the client side, we have to do a little bit of work in order to get to the workflow runtime to spin up a workflow instance.  In the early betas, we had an easy way to get to the runtime, WorkflowServiceHost.WorkflowRuntime.  In order to conform more with the extensibility of WCF, this has been moved to the extensions of the service host.  We get there by:

       1:  static void Main(string[] args)
       2:  {
       3:      using (WorkflowServiceHost wsh = new WorkflowServiceHost(typeof(Workflow1)))
       4:      {
       5:          Console.WriteLine("Press <ENTER> to start the workflow");
       6:          Console.ReadLine();
       7:          wsh.Open();
       8:          WorkflowRuntime wr = wsh.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime;
       9:          WorkflowInstance wi = wr.CreateWorkflow(typeof(Workflow1));
      10:          AutoResetEvent waitHandle = new AutoResetEvent(false);
      11:          wr.WorkflowCompleted += delegate { waitHandle.Set(); };
      12:          wr.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine("error {0}", e); waitHandle.Set(); };
      13:          wi.Start();
      14:          waitHandle.WaitOne();
      15:          Console.WriteLine("Workflow Completed");
      16:          Console.ReadLine();
      17:      }
      18:  }

    On line 3, you'll see we new up a WorkflowServiceHost based on the service type (it will do this to find and open the respective endpoints).  On line 8, we reach in and grab the WorkflowRuntimeBehavior and get the WorkflowRuntime, and we use that to create an instance of the workflow. 

    So, here's what we have done:

    • Figure out how to grab the context token from a Receive activity
    • Modify the contract to explicitly send the "callback info" to the service
    • On the service side, figure out how to grab that and apply it to a Send activity
    • Finally, on the client side, how to manually kick off workflows, rather than waiting for them to be message activated (the usual path we have is the infrastructure creating the workflow instance). 
  • mwinkle.blog

    Advanced Workflow Services Talk (Demo 1 of 4)

    • 5 Comments

    So, last week I wrapped up a conversation at TechReady, our internal conference, where I was talking about the integration between WF and WCF in .NET 3.5.  This talk was somewhat bittersweet, it's the last conference where I'm scheduled to talk about WF 3.0/3.5, I'll start talking about WF 4.0 at PDC this fall. 

    There are a series of 4 demos that we'll talk about in this series:

    1. Basic Context Management
    2. Simple Duplex
    3. Long Running Work Pattern
    4. Conversations Pattern

    I've gotten a lot of requests to post the code samples, so I want to do that here:

    Sample 1, Basic Management of Context

    The goal of this sample is to show the way that the context channel works, and how to interact with it from imperative code.

    Ingredients:

    • One basic workflow service that simply has two Receive activities bound to the same operation inside of a sequence.
    • image
    • Inside each Receive, I have placed a Code Activity that simply outputs a little bit of info (the vars declared on lines 1 and 2 are used by the Receive activities:

     

         1:  public String returnValue = default(System.String);
         2:  public String inputMessage = default(System.String);
         3:   
         4:  private void codeActivity1_ExecuteCode(object sender, EventArgs e)
         5:  {
         6:      returnValue = string.Format("first activity {0}", inputMessage);
         7:      Output(inputMessage + " Activity 1");
         8:  }
         9:   
        10:  private void Output(string message)
        11:  {
        12:      Console.WriteLine("Workflow {0} : Message {1}", this.WorkflowInstanceId, message);
        13:  }
        14:   
        15:  private void codeActivity2_ExecuteCode(object sender, EventArgs e)
        16:  {
        17:      returnValue = string.Format("second activity {0}", inputMessage);
        18:      Output(inputMessage + " Activity 2");
        19:  }

     

    Instructions:

    • Create a client type that will call the service for us
      class IWorkflowClient : ClientBase<Intro1.IWorkflow1>, Intro1.IWorkflow1
      {
          public IWorkflowClient() : base() { }
          public IWorkflowClient(Binding binding, EndpointAddress address) : base(binding, address) { }
          public string Hello(string message)
          {
              return base.Channel.Hello(message);
          }
      }
    • Create a utility function CheckAndPrintContext()
      private static void CheckAndPrintContext(IContextManager icm)
      {
          if (null != icm) Console.WriteLine("Context contains {0} elements", icm.GetContext().Count);
          if (null != icm)
          {
              if (icm.GetContext().Count > 0)
              {
                  foreach (string xmlName in icm.GetContext().Keys)
                  {
                      Console.WriteLine("key : {0}", xmlName);
                      Console.WriteLine("value : {0}", icm.GetContext()[xmlName]);
                  }
              }
          }
      }
      • The thing to note here is that we need to traverse the dictionary, since there could be more than one key in here, although there won't be in this sample.
    • Now, let's run the three different bits of code, we want to first show the happy path, show how to break it, and then show how to explicitly manage the context token
    • Scenario 1: The Happy Path

         1:  private static void DemoOne()
         2:  {
         3:      Console.WriteLine("Press Enter to Send a Message and reuse proxy");
         4:      // Console.ReadLine();
         5:      Debugger.Break();
         6:      IWorkflowClient iwc = new IWorkflowClient(new NetTcpContextBinding(),
         7:          new EndpointAddress("net.tcp://localhost:10001/Intro1"));
         8:      IContextManager icm = iwc.InnerChannel.GetProperty<IContextManager>();
         9:      if (null != icm) Console.WriteLine("Context contains {0} elements", icm.GetContext().Count);
        10:      string s = iwc.Hello("message1");
        11:      Console.WriteLine("the service returned the message '{0}'", s);
        12:      CheckAndPrintContext(icm);
        13:      s = iwc.Hello("message2");
        14:      icm = iwc.InnerChannel.GetProperty<IContextManager>();
        15:      CheckAndPrintContext(icm);
        16:      Console.WriteLine("the service returned the message '{0}'", s);
        17:      Console.WriteLine("Press Enter to Continue");
        18:  }
      • What's going on here?
        • Line 5, a more convenient way in demos to hit a breakpoint
        • Line 10: Call the service
        • Line 12: CheckAndPrint the Context Token.  In this case, this will print the Guid of the initiated workflow that is contained in the token
        • Line 13: Call the service a second time
          • Look at the service window, you'll see that this message has been routed to the same instance of the workflow.
          • You can also see in Line 16 that the second activities return message is included.
    • Scenario 2: The Path Grows Darker

         1:  // show this not working using a second client
         2:  private static void DemoTwo()
         3:  {
         4:      Console.WriteLine("Press Enter to Send a Message (it will break this time)");
         5:      //Console.ReadLine();
         6:      Debugger.Break();
         7:      IWorkflowClient iwc = new IWorkflowClient(new NetTcpContextBinding(),
         8:          new EndpointAddress("net.tcp://localhost:10001/Intro1"));
         9:      IContextManager icm = iwc.InnerChannel.GetProperty<IContextManager>();
        10:      if (null != icm) Console.WriteLine("Context contains {0} elements", icm.GetContext().Count);
        11:      string s = iwc.Hello("message1");
        12:      Console.WriteLine("the service returned the message '{0}'", s);
        13:      CheckAndPrintContext(icm);
        14:      iwc = new IWorkflowClient(new NetTcpContextBinding(),
        15:         new EndpointAddress("net.tcp://localhost:10001/Intro1"));
        16:      s = iwc.Hello("message2");
        17:      Console.WriteLine("the service returned the message '{0}'", s);
        18:      icm = iwc.InnerChannel.GetProperty<IContextManager>();
        19:      CheckAndPrintContext(icm);
        20:      Console.WriteLine("Press Enter to Continue");
        21:  }
      • What's going on here? (Same until line 14)
        • Line 14: Let's create a new proxy. 
        • Line 15: Call the service using the new proxy.  You'll note on the server side that a second workflow instance has been created.  This is where we break.
        • Line 19: On the client side, you'll see that the second GUID being returned
    • Scenario 3: Finding the Light

         1:  // show this working with a second client by caching the context
         2:  private static void DemoThree()
         3:  {
         4:      Console.WriteLine("Press Enter to Send a Message (we'll cache the context and apply it to the new proxy)");
         5:      // Console.ReadLine();
         6:      Debugger.Break();
         7:      IWorkflowClient iwc = new IWorkflowClient(new NetTcpContextBinding(),
         8:          new EndpointAddress("net.tcp://localhost:10001/Intro1"));
         9:      IContextManager icm = iwc.InnerChannel.GetProperty<IContextManager>();
        10:      if (null != icm) Console.WriteLine("Context contains {0} elements", icm.GetContext().Count);
        11:      string s = iwc.Hello("message1");
        12:      Console.WriteLine("the service returned the message '{0}'", s);
        13:      CheckAndPrintContext(icm);
        14:      IDictionary<string, string> context = icm.GetContext();
        15:      icm = null;
        16:      iwc = new IWorkflowClient(new NetTcpContextBinding(),
        17:         new EndpointAddress("net.tcp://localhost:10001/Intro1"));
        18:      icm = iwc.InnerChannel.GetProperty<IContextManager>();
        19:      icm.SetContext(context);
        20:      s = iwc.Hello("message2");
        21:      Console.WriteLine("the service returned the message '{0}'", s);
        22:      icm = iwc.InnerChannel.GetProperty<IContextManager>();
        23:      CheckAndPrintContext(icm);
        24:      Console.WriteLine("Press Enter to Exit");
        25:   
        26:  }
      • Line 14 is where the magic happens, here' we grab the context token from the IContextManager. 
      • Line 19 is where the magic completes, we apply this token to the new proxy.  Note, this proxy could be running on different machine somewhere, but one I get the context token, I can use it to communicate with the same workflow instance that the first call did.

    So, what have we shown:

    • Manipulating context in workflow and imperative code
      • How to extract the context token
      • How to explicitly set the context token
    • The caching behavior of the context channel (as seen in Scenario 1)
    • The behavior of the context channel to return the context token only on the activating message
  • mwinkle.blog

    Oslo PDC Sessions Posted

    • 1 Comments

    Late last night, the PDC team posted an additional "bunch" of sessions, including one I'm particularly interested in:

    Extending Windows Workflow Foundation v.Next with Custom Activities

    Presenter: Matt Winkler

    Windows Workflow Foundation (WF) coordinates and manages individual units of work, encapsulated into activities. The next version of WF comes with a library of activities, including Database and PowerShell. Learn how to extend this library by encapsulating your own APIs with custom activities. See how to compose those basic activities into higher level units using rules, flowchart, or state machine control flow styles. Learn how to extend beyond WF control styles by building your own. Learn how to customize and re-host the workflow authoring experience using the new WF designer framework.

    Tags:

    Advanced, WF

    They also posted a number of other interesting Oslo sessions that folks might be interested in, these cover a wide range of the things that our group is doing:

    • "Oslo:" The Language - Don Box and David Langworthy
      • "Oslo" provides a language for creating schemas, queries, views, and values. Learn the key features of the language, including its type system, instance construction, and query. Understand supporting runtime features such as dynamic construction and compilation, SQL generation, and deployment. Learn to author content for the "Oslo" repository and understand how to programmatically construct and process the content.

    • "Oslo:" Customizing and Extending the Visual Design Experience - Florian Voss
      • "Oslo" provides visual tools for writing data-driven applications and services. Learn how to provide a great experience over domain-specific schemas, and explore the basic user model, data-driven viewer construction, user-defined queries, and custom commands. See how the design experience itself is an "Oslo" application and is driven by content stored in the "Oslo" repository.

    • Hosting Workflows and Services in "Oslo" - Ford McKinstry
      • "Oslo" builds on Windows Workflow (WF) and Windows Communication Foundation (WCF) to provide a feature-rich middle-tier execution and deployment environment. Learn about the architecture of "Oslo" and the features that simplify deployment, management, and troubleshooting of workflows and services.

    • "Oslo" Repository and Schemas - Martin Gudgin, Chris Sells
      • "Oslo" uses schematized data stored in the "Oslo" repository to drive the development and execution of applications and services. Tour the schemas and see how user-defined content can be created and related to them. Learn how to utilize platform schemas, such as worflow, services, and hosting. Also, learn how to extend the repository and how to use repository-extended SQL database services to support critical lifecycle capabilities such as versioning, security, and deployment.

    It'll be a good time, can't wait to see ya there!

    • mwinkle.blog

      TechEd 2008

      • 1 Comments

      TechEd Developer kicks off next week in Orlando, the first time the US group has tried the European model of separate dev and IT pro weeks.  I've grown to like the model in Europe a little better, because I think both attendees and speakers benefit from the greater focus within their specialized areas.  The people who it hurts are obviously those who fall squarely into both camps, but at the US events, I have not run into many of those.

      The conference agenda is getting busy for folks who like to stay on top of Microsoft technologies (or who like to speak at these events), with MIX in the spring, PDC in the fall, and TechEd in the summer, and that's just the US centric Microsoft "general" conferences.  I'm intentionally excluding the Office Developer Conference, international conferences, and those that are not directly put on by Microsoft, such as VS Live.

      Why am I going next week?  In short, it's to give a session talking about advanced WF+WCF integration, but more importantly to escape the Redmond bubble and find out what's actually happening to real customers in the real world.  Those interactions become more and more valuable as we work to build tools to help those customers build applications.  A few of the sessions I'd be interested in as an attendee:

       

      SOA209 The Road to “Oslo”: The Microsoft Services and Modeling Platform

      Thursday, June 5 1:00 PM - 2:15 PM, S220 A 

      Speaker(s): David Chappell

      Microsoft’s “Oslo” project aims at creating a unified platform for model-based, service-oriented applications. This new approach will affect the next versions of several products and technologies, including the Microsoft .NET Framework, Microsoft Visual Studio, Microsoft BizTalk Server, Microsoft System Center, and more. Although many details of “Oslo” won’t be public until later in 2008, this session provides an overview of what Microsoft has revealed so far. Along with a description of the problems it addresses, the session includes a look at several new “Oslo” technologies, including a general-purpose modeling language, role-specific modeling tools, a shared model repository, and a distributed service bus.

      Why? This is the first time we'll be saying more about what's going on in Oslo.  David's a fantastic speaker and the approach he will take with this presentation will take a lot of what we've said so far and tie it together.

       

      SOA302 Framework and Microsoft BizTalk Best Practices with an Eye Toward "Oslo"

      Wednesday, June 4 4:30 PM - 5:45 PM, S210 B 

      Speaker(s): Jon Flanders

      Microsoft has announced "Oslo", the code-name for a wave of technology affecting the Microsoft .NET Framework, Microsoft BizTalk Server, and the idea of building service-oriented systems using Microsoft technologies. In this session we discuss what we know so far about these technologies, and how to think about what you are currently doing with Windows Communication Framework/Windows Workflow Foundation and BizTalk Server to best prepare for the future.

      Why? David's talk is more about the ideas, Jon's talk is more about the tech.  If you code WF, WCF, or BizTalk solutions today, this will be a great talk to understand how to make your apps ready to take advantage of the new features coming in Oslo

      SOA305 Getting Workflows Running and Talking in Your Applications

      Friday, June 6 1:00 PM - 2:15 PM, S320 E 

      Speaker(s): Brian Noyes

      Once you understand the basics of Windows Workflow Foundation (WF) and can put together a workflow using the built-in activities, you will need to know how to get that workflow running in a variety of hosting environments and communicate between the workflow and the host application or the outside world. This session gives you a solid foundation to get started with these techniques. Gain a better understanding of how workflows exist in a hosting process and how to control the hosting services. Learn about the various forms of communication that can exist between a running workflow and the hosting application as well as with outside Web and WCF Services. Also, learn about the persistence and tracking features of WF.

      Why? Brian's talk will focus on how to get workflows communicating, something that's neccessary in any WF app.  I'll follow on this talk with an advanced look at WC+WCF integration in .NET 3.5

      SOA403 Building Federated Solutions on the Internet Service Bus

      Thursday, June 5 10:15 AM - 11:30 AM, S220 C (DEV) 

      Speaker(s): Clemens Vasters

      Using the code-name "BizTalk Services," Microsoft is building a set of "cloud" technologies that are developed and operated by Microsoft as a logical extension to the .NET Framework and the Microsoft SOA technologies. They aim to enable corporate software developers and ISVs building solutions that require broad, cross-organizational identity management, the ability to safely and securely traverse NATs and Firewalls to enable bi-directional communication, Internet-scale publish/subscribe services, broad interoperability, and services orchestration. In short, these technologies are expanding the reach of the ESB pattern to the Internet—that’s why we call it "Internet Service Bus." In this session, Clemens takes you along on a "lots of code" tour through an exemplary solution built using these technologies.

      Why? Get on the bus, baby!  This team is doing some very cool stuff in the cloud, and the infrastructure that is being provided is something that enables you to focus on the cool stuff your app does, not the bizarre intricacies of network traversal or identity management implementation details.

      TLA304 The Nine Essential Power Tools for Every Developer: Extending Microsoft Visual Studio to Enhance the Microsoft Office Development Experience

      Wednesday, June 4 8:30 AM - 9:45 AM, S320 E 

      Speaker(s): John Durant

      Check out the first release of Visual Studio Power Tools, a set of free tools that enhance the design-time or runtime capabilities of Office development in Visual Studio 2008 Professional.This session includes demos of all the tools, such as the Office Interop API Extensions library which brings optional and named parameters to Microsoft Visual C#, the Ribbon IDs Tool Window, and the SharePoint Workflow Package Generator. Come check them out and find out how you can start using them today

      Why?  John is a great speaker, he once appeared at a talk I set up wearing Heelys and wheeled around the audience blasting through technical details.  At 8:30 am, this talk is a great way to start your Wednesday.

      TLA317 Busy .NET Developer's Guide to Microsoft F#

      Speaker(s): Luke Hoban, Ted Neward

      F#, Microsoft's new functional language for the Microsoft .NET platform, makes it easy—as in, half the total lines of code easy—to create business objects for .NET applications that can be used from any other .NET language, like Microsoft Visual C#, Visual Basic, or Visual C++/CLI. In this presentation, we look at how to do this in F#, the advantages of doing so, and how doing this simplifies your life as a .NET developer.

      Why? Luke gave this talk in Israel where it was well received.  The addition of functional programming into the VS family of languages is a huge win for developers.  This talk will help you think about programs from a functional perspective, and show you how to do it.

    • mwinkle.blog

      PDC, 2008

      • 1 Comments

      The site went live last night, check it out and I hope to see you there.

      A few of the sessions that caught my eye.

      Windows 7: Optimizing for Energy Efficiency and Battery Life

      A single application can reduce mobile battery life by up to 30%. Windows 7 provides advances for building energy-efficient applications. In this session we will discuss how to leverage new Windows infrastructure to reduce application power consumption and efficiently schedule background tasks and services.

      Windows 7: Touch Computing

      In Windows 7, innovative touch and gesture support will enable more direct and natural interaction in your applications. This session will highlight the new multi-touch gesture APIs and explain how you can leverage them in your applications.

      Windows Mobile: Location, Location, Location

      Mobile location based services are the next "big thing", and this session will review the tools and technologies Windows Mobile makes available to developers wanting to integrate location into their applications. Location acquisition, services integration, mapping and visualization, and best practices will be discussed.

      Live Platform: Mesh Services Architecture Deep Dive

      You've heard about Microsoft's new software+services platform Live Mesh, combining the world of the web and the world of digital devices. Come take a look under the hood and learn about the underlying service architecture behind this mass-scale cloud service and client platform. We'll look at services such as FeedSync-based synchronization, accounts and security services, P2P communications, pub-sub infrastructure, and the Mesh Operating Environment (MOE).

      Architecture of the Building Block Services

      Dive into the architecture that links many of the building block services and lets ISVs and businesses deliver compelling solutions. Learn how to compose these services to create applications in the cloud and connect them with on-premises systems. In this session we'll cover the next generation of messaging, data, identity, and directory services, and how they help developers.

       

      oh, and this one...

      Advanced Workflow Services

      This session covers significant enhancements in Windows Communication Foundation (WCF) and Workflow Foundation (WF) to deal with the ever increasing complexity of communication patterns. Learn how to use WCF to correlate messages to service instances using transport, context, and application payloads. We'll show you how to use the new WF messaging activities to model rich protocols and how to use WCF as a rich default host for your workflows and expand the reach of WF with features like distributed compensation. See how service definition in XAML completes the union of WF and WCF with a unified authoring experience that dramatically simplifies configuration and is fully integrated w/ IIS activation and deployment.

      We'll probably have a few other things to talk about with WF as well ;-)

    • mwinkle.blog

      Usability Testing the WF Designer vNext (or, Yelling at Customers)

      • 13 Comments

      One of the things that my team is working on is the next version of the workflow designer.  In order to help us get real feedback, we engaged with our usability teams to design and execute a usability study. 

      For details on what the test looks like (when we did them 3 years ago for the first version of the WF designer, see this great channel9 video).  The setup is still the same (one way glass mirror, cameras tracking the face, screen, posture of the subject), the only difference is the software, we're busy testing out some new concepts to make workflow development much more productive.  At this stage of the lifecycle, we're really experimenting with some different designer metaphors, and a usability test is a great way to get real feedback.

      One thing I've always tried to do since I came to Microsoft is being sucked into the Redmond bubble.  The symptoms of placement inside said bubble are a gradual removal from the reality that everyday developers face.  When I came to the company two years ago, I was chock full of great thoughts and ideas from the outside, and much less tolerant of the "well, that's just how it works" defense. 

      Slowly, though, as you start to get deep into thinking about a problem, and tightly focusing on that problem, those concerns start to fade away, as you look to optimize the experience you are providing.  Sitting in on the usability labs yesterday was a great reminder to me of how easily one can slip into the bubble.  Our test subject was working with a workflow in the designer and had a peculiar style of working with the property window in VS.  Now, when I use VS, I use the property grid in one way.  I have it docked, and I have the dock set to automatically hide.  I have known some developers who prefer the Apple / photoshop style where the property pane floats.  The customer's way of working with the property grid was that he had it floating, but he would close it after every interaction.  This required him to do one of two things in order to display the grid again, either go to the View menu, or (and what his style of work was) right clicking on an element and selecting properties.

      The prototype we were doing the usability testing with, however, does not have that feature wired up, in fact, it currently doesn't displaimagey the properties item in the context menu at all.  Not because we have an evil, nefarious plan to remove the properties item inconsistently throughout our designer, but rather because no one gave it any thought when we put the prototype together as we had other UI elements we wanted to focus on. 

      This became a serious problem for our customer, as the way he expected to work was completely interrupted.  At one point, we asked him to dock the property window so we could continue with the test.  This is the most fascinating part of the study to me, and that was watching him work to dock the property grid in the left panel.  I've become so used to the docking behavior in VS (see screenshot below), that it didn't even occur to me that this might present a problem for the user.  Instead, we watched for 3 minutes or so as he attempted to figure out how to move the window, and then try to process the feedback that the UX elements give.  About 60 seconds in or so, the property grid was about at a similar location to the screenshot, with just a centimeter or two's distance away from being in "the right place".  Watching his face, we saw him look slightly confused and then move it elsewhere.  Two more times he came back to that same spot, just far enough away to not get the feedback that might help him in the right direction.  It was at this point, the spontaneous yelling started among the observers in the room.  Something that has become so obvious to us, something we have internalized and accepted as "just the way the world," was becoming crystal clear to us how much difficulty this was causing.  The yelling was things like "Move up, move up" "no, wait, over, over" "oh, you almost, almost, no...." trying to will the customer through the soundproof wall what we wanted him to do.

      This situation repeated itself time and time again with different UI elements, and it was very, very educational to see the way different users manage their workspace and interact with a tool that I've become so familiar with that I forget to see the forest for the trees.  I also realized, that although I had worked with a lot of customers and other developers, very rarely had I paid attention to how they work, rather than simply their work. 

      Now, here's where I open up the real can of worms.  We're looking to make usability improvements in the WF designer.  Are there any that really bother you?  What can we do to make you a more productive WF developer? 

    • mwinkle.blog

      Proving a Point with LINQ (or, the Longest Type Names in the .NET Framework)

      • 1 Comments

      I will often take a few moments during a presentation to get a chuckle by bringing up the SharedConnectionWorkflowCommitWorkBatchService.  Due to the sheer length of the type name, it's sure to bring a smile or two in one of my otherwise snore-inducing presentation.

      The other day, while reviewing a deck for a colleague I brought up that he should mention this type, and that it usually gets a laugh from a developer audience.  He then asked, "Is that really the longest type name in the framework?"  My response, "Well, I'm not really sure, I bet you could do some LINQ magic in order to figure it out." 

      Well, sitting on the bus this morning with some traffic time to spare (and needing to work on my LINQ skills a bit), put together some code.  My goal was to go through all of the types, calculate their length and figure out which one was the longest named type.  You can replicate this, create a new console application, right click to add references, and select all the references you want to add into this comparison.  I added all of the system.* assemblies, PresentationFramework, PresentationCore and WindowBase.  You could do even more by selecting everything in the reference dialog.

      The thing that appeals to me about LINQ is really that i can just write a query, I don't have to worry about looping through a number of times.  I also like the fact I can develop by refining, that is, I can get a collection back, tweak the query to shape it, take that new collection and query against that.

      Let's first look at what I started with:

      var orderedTypeListing =
             (from assembly in AppDomain.CurrentDomain.GetAssemblies()
              select assembly.GetExportedTypes());

      This ends up returning an object of type IEnumerable<List<Type>>, which doesn't quite get me to what I want.

      I use the Aggregate extension method to operate on this and create an entire list of all the types contained (think of this as flattening the tree by one level, or only returning the leaf nodes in the tree).  With the Aggregate method, I need to provide the operation to do the accumulation.

      var orderedTypeListing =
         (from assembly in AppDomain.CurrentDomain.GetAssemblies()
           select assembly.GetExportedTypes()).Aggregate(
                 (x, y) =>
                 { return x.Union(y).ToArray(); }
              )

      The only weirdness here is that I have to use ToArray(); since Aggregate returns T[], rather than IEnumerable<T>.

      Now I add a little bit of code to do some ordering.  I like the ordering syntax since I just provide a way to get the value I want to sort by.  Remember to use OrderByDescending in order to get the right ordering.

      Our query near looks like this:

      var orderedTypeListing =
         (from assembly in AppDomain.CurrentDomain.GetAssemblies()
           select assembly.GetExportedTypes()).Aggregate(
                 (x, y) =>
                 { return x.Union(y).ToArray(); }
              ).OrderByDescending(
                  (x) =>
                  { return x.Name.Length; }
              );

      So this returns a list, ordered by the length of the name.

      I could just grab the first one off the list, and I'd be done, but I'd like to see the 100 longest names, just in case I'm wrong about our friend SharedConnectionWorkflowCommitWorkBatchService.   To do this, I'll say I want to take 100 off the top of the list and print those out. 

      int count = 1;
      orderedTypeListing.Take(100).ToList().ForEach
      (
          x => 
          Console.WriteLine("{0}: {1}, {3} ({2})", 
          count++, 
          x.Name.Length, 
          x.Assembly.FullName.Split(",".ToCharArray())[1], 
          x.Name)
          );

      This will pretty print the top 100 longest names (these are at the bottom of the post).

      Next, i thought, I'd really like to see a histogram of the sizes.  To do that, I need to group by data.  The Group() extension method, just like the order method, allows me to pass in the value by which I want to group (and that can be computed, say a hash).  It also returns an IGrouping that lets me see the key (in my case, the size of the key) and the IEnumerable itself.

      var groupedTypeListing = orderedTypeListing.GroupBy(
          t => 
          { return t.Name.Length; }
          );
      groupedTypeListing.ToList().ForEach(
          x => 
              Console.WriteLine("{0} : {1}", x.Key, x.Count())
              );

      Finally, I thought I'd see just how many types were included in each version of the framework, and prove that I can group by anything, including manipulating the string on the assembly's full name.

      var groupedVersionListing = orderedTypeListing.GroupBy(
          t => 
          { return t.Assembly.FullName.Split(",".ToCharArray())[1]; }
          );
      groupedVersionListing.ToList().ForEach(
          x => 
              Console.WriteLine("{0} : {1}", x.Key, x.Count()
              )
      );

      This has now let me retrieve a lot of interesting data (interesting at least to me :-) ) that I was able to write with a pretty simple query syntax and do some somewhat sophisticated things (grouping, etc).

      It turns out that our friend SharedConnectionWorkflowCommitWorkBatchService is only number 16 on my list.  The real honor goes to:

       

      AttachedPropertyBrowsableWhenAttributePresentAttribute, with 53 characters.

       

       

      Histogram of Type Name Sizes

      image

       

      Top 100 Longest Type Names

      Rank Length Name Version
      1 54  AttachedPropertyBrowsableWhenAttributePresentAttribute   v3.0
      2 53  ListViewVirtualItemsSelectionRangeChangedEventHandler   v2.0
      3 52  ServiceModelEnhancedConfigurationElementCollection`1   v3.0
      4 50  DataGridViewCellContextMenuStripNeededEventHandler   v2.0
      5 50  ListViewVirtualItemsSelectionRangeChangedEventArgs   v2.0
      6 49  DataGridViewRowContextMenuStripNeededEventHandler   v2.0
      7 49  WorkflowServiceAttributesDynamicPropertyValidator   v3.5
      8 48  DataGridViewColumnDividerDoubleClickEventHandler   v2.0
      9 47  DataGridViewCellContextMenuStripNeededEventArgs   v2.0
      10 47  DataGridViewCellStyleContentChangedEventHandler   v2.0
      11 47  ReadOnlyActiveDirectorySchemaPropertyCollection   v2.0
      12 47  ExtendedWorkflowRuntimeServiceElementCollection   v3.5
      13 46  IDataGridColumnStyleEditingNotificationService   v2.0
      14 46  DataGridViewRowContextMenuStripNeededEventArgs   v2.0
      15 46  UpdateProgressAssociatedUpdatePanelIDConverter   v3.5
      16
      46
       SharedConnectionWorkflowCommitWorkBatchService 
       v3.0
      17 46  DispatcherUnhandledExceptionFilterEventHandler   v3.0
      18 45  DataGridViewColumnDividerDoubleClickEventArgs   v2.0
      19 45  DataGridViewCellToolTipTextNeededEventHandler   v2.0
      20 45  DataGridViewEditingControlShowingEventHandler   v2.0
      21 45  DataGridViewRowDividerDoubleClickEventHandler   v2.0
      22 45  NamedServiceModelExtensionCollectionElement`1   v3.0
      23 45  StandardBindingOptionalReliableSessionElement   v3.0
      24 45  X509CertificateTrustedIssuerElementCollection   v3.0
      25 45  X509ScopedServiceCertificateElementCollection   v3.0
      26 45  InitiatorServiceModelSecurityTokenRequirement   v3.0
      27 45  RecipientServiceModelSecurityTokenRequirement   v3.0
      28 45  DataContractSerializerMessageContractImporter   v3.0
      29 45  ClientWindowsAuthenticationMembershipProvider   v3.5
      30 45  IClientFormsAuthenticationCredentialsProvider   v3.5
      31 45  AttachedPropertyBrowsableForChildrenAttribute   v3.0
      32 44  DataGridViewCellStyleContentChangedEventArgs   v2.0
      33 44  DataGridViewColumnDesignTimeVisibleAttribute   v2.0
      34 44  CodeParameterDeclarationExpressionCollection   v2.0
      35 44  ReadOnlyActiveDirectorySchemaClassCollection   v2.0
      36 44  ServiceModelConfigurationElementCollection`1   v3.0
      37 44  UseManagedPresentationBindingElementImporter   v3.0
      38 44  WS2007FederationHttpBindingCollectionElement   v3.0
      39 43  KeyContainerPermissionAccessEntryCollection   v2.0
      40 43  KeyContainerPermissionAccessEntryEnumerator   v2.0
      41 43  DataGridViewAutoSizeColumnsModeEventHandler   v2.0
      42 43  DataGridViewCellErrorTextNeededEventHandler   v2.0
      43 43  DataGridViewRowHeightInfoNeededEventHandler   v2.0
      44 43  DataGridViewRowHeightInfoPushedEventHandler   v2.0
      45 43  PerformanceCounterPermissionEntryCollection   v2.0
      46 43  TypeUniqueIdentifierSchemaImporterExtension   v2.0
      47 43  IRemoteArgumentDictionaryEnumeratorContract   v2.0
      48 43  ForeignKeyReferenceAlreadyHasValueException   v3.5
      49 43  SecurityPackageContextConnectionInformation   v2.0
      50 43  PrintSystemObjectPropertiesChangedEventArgs   v3.0
      51 43  IssuedTokenClientBehaviorsElementCollection   v3.0
      52 43  IssuedTokenParametersEndpointAddressElement   v3.0
      53 43  X509ServiceCertificateAuthenticationElement   v3.0
      54 43  TransportConfigurationTypeElementCollection   v3.0
      55 43  ClientFormsAuthenticationMembershipProvider   v3.5
      56 43  ServiceDescriptionFormatExtensionCollection   v2.0
      57 43  DispatcherUnhandledExceptionFilterEventArgs   v3.0
      58 42  DataGridViewCellToolTipTextNeededEventArgs   v2.0
      59 42  DataGridViewEditingControlShowingEventArgs   v2.0
      60 42  DataGridViewAutoSizeColumnModeEventHandler   v2.0
      61 42  DataGridViewColumnStateChangedEventHandler   v2.0
      62 42  DataGridViewRowErrorTextNeededEventHandler   v2.0
      63 42  DataGridViewRowDividerDoubleClickEventArgs   v2.0
      64 42  ToolStripItemDesignerAvailabilityAttribute   v2.0
      65 42  EdmRelationshipNavigationPropertyAttribute   v3.5
      66 42  BehaviorServiceAdornerCollectionEnumerator   v2.0
      67 42  DirectoryServicesPermissionEntryCollection   v2.0
      68 42  ForestTrustRelationshipCollisionCollection   v2.0
      69 42  X509ClientCertificateAuthenticationElement   v3.0
      70 42  ServiceControllerPermissionEntryCollection   v2.0
      71 42  DatabaseNotEnabledForNotificationException   v2.0
      72 42  DesignTimeResourceProviderFactoryAttribute   v2.0
      73 41  CryptographicUnexpectedOperationException   v2.0
      74 41  DataGridPreferredColumnWidthTypeConverter   v2.0
      75 41  IDesignTimeResourceProviderFactoryService   v2.0
      76 41  SiteMapDesignerHierarchicalDataSourceView   v2.0
      77 41  WindowsUserNameSecurityTokenAuthenticator   v3.0
      78 41  PrintSystemObjectPropertyChangedEventArgs   v3.0
      79 41  ConnectionOrientedTransportBindingElement   v3.0
      80 41  SecurityContextSecurityTokenAuthenticator   v3.0
      81 41  SecureConversationSecurityTokenParameters   v3.0
      82 41  X509CertificateInitiatorServiceCredential   v3.0
      83 41  X509CertificateRecipientServiceCredential   v3.0
      84 41  RecordDescriptionToTypeReferenceConverter   v3.0
      85 41  BlobMessageEncodingBindingElementImporter   v3.0
      86 41  DistributedTransactionPermissionAttribute   v2.0
      87 41  CompositeActivityDesignerLayoutSerializer   v3.0
      88 41  SqlPersistenceWorkflowInstanceDescription   v3.0
      89 41  AttachedPropertyBrowsableForTypeAttribute   v3.0
      90 40  DataGridViewAutoSizeColumnsModeEventArgs   v2.0
      91 40  DataGridViewCellErrorTextNeededEventArgs   v2.0
      92 40  DataGridViewCellStateChangedEventHandler   v2.0
      93 40  DataGridViewRowHeightInfoNeededEventArgs   v2.0
      94 40  DataGridViewRowHeightInfoPushedEventArgs   v2.0
      95 40  ListViewItemSelectionChangedEventHandler   v2.0
      96 40  DesignerSerializationVisibilityAttribute   v2.0
      97 40  TypeSmallDateTimeSchemaImporterExtension   v2.0
      98 40  SchemaImporterExtensionElementCollection   v2.0
      99 40  ProtectedConfigurationProviderCollection   v2.0
      100 40  DirectoryAttributeModificationCollection   v2.0
    • mwinkle.blog

      We're Hiring

      • 2 Comments

      My team is looking for people interested in building the next generation of the WF designer.  We've posted an opening here, please let me know if you're interested. 

      I can't really say too much about what we're building, but it's a great team that's committed to creating a great experience for building, editing, and viewing workflows.  Everyone on the team believes in the power of a declarative model of process, and believes that tools are the way that model is consumable by humans.  Everyone also believes that we're making it easier to write code and solve problems with software, which makes our mission exciting.

      From the job posting:

      Windows Workflow Foundation (WF) is the workflow engine that powers SharePoint, Speech Server, the next major release of BizTalk, and countless customer and partner solutions as part of the .NET Framework. Our team builds the tooling that allows people to rapidly model, execute and debug the execution logic of their applications in a rich, graphical programming environment. The tools we build range from flowchart and process designers, to the visualization and management of complex rule sets. If you’re passionate about enabling the rapid modeling of process, or creating a great user experience building on the power of WPF, check us out. The tools we build will ship inside the next release of Visual Studio and the .NET Framework, and support the “Oslo” effort currently ongoing in Microsoft’s Connected Systems Division.

      The Program Manager role so far has been a great experience for me (coming up on 4 months now).  If you've got questions, drop me a line at mwinkle [at] [large redmond based software firm].com. 

    • mwinkle.blog

      Designer Rehosting Survey

      • 1 Comments

      We're heads down working on the next version of the WF designer.  One of the areas we're considering investing in is the area of designer re-hosting.  The V1 designer had this really cool feature where you can rehost the designer inside any winforms app.  I've been surprised by the number of customers I've talked to who are very interested in doing this to either allow end users to edit process, or simply to enable the visualization of the workflow.

      We're really interested in why and how you are using designer rehosting (or, even more importantly, why you may have decided to not rehost the designer).

      We've got a survey posted here, and would appreciate a few minutes of your time to fill it out.

    • mwinkle.blog

      You say XAML, I say XOML, PoTAYto, PoTAHto, let's call the whole thing off

      • 8 Comments

      With all due respect to George and Ira Gershwin, I have a quick question for the readers of this blog.  In V1, we have an interesting scenario is talked about frequently, and that's the file extension of our xml form of workflow. 

      When we debuted at PDC05, there existed an XML representation of the workflow which conformed to a schema that the WF team had built, and it was called XOML.  Realizing that WPF was doing the same thing to serialize objects nicely to XML, we moved to that (XAML), but the file extensions had been cast in stone due to VS project setups.  So, we had XAML contained in a XOML file.

      Is this a problem for you?  I could see three possible solutions in the future <insert usual disclaimer, just gathering feedback>:

      • XOML -- we have a legacy now, let's not change it
      • XAML -- it's XAML, so change the file extension to match it (and introduce an overload to the XAML extension, which for now is associated with WPF)
      • something else, say .WFXAML -- this reflects the purpose, is unique to declarative workflows and doesn't have any weird connotations (What does xoml stand for???).

      Is this an issue?  Is this something you would like to see changed?  Do any of these solutions sound like a good idea, bad idea, etc?

      Thanks, we appreciate your feedback :-)

    • mwinkle.blog

      Would you like to refactor workflows?

      • 9 Comments

      One of the things I am working on now is the next release of the workflow designer.  One thing I have heard a number of requests for over the years is the ability to refactor workflows.  I'd love to get some feedback if this would be valuable (I'm pretty convinced it is), and if it is valuable, what kind of things would you like to be able to do?  One I have heard before is the selection of some subset of activities in a workflow and select "refactor to new activity" which would pull that out to a new custom activity.

      What other things make sense?  Please reply in comments, a blog post that pingbacks, or send me email at mwinkle_AtSign_Microsoft_dot_com.

       

      <Usual disclaimers apply, this is not something we have made any decisions about, I am just trying to gather some data>

    • mwinkle.blog

      Workflows that don't start with a Receive

      • 5 Comments

      A question recently came up on an internal list about how to start a workflow to do some work and then have it accept a message via a Receive activity.  This led to an interesting discussion that provides some insight into how the WorkflowServiceHost instantiates workflows in conjunction with the ContextChannel.

      Creating a Message Activated Workflow

      By default, the WorkflowServiceHost will create a workflow when the following two conditions are true:

      • The message received is headed for an operation that is associated with a RecieveActivity that has the CanCreateInstance property set to true
      • The message contains no context information

      It is interesting to note that you don't even need to use a binding element collection that contains a ContextBindingElement.  The ContextBindingElement is responsible for creating the ContextChannel.  The job of the ContextChannel is to do two things on the Receive side

      • Extract the context information and pass that along up the stack (hand it off into the service model)
      • On the creation, and only on the creation, of a new instance, return the context information to the caller in the header of the response.

      So, if we want to create workflows based on messages dropped into an MSMQ queue, we can do that by not trying to add the ContextBindingElement into a custom binding on top of the netMsmqBinding, and associating the operation with a Receive activity with the CanCreateInstance equaling true. Note, that any subsequent communication with the workflow will have to occur with a communication channel over which we can pass context.

      Creating a Non-Message Activated Workflow

      In the case that this post is about, we do not want to activate off an inbound message.  The way to do this doesn't require much additional work.  We first need to make sure we don't have any of our Receive activities marked with CanCreateInstance to true.  This means that no message coming in can activate the workflow.  Our workflow will then do some work prior to executing the Receive activity and waiting for the next message.  Our workflow will look like this (pretty simple)

      image 

      When we want to start a workflow, we need to reach into the workflow service host and extract the workflow runtime and initiate the workflow:

      WorkflowServiceHost myWorkflowServiceHost = new WorkflowServiceHost(typeof(Workflow1), null);
      // do some work to set up workflow service host
      myWorkflowServiceHost.Open();
      // on some reason to start the workflow
      WorkflowRuntime wr = myWorkflowServiceHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime;
      WorkflowInstance wi = wr.CreateWorkflow(typeof(Workflow1));
      wi.Start();
      // need to send wi.InstanceId somewhere for others to communicate with it
      The last note is important.  In order for a client to eventually be able to communicate to the workflow, the workflow instance Id will need to be relayed to that client. 
    • mwinkle.blog

      .NET 3.5 Beta Exams

      • 1 Comments

      Trika dropped me an email asking me to point out the nice fact that if you're interested in taking a beta certification exam for WPF, WCF or WF, they've extended the deadline out a few weeks.  This means you can take a beta version of the test (FOR FREE), and if you pass it counts as if you passed the actual test, but you can get an early jump on the certification train this way.

      Check it out here.

    • mwinkle.blog

      Musings for 2008 Resolutions

      • 2 Comments

      It seems to be the thing to note a few things one will try to do better in the new year.  What follows are my resolutions that are related to things at work.

      • Work with Outlook shut off - let me focus on the task at hand
      • Work with minimal internet induced interruption - see note above :-)
      • Find interesting WF content to blog about until I can talk more about the work going on for Oslo
      • Ask a lot more questions of you, what your experience is with the WF designer, and what we can do to make that better
      • Learn F# - I enjoyed the brief excursion into Lisp while an undergrad, I would like to get back into thinking in a functional way
      • Work to improve my speaking skills - I've been happy with my performance at the conferences I have spoken at, but I haven't really done anything to try to take that to the next level. 
        • A corollary: Deliver at least one "non-traditional" presentation - I (and many people in the audiences) see a million and a half "bludgeoned by bullet point" presentations a year.  I'd like to try something different (a good example of this is Larry Lessig's talk at TED this past spring (deeper sidenote, a great collection of interesting speakers and speaking styles are present at the TED podcast.  I always make sure to have a few of those on my Zune to watch on the bus))
      • See you all at PDC :-)
    • mwinkle.blog

      mwinkle.SetState("newRole")

      • 1 Comments

      I'm moving on from my role as the technical evangelist for WF, but not too far.  I've joined the product team, working as a program manager (PM) for the Connected Tools team.  The job of the connected tools team is to provide all of the tools for the technologies inside the Oslo effort, including the WF designer.  As such, I'll be focused on the programming model for activity designers to use when they create WF activities.

      Oslo is interesting, as it represents the first real chance to look at the stuff we did in V1 of WF and think about it and find out ways we can improve on the experience.  .NET 3.5 was a very "constrained" release for the WF team, as we had only shipped about 12 months prior, so we were primarily concerned with adding functionality to what we shipped (the WF/WCF integration, for instance).  For WF, Oslo will be our first chance to take in a lot of the feedback we have heard (and keep it coming) to move things to the next level.  I'm excited to be part of that effort, especially from the designer side of things, as I see a great opportunity to simplify a number of things that a lot of our customers have been doing.

      It was a tough decision to leave DPE (developer and platform evangelism).  The job of a TE is probably one of the closest to geek nirvana one can achieve.  It was a bit odd when I was looking into this new position to lead off by saying, "I'm leaving the best job I've had."  I didn't do it because anything was wrong with the role, on the contrary, it is a perfect fit for anyone who is deeply passionate about technology and wants to drive that passion and excitement out to the rest of the world while working with an entire team of people focused on that goal.  My new role offered a really unique opportunity to have a large influence on the way people see WF (literally).  I'm also a bit crazy about making sure the tools are right, because that is going to be the bit of the technology most people will see first, and the way many people will interact with the product. Finally, when I look at the things I want to accomplish at Microsoft, shipping a product is a big item on that list. 

      As we're not talking publicly yet about a lot of the stuff we are doing in Oslo, I probably won't be blogging about it (that tends to be frowned upon for obvious reasons).  I'll still be posting about WF, and as always, am interested in your feedback (and will probably use the blog to solicit some as well).

    • mwinkle.blog

      VS 2008 RTM's!

      • 0 Comments

      As widely reported on blogs far and wide, Visual Studio 2008 has been released to manufacturing (or shipped, available, ready to get, etc).  MSDN subscribers can do their part to degrade the global bandwidth supply and get in the download queue via the subscription center, trial editions are available here.  One can also simply get the updated version of the .NET Framework, .NET 3.5 here, and I'd strongly recommend the web setup to only get the bits you need on the machine, and not ones you may already have.

      While you're waiting for those bits to get downloaded, you might find yourself with some free time watching the status bar slowly move in the direction of completion.  Maybe I can interest you in some quality work that has been done by my former team (more on that in the next day or two). 

      First, I would grab the VS 2008 Training Kit, which consists of a metric boatload of labs, content, presentations and sample code to get you excited.  This is something my colleague, David Aiken, has been hard at work putting together.  In David's words:

      The Visual Studio 2008 and .NET Framework 3.5 Training Kit includes presentations, hands-on labs, and demos. This content is designed to help you learn how to utilize the Visual Studio 2008 features and a variety of framework technologies including: LINQ, C# 3.0, Visual Basic 9, WCF, WF, WPF, ASP.NET AJAX, VSTO, CardSpace, SilverLight, Mobile and Application Lifecycle Management.

      This content was developed over the last few months. As part of the development process, we presented many of the topics to real people we invited to Redmond. In September we recorded these sessions and are making these available on Channel 9. There will be several videos posted each Monday for the next few weeks. Today I posted:

       

       

      The Channel9 videos are especially good, these are all various Microsoft folks from the product teams presenting about their individual area of expertise.  I especially recommend the What's new in VB9 and intro to LINQ talk.  There are some pretty cool things in VB9, and I think the XML support is something really cool.  For those of you from the WF world, inside the training kit is a presentation on the WF-WCF integration, as well as a set of labs and demos that walk through simple to complex use cases.

      That should be enough to get you through a few hours of downloading :-)

      Congrats to all the product teams involved in shipping, it's always incredible to me to see how we actually ship software out of this place (and to get to take part in bits and pieces of it).

    • mwinkle.blog

      Regarding Re-use of Context-aware Proxies

      • 1 Comments

      Yesterday, following my "What's the context for this conversation" presentation, I was approached with the following question:

      I am sharing a singleton client that I want to use to interact with multiple workflow instances, how do I change the context for each of them.

      Completely unbeknownst to me, Wenlong, one of the product team's more prolific bloggers, addressed this very topic in his post here, conveniently posted yesterday :-)

    • mwinkle.blog

      Hanging in the Speaker Room

      • 2 Comments

      No One of the best parts of any conference is hanging out with the other speakers and osmosing off some of the collective brainpower in there.  Some times it is big concepts, other times, it's the little stuff.

      Like my new favorite feature of Vista (Show Desktop Icons)

      image

      No more need for a folder where I have to hide all that other stuff on my desktop.

      Right click, view, ShowDesktop icons.

       

      Sweet

    • mwinkle.blog

      Worst Presentation... Ever.

      • 4 Comments

      I would like to take this moment to apologize for all of the attendees who were at our WIN302 session this afternoon here in Barcelona.  Moments before we were scheduled to begin, a very nasty power issue hit our room, causing the lights to go out, all of the equipment on stage to shut down, and reset all of the audio equipment (replaced with a series of rather nasty sounding "pops".)  Our demo machine, which we had just spent the last few hours getting set "just so," was also a casualty of this.

      Following 10 minutes of working with stage crews, audio techs, and David frantically trying to get the demo machine back to a usable state, we decided to begin the talk.  I had counted 5 minutes since someone ran down onto the stage yelling into a walkie talkie, so I figured we were in the clear.

      David was still working on the demo, so I began the talk, and quickly needed to fill time while David worked on the demo machine. 

      In short, by the time we got back to being ready, things were all jabberwockied up, and I was most certainly off my game, and as a result found myself rambling when I should have been focused, grasping for phrasing when I should have been driving the message, and stumbling in a talk where I had hoped to be knocking it out of the park.

      I want to apologize to the attendees, because you deserved a much better talk than the one you got (and David and I are going to make it up in part 2, tomorrow). 

      Reading through the feedback was pretty hard, this is a crowd that has very high expectations, and today did not meet that bar.

      Just when you think you have things all ready to go.

      How could we have done better?

      • A backup machine, set in exactly the same fashion as the first machine would have still not been particularly pleased with the power issue.
      • I need a way to be able to save the state of all of my open visual studio windows and script out so I can run one script that opens all of the instances, and all of the right files (setting to the right spot would be nice as well).
      • Not freaked out.  We had just gotten set and ready to go, and the power thing really knocked me off kilter. 

      So, we walk away and we learn something, and we'll be back to do it again tomorrow.  Everyone has these nightmare conference stories, but that still doesn't make things better.

    • mwinkle.blog

      Greetings from Barcelona

      • 3 Comments

      I (and my entire team except for our boss) am here in beautiful Barcelona for TechEd Developer.  This is definitely one of my favorite events, because of the location, the amenities, and most importantly, the people. 

      I'm giving a number of talks throughout the week (see below), so if you're here, please drop on by.  If you don't make it to the talks, I've been known to frequent the bar on the first floor of the Hilton right next to the convention center :-)   There's also a great lineup of talks from other folks as well that I will probably be dropping into.  It will be a good week, and then on Thursday, following my last talk, I will be taking a bit of holiday until next Tuesday.

       

      Session list:

      SBP08-IS Windows Workflow Foundation (WF) Open Microphone Talk

      Matt Winkler

      • “Should I let a business analyst compose workflows?”
      • “Why is this class sealed?”
      • “How can I extend the designer to fit my scenario?”
      • “How would I build and use a repository of business rules in non-WF applications?”
      • “I think that WF is great.”
      • “I think that WF i... more

      Wed Nov 7 15:45 - 17:00 Room 130

      SBP09-IS Windows Workflow Foundation Performance

      Matt Winkler

      A key to understanding performance of any system is an understanding of the tradeoffs one can make. In a more relaxed, casual environment come and join us for a conversation about performance. This chalk talk will be organized around a series of performance considerations for Windows Workflow Foundation and how those c... more

      Thu Nov 8 17:30 - 18:45 Room 125 , Thu Nov 8 10:45 - 12:00 Room 128

      SBP304 Implementing Workflow Enabled Services and Durable Services using .NET Framework 3.5

      Matt Winkler , Justin Smith

      Inside .NET Framework 3.5, there is new functionality allowing Windows Communication Foundation (WCF) services to be built and consumed from a Windows Workflow Foundation (WF) workflow. This session will introduce the feature, discussing motivation, scenarios, and reasons for using this feature, an architectural overvi... more

      Tue Nov 6 17:00 - 18:15 Room 114

      SBP313 What is the Context of this Conversation? Enabling Long Running Conversations in Workflow Services

      Matt Winkler

      The .NET Framework 3.5 will introduce the functionality to call services from Windows Workflow Foundation (WF), and to expose workflows as a Windows Communication Foundation (WCF) service. A common pattern is to have a workflow serve as the coordinator between a number of other processes (including workflows). This tal... more

      Wed Nov 7 10:45 - 12:00 Room 114

      Matt Winkler , David Aiken

      Come with your questions for Matt and David about the Dinner Now demo. If there is something that you need to do in .NET Framework 3.5 but don’t know how, come and ask! more

      Tue Nov 6 10:45 - 12:00 Room 130

      WIN302 .NET Framework 3.5 End-to-End: Putting the Pieces Together - Part 1

      Matt Winkler , David Aiken

      Do you build .NET Applications? In this session, learn how to use the .NET Framework to build better end-to-end solutions using the DinnerNow.NET Sample application. From a Windows Presentation Foundation (WPF) client to a Windows Communication Foundation (WCF) service tier driven by Windows Workflow Foundation (WF), w... more

      Mon Nov 5 17:45 - 19:00 Auditorium

       

      WIN303 .NET Framework 3.5 End-to-End: Putting the Pieces Together - Part 2

      Matt Winkler , David Aiken

      Do you build .NET Applications? In this session, learn how to use the .NET Framework to build better end-to-end solutions using the DinnerNow.NET Sample application. From a Windows Presentation Foundation (WPF) client to a Windows Communication Foundation (WCF) service tier driven by Windows Workflow Foundation (WF), w... more

      Tue Nov 6 09:00 - 10:15 Auditorium

    • mwinkle.blog

      SOA&BP Conference Announcements, "Oslo"

      • 2 Comments

      This morning at the SOA&BP Conference, we talked about Oslo for the first time.  For me, this is a big day, as it marks the point where the rest of the world knows what a lot of people have been and will continue to be working on.  Robert Wahbe, the VP of Connected Systems, mentioned in the keynote that Oslo can be best viewed as a series of investments that span a number of release cycles.

      What does this mean for me, a WF developer (note, these are my interpretations).

      • A vehicle for further investments in WF and WCF.  There will be a ton of enhancements in order to enable new scenarios, take the idea of modeling processes in an executable workflow to the next level, and drive performance and functional stuff.
      • Moving WF to the next level, by making it a first class citizen in this modeling world, by making rules and other artifacts get elevated into a way to modeled, managed, deployed and monitored.
      • Getting a chance to look at what people are doing with v1, and what lessons we can learn from it.  In Orcas, the stuff that we did was purely additive.  This longer release gives us a chance to enhance and improve and address things that we couldn't do in the Orcas timeframe.  There's some really exciting work going on here that I'm looking forward to talking about more in the future.
      • Finally, it gives us a better way to tell the WF hosting story, in that we will have a host and way to manage and deploy and execute WF and WCF in an host we will deliver, rather than requiring a "build on your own" approach (which still remains an option for folks who have specific hosting requirements).

      Our marketing folks always get nervous when we start talking about "revolutionary" technology (although, maybe it would get us some more Apple 1984 like commercials :-) ).  I've always seen workflow as a very transformational technology.  I see the things that are coming in Oslo as a very natural, evolutionary step, in the process of what I believe has been, and will continue to be a revolutionary way of making us be more productive developers.

      Finally, given some of the past history people have had with version numbers, I would not get caught up in the version numbers mentioned in press release.  As one of the marketing guys told me, "The quotes mean something," which, translated means "The numbers are just placeholders indicating a major release beyond where we are currently at."

    • mwinkle.blog

      Activities Survey

      • 1 Comments

      So, we're getting close to .NET 3.5 getting out the door, and as always we're thinking about what comes next.  The activities team is looking how to make activities better going forward, and they are very interested in what you have to say, how you have been using them and how you'd like to use them.

      This feedback will help us understand how to shape the future of things and how we should think about the pain points you are experiencing.

      Fill survey out here!

    • mwinkle.blog

      .NET 3.5 on Channel9

      • 1 Comments

      Following the big announcement last week, I got tapped to do a quick c9 interview with Shawn Burke.  Check it out here if you have 11 minutes or so to spare and want to see what the .NET source debugging will look like.

      Additionally, I see on the homepage that Jack is talking about the add-in framework in the latest video there.  Folks, if you work on a project where you want to allow add-in functionality, or have the need to version components separately and distinctly from the host, you need to check this out.  There are a few moving pieces and parts, but if you need to enable this scenario, investing up front in thinking through these bits and pieces will be enormously helpful.

    Page 3 of 6 (148 items) 12345»