我想通过一些特定的活动访问工作流程中的服务总线队列和主题。
我找不到符合此方案的任何内容(this MSDN article和this article by Roman Kiss)是最近的。
我想设计一个自定义活动,它使用QueueClient异步接收代理消息,使用使用async / await模式实现的BeginReceive方法(请参阅my question关于它)。
首先,我想问一下,为什么我更喜欢建议的方法(改编的WCF)而不是我想要的方法(使用QueueClient)。
然后,我将非常感谢以持久友好的方式设计它。
更新
这是我到目前为止所尝试的:
public class AsyncReceiveBrokeredMessage : AsyncCodeActivity<BrokeredMessage>
{
[RequiredArgument]
public InArgument<string> ConnectionString { get; set; }
[RequiredArgument]
public InArgument<string> Path { get; set; }
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var connectionString = this.ConnectionString.Get(context);
var path = this.Path.Get(context);
var queueClient = QueueClient.CreateFromConnectionString(connectionString, path);
var cts = new CancellationTokenSource();
context.UserState = new ReceiveState
{
CancellationTokenSource = cts,
QueueClient = queueClient
};
var task = ExecuteAsync(context, cts.Token);
var tcs = new TaskCompletionSource<BrokeredMessage>(state);
task.ContinueWith(
t =>
{
if (t.IsFaulted)
{
tcs.TrySetException(t.Exception.InnerExceptions);
}
else if (t.IsCanceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(t.Result);
}
if (callback != null)
{
callback(tcs.Task);
}
});
return tcs.Task;
}
protected sealed override BrokeredMessage EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var task = (Task<BrokeredMessage>)result;
try
{
return task.Result;
}
catch (OperationCanceledException)
{
if (context.IsCancellationRequested)
{
context.MarkCanceled();
}
else
{
throw;
}
return null; // or throw?
}
catch (AggregateException exception)
{
if (exception.InnerException is OperationCanceledException)
{
if (context.IsCancellationRequested)
{
context.MarkCanceled();
}
else
{
throw;
}
return null; // or throw?
}
ExceptionDispatchInfo.Capture(exception.InnerException).Throw();
throw;
}
}
protected override void Cancel(AsyncCodeActivityContext context)
{
var state = (ReceiveState)context.UserState;
state.CancellationTokenSource.Cancel();
}
private async Task<BrokeredMessage> ExecuteAsync(
AsyncCodeActivityContext context, CancellationToken cancellationToken)
{
var receiveState = context.UserState as ReceiveState;
var receiveTask = Task<BrokeredMessage>.Factory.FromAsync(
receiveState.QueueClient.BeginReceive, receiveState.QueueClient.EndReceive, null);
var completionTask = receiveTask.ContinueWith(
t =>
{
BrokeredMessage result;
if (t.IsCanceled)
{
context.MarkCanceled();
result = null;
}
else if (t.IsFaulted)
{
result = null;
}
else
{
t.Result.Complete();
result = t.Result;
}
receiveState.QueueClient.Close();
return result;
},
cancellationToken);
return await completionTask;
}
private class ReceiveState
{
public CancellationTokenSource CancellationTokenSource { get; set; }
public QueueClient QueueClient { get; set; }
}
}
并以这种方式测试(使用本地Windows Server Service Bus):
var connectionString = new Variable<string>
{
Default = connectionStringValue
};
var path = new Variable<string>
{
Default = pathValue
};
var test = new While
{
Body =
new Pick
{
Branches =
{
new PickBranch
{
Trigger =
new AsyncReceiveBrokeredMessage
{
ConnectionString = new InArgument<string>(connectionString),
Path = new InArgument<string>(path)
},
Action =
new WriteLine
{
Text =
"Received message"
}
},
new PickBranch
{
Trigger =
new Delay
{
Duration = TimeSpan.FromSeconds(10)
},
Action =
new WriteLine
{
Text =
"Timeout!"
}
}
}
},
Condition = true,
Variables = { connectionString, path }
};
WorkflowInvoker.Invoke(test);
如果我不断发送消息,我会按预期收到消息。问题在第一次超时后出现,因为那时我没有收到任何消息。 任何澄清都表示赞赏。
答案 0 :(得分:1)
首先,您需要了解一些重要的事情: 1)工作流程是长时间运行的过程,意味着可以在以后使用并可恢复。 2)工作流被唤醒和恢复的方式是书签。 3)通常人们喜欢他们的工作流程在暂停时也可以保持。 (如果你不关心持久性,你为什么还要使用WF - 只是为了视觉设计工具?)
逻辑问题:
如果您的所有工作流程及其活动都被保留并暂停,那么您的活动代码的 none 甚至已加载,那么谁在进行聆听?答案:别的东西,而不是活动,必须是在ServiceBus队列上侦听并负责恢复书签以唤醒工作流程的事情。
某些内容是工作流程&#39;主机&#39;或其某些扩展。以下是一些关于如何自定义主机以监听[来自GUI按钮]的消息并唤醒工作流活动的博客文章。
http://blogs.msdn.com/b/tilovell/archive/2011/02/26/wf4-workflow-4-0-hosting-extensions-redux.aspx
http://blogs.msdn.com/b/tilovell/archive/2010/06/08/wf4-workflow-4-0-hosting-extensions.aspx
你可以做的是获取此代码并使其适应于侦听ServiceBus队列而不是GUI按钮,并唤醒您自己的ReceiveFromServiceBus活动,这类似于PageActivity - 请注意您必须按顺序编写NativeActivity正确使用书签。
所有相当麻烦......但我相信“正确的”#39;用WF 做 的方法。
答案 1 :(得分:0)
队列实体提供以下功能: “能够指定将消息添加到队列的时间。”
经过一段时间的超时后,由于这条规则,你可能无法收到?
5月决议是:
检测入站邮件重复项,允许客户端多次发送相同的邮件而不会产生不良后果。
答案 2 :(得分:0)
可能是DefaultMessageTimeToLive或TimeToLive属性的问题。
NamespaceManager.CreateSubscription(
new SubscriptionDescription(TopicName, SubscriptionName)
{
LockDuration = TimeSpan.FromMinutes(5),
DefaultMessageTimeToLive = TimeSpan.FromDays(7),
EnableDeadLetteringOnMessageExpiration = true
});