title: StateMachine in WF4
body: <p>First a disclaimer - I am new to WF and I've beel playing with WF4 only for 3 days - so apologies on any benign or lame questions I may have...</p>
  
  <p>I am trying to implement WF4 State Machine in my project. Here is some background info:</p>
  
  <ol>
  <li>I have WinForm UI as a main app that can generate different commands to a networking stack</li>
  <li>I have Interface layer as a DLL that receives events from a network stack</li>
  <li>The state machine should implement a softphone state machine somewhere in the intermediate layer parallel to interface layer. The phone state change based on the networking events and on the user actions. Some user actions just cause networking commands and some may directly affect the state machine.</li>
  <li>My interface layer implements an object Phone so I made this object as a host of the state machine. I am passing my main interface object WinSipItf to the phone object, and do the following (WinSipItf object lives in another namespace WinSipNetLib):</li>
  </ol>
  
  <p>Code:</p>
  
  <pre><code>public void Initialize(WinSipNetLib.WinSipItf winSipItf, string hostname, string user, string password)
  {
      try
      {
          WinSipItf = winSipItf;
          var Itf = WinSipItf;
          var input = new Dictionary&lt;string, object&gt;
                      {
                          {"winSipItf", Itf}
                      };
          this.WorkFlowHostApp = new WorkflowApplication(new Activity1(), input)
          {
              Idle = this.OnWorkflowIdle,
              Completed = this.OnWorkflowCompleted
          };
  
          // Setup the Tracking to output in the debug window
          WorkFlowHostApp.Extensions.Add(new Tracker());
  
          this.WorkFlowHostApp.Extensions.Add(this);
  
          this.workflowBusy.Reset();
  
          Console.WriteLine("Starting Workflow");
          this.WorkFlowHostApp.Run();
      }
      catch (Exception ex)
      {
          Console.Write(ex);
      }
  }
  </code></pre>
  
  <p>Phone initial state is Initial and it has automatic/null trigger with a target state PhoneIdle. OnEntrace to Initial state I need to execute couple of Phone registrations with networking stack - register a callback (sync operation) and register with network stack manager (async). All this functionality lives at the lower level unmanaged code that I access through constructed APIs in my Interface layer. Upon successful registration I get a callback in the Interface layer and fire an event. Therefore my Registration Acitivity looks like that:</p>
  
  <pre><code>public sealed class Register : NativeActivity&lt;Int32&gt;
  {
      // Define an activity input argument of type string
      [RequiredArgument]
      public InArgument&lt;WinSipNetLib.WinSipItf&gt; winSipItf { get; set; }
  
      #region Constants and Fields
  
      private readonly Variable&lt;NoPersistHandle&gt; _noPersistHandle = new Variable&lt;NoPersistHandle&gt;();
      internal const string BookmarkName = "WaitingForAccountStatusEvent";
  
      /// &lt;summary&gt;
      /// The transition callback.
      /// &lt;/summary&gt;
      private BookmarkCallback registrationCallback;
  
      #endregion
  
      #region Properties
  
      ///// &lt;summary&gt;
      /////   Gets or sets PhoneTransition.
      ///// &lt;/summary&gt;
      //public PhoneTransition PhoneTransition { get; set; }
  
      /// &lt;summary&gt;
      ///   Gets a value indicating whether CanInduceIdle.
      /// &lt;/summary&gt;
      protected override bool CanInduceIdle
      {
          get
          {
              return true;
          }
      }
  
      /// &lt;summary&gt;
      /// Gets TransitionCallback.
      /// &lt;/summary&gt;
      private BookmarkCallback RegistrationCallback
      {
          get
          {
              return this.registrationCallback ?? (this.registrationCallback = new BookmarkCallback(this.OnRegistrationCallback));
          }
      }
  
      #endregion
  
      #region Methods
  
      /// &lt;summary&gt;
      /// The cache metadata.
      /// &lt;/summary&gt;
      /// &lt;param name="metadata"&gt;
      /// The metadata.
      /// &lt;/param&gt;
      protected override void CacheMetadata(NativeActivityMetadata metadata)
      {
          metadata.RequireExtension(typeof(Tracker));
          metadata.RequireExtension(typeof(Phone));
          metadata.RequireExtension(typeof(WaitForRegistrationExt));
          // !!! and one more for GUI
  
          // Provide a Func&lt;T&gt; to create the extension if it does not already exist
          metadata.AddDefaultExtensionProvider(() =&gt; new WaitForRegistrationExt());
  
          metadata.AddArgument(new RuntimeArgument("winSipItf", typeof(WinSipNetLib.WinSipItf), ArgumentDirection.In, true));
          metadata.AddArgument(new RuntimeArgument("Result", typeof(int), ArgumentDirection.Out, false));
  
          metadata.AddImplementationVariable(_noPersistHandle);
      }
  
      protected override void Execute(NativeActivityContext context)
      {
          // Enter a no persist zone to pin this activity to memory since we are setting up a delegate to receive a callback
          var handle = _noPersistHandle.Get(context);
          handle.Enter(context);
  
          // Get Phone extension needed to call the functions in WinSipItf
          Phone phone = (Phone)context.GetExtension&lt;Phone&gt;();
  
          // Get (which may create) the extension
          WaitForRegistrationExt regExt = context.GetExtension&lt;WaitForRegistrationExt&gt;();
  
          // Add the callback
          regExt.AddRegistrationCallback(winSipItf.Get(context));
  
          bool bRet = phone.WinSipItf.RegisterDBusCallback("WinSipPhone");
  
          // Obtain the runtime value of the Text input argument
          if (bRet == false)
          {
              this.Result.Set(context, bRet.ToString());
              return;
          }
  
          string hostname = "demo2.demo.com";
          string username = "406";
          string password = "123123"; 
          string id = username + "@" + hostname;
          String regUri = hostname;
          if (phone.WinSipItf.DoSipRegister(id, regUri, username, password) == 0)
          {
              this.Result.Set(context, bRet.ToString());
              return;
          }
  
          // Set a bookmark - the extension will resume when the Gizmo is fired
          context.CreateBookmark(BookmarkName, RegistrationCallback);
  
          //context.CreateBookmark(this.PhoneTransition.ToString(), this.RegistrationCallback);
  
          //// Obtain the runtime value of the Text input argument
          //string text = context.GetValue(this.Text);
  
          //Result.Set(context, string.Format("The text is {0}", text));
      }
  
      /// &lt;summary&gt;
      /// The on transition callback.
      /// &lt;/summary&gt;
      /// &lt;param name="context"&gt;
      /// The context.
      /// &lt;/param&gt;
      /// &lt;param name="bookmark"&gt;
      /// The bookmark.
      /// &lt;/param&gt;
      /// &lt;param name="value"&gt;
      /// The value.
      /// &lt;/param&gt;
      /// &lt;exception cref="InvalidOperationException"&gt;
      /// &lt;/exception&gt;
      private void OnRegistrationCallback(NativeActivityContext context, Bookmark bookmark, object value)
      {
          if (value is WinSipItf.MSGDATA)
          {
  
          }
          ////if (value is StateTransitionResult)
          //{
          //    this.Result.Set(context, value as StateTransitionResult);
          //}
          //else if (value != null)
          //{
          //    // Resumed with something else
          //    throw new InvalidOperationException(
          //        "You must resume PhoneTransition bookmarks with a result of type StateTransitionResult");
          //}
  
          // Exit the no persist zone 
          var handle = _noPersistHandle.Get(context);
          handle.Exit(context);
      }
  
      #endregion
  }
  </code></pre>
  
  <p>As you can see from the code I make cals like: <code>phone.WinSipItf.DoSipRegister</code>
  Is it valid? I think all state machine is executing on a different thread from the one that the WinSipItf object is constructed...
  Redundant to say that I dont get anywhere with this... I cant even break in Execute or CacheMetadata. Not sure what to do at this point.
  Worth to mention that my xaml diagram is quite built but I was trying to implement only the Initial state and its transition to Idle state by constructing this custom activity...</p>
  
  <p>Maybe I shouold have started from a simple question: I am getting "Value for a required activity argument 'winSipItf' was not supplied" warning when I drop my Register activity on the Entry of Initial state. I checked all the code and I dont see why. WHat am I missing?</p>