Marcadores

Los marcadores son el mecanismo que permite a una actividad esperar datos pasivamente sin tener que mantener un subproceso de flujo de trabajo. Cuando una actividad indica que está esperando un estímulo, puede crear un marcador. Esto indica al tiempo de ejecución que la ejecución de la actividad no debería considerarse completada aun cuando se devuelva el método que se está ejecutando actualmente (que creó Bookmark).

Fundamentos de los marcadores

Bookmark representa un punto en el que la ejecución se puede reanudar (y, a través de la cual, se puede entregar los datos) dentro de una instancia de flujo de trabajo. Normalmente, a Bookmark se le proporciona un nombre y el código externo (host o extensión) será el responsable de reanudar el marcador con datos pertinentes. Cuando se reanuda Bookmark, el tiempo de ejecución del flujo de trabajo programa el delegado de BookmarkCallback que estuvo asociado con ese Bookmark en el momento de su creación.

Opciones de marcador

La clase BookmarkOptions especifica el tipo de Bookmark que se crea. Los posibles valores que no se excluyen mutuamente son None, MultipleResume y NonBlocking. Use None, el valor predeterminado, al crear un Bookmark que se espera que se reanude una vez. Use MultipleResume al crear un Bookmark que se puede reanudar varias veces. Use NonBlocking al crear un Bookmark que posiblemente no se reanude nunca. A diferencia de los marcadores que se crean usando el BookmarkOptionspredeterminado, los marcadores NonBlocking no impiden que se complete una actividad.

Reanudar marcadores

Los marcadores pueden reanudarse según el código fuera de un flujo de trabajo usando una de las sobrecargas de ResumeBookmark. En este ejemplo, se crea una actividad ReadLine. Cuando se ejecuta, la actividad ReadLine crea un Bookmark, registra una devolución de llamada y, a continuación, espera a que se reanude Bookmark. Cuando lo haga, la actividad ReadLine asigna los datos que se pasaron con Bookmark a su argumento Result.

public sealed class ReadLine : NativeActivity<string>  
{  
    [RequiredArgument]  
    public  InArgument<string> BookmarkName { get; set; }  
  
    protected override void Execute(NativeActivityContext context)  
    {  
        // Create a Bookmark and wait for it to be resumed.  
        context.CreateBookmark(BookmarkName.Get(context),
            new BookmarkCallback(OnResumeBookmark));  
    }  
  
    // NativeActivity derived activities that do asynchronous operations by calling
    // one of the CreateBookmark overloads defined on System.Activities.NativeActivityContext
    // must override the CanInduceIdle property and return true.  
    protected override bool CanInduceIdle  
    {  
        get { return true; }  
    }  
  
    public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj)  
    {  
        // When the Bookmark is resumed, assign its value to  
        // the Result argument.  
        Result.Set(context, (string)obj);  
    }  
}  

En este ejemplo, se crea un flujo de trabajo que usa la actividad ReadLine para recopilar el nombre del usuario y mostrarlo en la ventana de la consola. La aplicación host realiza el trabajo real de recopilación de datos y los pasa al flujo de trabajo al reanudar Bookmark.

Variable<string> name = new Variable<string>  
{  
    Name = "name"  
};  
  
Activity wf = new Sequence  
{  
    Variables =  
    {  
        name  
    },  
    Activities =  
    {  
        new WriteLine()  
        {  
            Text = "What is your name?"  
        },  
        new ReadLine()  
        {  
            BookmarkName = "UserName",  
            Result = name  
        },  
        new WriteLine()  
        {  
            Text = new InArgument<string>((env) => "Hello, " + name.Get(env))  
        }  
    }  
};  
  
AutoResetEvent syncEvent = new AutoResetEvent(false);  
  
// Create the WorkflowApplication using the desired  
// workflow definition.  
WorkflowApplication wfApp = new WorkflowApplication(wf);  
  
// Handle the desired lifecycle events.  
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)  
{  
    // Signal the host that the workflow is complete.  
    syncEvent.Set();  
};  
  
// Start the workflow.  
wfApp.Run();  
  
// Collect the user's name and resume the bookmark.  
// Bookmark resumption only occurs when the workflow  
// is idle. If a call to ResumeBookmark is made and the workflow  
// is not idle, ResumeBookmark blocks until the workflow becomes  
// idle before resuming the bookmark.  
wfApp.ResumeBookmark("UserName", Console.ReadLine());  
  
// Wait for Completed to arrive and signal that  
// the workflow is complete.  
syncEvent.WaitOne();  

Cuando se ejecuta la actividad ReadLine, crea un Bookmark denominado UserName y, a continuación, espera a que se reanude el marcador. El host recopila los datos deseados y, a continuación, reanuda Bookmark. El flujo de trabajo se reanuda, muestra el nombre y, a continuación, finaliza. Tenga en cuenta que no se necesita el código de sincronización con respecto a la reanudación del marcador. Se puede reanudar Bookmark sólo cuando el flujo de trabajo está inactivo y, si no lo está, la llamada a ResumeBookmark se bloquea hasta que el flujo de trabajo se vuelve inactivo.

Resultado de reanudación del marcador

ResumeBookmark devuelve un valor de enumeración de BookmarkResumptionResult para indicar los resultados de la solicitud de reanudación del marcador. Los valores de devolución posibles son Success, NotReady y NotFound. Los hosts y extensiones pueden usar este valor para determinar cómo continuar.