2011-09-28 4 views
2

D'abord un avertissement - Je suis nouveau à WF et j'ai beel jouer avec WF4 seulement pendant 3 jours - si des excuses sur des questions bénignes ou boiteux que je pourrais avoir ...StateMachine dans WF4

Je suis en train de implémenter WF4 State Machine dans mon projet. Voici quelques informations de fond:

  1. je UI WinForm comme application principale qui peut générer différentes commandes à une pile de mise en réseau
  2. Je couche d'interface comme une DLL qui reçoit des événements à partir d'une pile réseau
  3. Le La machine d'état doit implémenter une machine d'état de softphone quelque part dans la couche intermédiaire parallèle à la couche d'interface. L'état du téléphone change en fonction des événements réseau et des actions de l'utilisateur. Certaines actions de l'utilisateur provoquent simplement des commandes de mise en réseau et certaines peuvent affecter directement la machine d'état.
  4. Ma couche d'interface implémente un objet Phone donc j'ai fait de cet objet un hôte de la machine d'état. Je passe mon principal objet d'interface WinSipItf à l'objet de téléphone et effectuez les opérations suivantes (vie de l'objet WinSipItf dans un autre espace de noms WinSipNetLib):

code:

public void Initialize(WinSipNetLib.WinSipItf winSipItf, string hostname, string user, string password) 
{ 
    try 
    { 
     WinSipItf = winSipItf; 
     var Itf = WinSipItf; 
     var input = new Dictionary<string, object> 
        { 
         {"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); 
    } 
} 

Téléphone état initial est initial et il a déclencheur automatique/nul avec un état cible PhoneIdle. OnEntrace à l'état initial J'ai besoin d'exécuter quelques enregistrements de téléphone avec la pile de réseau - enregistrer un rappel (opération de synchronisation) et enregistrer avec le gestionnaire de pile réseau (async). Toute cette fonctionnalité réside dans le code non géré de niveau inférieur auquel j'accède via les API construites dans ma couche Interface. Après un enregistrement réussi, je reçois un rappel dans la couche Interface et déclenche un événement. Par conséquent mon inscription acitivité ressemble à ça:

public sealed class Register : NativeActivity<Int32> 
{ 
    // Define an activity input argument of type string 
    [RequiredArgument] 
    public InArgument<WinSipNetLib.WinSipItf> winSipItf { get; set; } 

    #region Constants and Fields 

    private readonly Variable<NoPersistHandle> _noPersistHandle = new Variable<NoPersistHandle>(); 
    internal const string BookmarkName = "WaitingForAccountStatusEvent"; 

    /// <summary> 
    /// The transition callback. 
    /// </summary> 
    private BookmarkCallback registrationCallback; 

    #endregion 

    #region Properties 

    ///// <summary> 
    ///// Gets or sets PhoneTransition. 
    ///// </summary> 
    //public PhoneTransition PhoneTransition { get; set; } 

    /// <summary> 
    /// Gets a value indicating whether CanInduceIdle. 
    /// </summary> 
    protected override bool CanInduceIdle 
    { 
     get 
     { 
      return true; 
     } 
    } 

    /// <summary> 
    /// Gets TransitionCallback. 
    /// </summary> 
    private BookmarkCallback RegistrationCallback 
    { 
     get 
     { 
      return this.registrationCallback ?? (this.registrationCallback = new BookmarkCallback(this.OnRegistrationCallback)); 
     } 
    } 

    #endregion 

    #region Methods 

    /// <summary> 
    /// The cache metadata. 
    /// </summary> 
    /// <param name="metadata"> 
    /// The metadata. 
    /// </param> 
    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<T> to create the extension if it does not already exist 
     metadata.AddDefaultExtensionProvider(() => 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<Phone>(); 

     // Get (which may create) the extension 
     WaitForRegistrationExt regExt = context.GetExtension<WaitForRegistrationExt>(); 

     // 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)); 
    } 

    /// <summary> 
    /// The on transition callback. 
    /// </summary> 
    /// <param name="context"> 
    /// The context. 
    /// </param> 
    /// <param name="bookmark"> 
    /// The bookmark. 
    /// </param> 
    /// <param name="value"> 
    /// The value. 
    /// </param> 
    /// <exception cref="InvalidOperationException"> 
    /// </exception> 
    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 
} 

Comme vous pouvez le voir dans le code comme je fais cals: phone.WinSipItf.DoSipRegister est-il valide? Je pense que toutes les machines d'état s'exécutent sur un thread différent de celui que l'objet WinSipItf est construit ... Redondant pour dire que je n'arrive à rien avec ça ... Je ne peux même pas faire une pause dans Execute ou CacheMetadata. Je ne sais pas quoi faire à ce stade. Il vaut la peine de mentionner que mon diagramme xaml est assez construit mais j'essayais de mettre en œuvre uniquement l'état initial et sa transition en état inactif en construisant cette activité personnalisée ...

Peut-être que je shouold ont commencé à partir d'une question simple: je Je reçois la "Valeur pour un argument d'activité requis" winSipItf "n'a pas été fourni" d'avertissement lorsque je dépose mon activité de Registre sur l'état Entrée d'initial. J'ai vérifié tout le code et je ne vois pas pourquoi. Qu'est-ce que je rate?

Répondre

0

Vous n'avez pas ajouté la définition de workflow, mais l'erreur "La valeur d'un argument d'activité requis 'winSipItf' n'a pas été fournie" semble être le résultat de l'argument winSipItf sur l'activité de Registre non définie. Il est marqué comme requis, il doit donc être défini à l'aide d'une expression VB dans le flux de travail. Vous fournissez un argument avec le nom winSipItf au workflow mais qui est lié à un argument worklfow et ne se propage pas aux activités contenues avec le même nom d'argument.