我们在使用工作流服务时,一般会在工作流设计中使用Receive等消息活动,然后使用WorkflowServiceHost进行宿主,如果没有Receive活动,工作流就无法接受发送来的消息,这个时候我们可以使用WorkflowHostingEndpoint类:
要宿主一个没有服务的工作流,需要继承WorkflowHostingEndpoint并重写OnGetInstanceId,OnGetCreationContext,OnResolveBookmark。首先我们要声明一个服务契约,该契约包含一个创建新实例的服务操作,这个操作要传一个IDictionary<string,object>参数,这个契约隐式被WorkflowHostingEndpoint实现。当宿主这个工作流时,使用WorkflowServiceHost的AddServiceEndpoint方法添加。下面举例说明:
1.下面是项目结构:
[ServiceContract(Name = "IWorkflowCreation")]
public interface IWorkflowCreation
{
[OperationContract(Name = "Create")]
Guid Create(IDictionary<string, object> inputs);
[OperationContract(Name = "CreateWithInstanceId", IsOneWay = true)]
void CreateWithInstanceId(Guid instanceId, IDictionary<string, object> inputs);
[OperationContract(Name = "ResumeBookmark", IsOneWay = true)]
void ResumeBookmark(Guid instanceId, string bookmarkName, string message);
}
3.下面是ResumeBookmarkEndpoint的实现:
namespace CaryCommon
{
public class ResumeBookmarkEndpoint : WorkflowHostingEndpoint
{
public ResumeBookmarkEndpoint(Binding binding, EndpointAddress address)
: base(typeof(IWorkflowCreation), binding, address)
{
}
protected override Guid OnGetInstanceId(object[] inputs, OperationContext operationContext)
{
if (operationContext.IncomingMessageHeaders.Action.EndsWith("Create"))
{
return Guid.Empty;
}
else if (operationContext.IncomingMessageHeaders.Action.EndsWith("CreateWithInstanceId") ||
operationContext.IncomingMessageHeaders.Action.EndsWith("ResumeBookmark"))
{
return (Guid)inputs[0];
}
else
{
throw new InvalidOperationException("Invalid Action: " + operationContext.IncomingMessageHeaders.Action);
}
}
protected override WorkflowCreationContext OnGetCreationContext(object[] inputs, OperationContext operationContext, Guid instanceId, WorkflowHostingResponseContext responseContext)
{
WorkflowCreationContext creationContext = new WorkflowCreationContext();
if (operationContext.IncomingMessageHeaders.Action.EndsWith("Create"))
{
Dictionary<string, object> arguments = (Dictionary<string, object>)inputs[0];
if (arguments != null && arguments.Count > 0)
{
foreach (KeyValuePair<string, object> pair in arguments)
{
creationContext.WorkflowArguments.Add(pair.Key, pair.Value);
}
}
responseContext.SendResponse(instanceId, null);
}
else if (operationContext.IncomingMessageHeaders.Action.EndsWith("CreateWithInstanceId"))
{
Dictionary<string, object> arguments = (Dictionary<string, object>)inputs[0];
if (arguments != null && arguments.Count > 0)
{
foreach (KeyValuePair<string, object> pair in arguments)
{
creationContext.WorkflowArguments.Add(pair.Key, pair.Value);
}
}
}
else
{
throw new InvalidOperationException("Invalid Action: " + operationContext.IncomingMessageHeaders.Action);
}
return creationContext;
}
protected override System.Activities.Bookmark OnResolveBookmark(object[] inputs, OperationContext operationContext, WorkflowHostingResponseContext responseContext, out object value)
{
Bookmark bookmark = null;
value = null;
if (operationContext.IncomingMessageHeaders.Action.EndsWith("ResumeBookmark"))
{
bookmark = new Bookmark((string)inputs[1]);
value = (string)inputs[2];
}
else
{
throw new NotImplementedException(operationContext.IncomingMessageHeaders.Action);
}
return bookmark;
}
}
}
4.下面完成工作流,首先定义一个自定义活动如下:
namespace CaryHost
{
public sealed class CaryActivity<T> : NativeActivity<T>
{
public string BookmarkName { get; set; }
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(BookmarkName, new BookmarkCallback(OnBookmarkCallback));
}
void OnBookmarkCallback(NativeActivityContext context, Bookmark bookmark, object state)
{
this.Result.Set(context, (T)state);
}
}
}
5.工作流设计如下:
6.服务端宿主程序如下:
namespace CaryHost
{
class Program
{
static void Main(string[] args)
{
WorkflowServiceHost host = null;
try
{
host = new WorkflowServiceHost(new Workflow1(), new Uri("http://localhost"));
ResumeBookmarkEndpoint endpoint = new ResumeBookmarkEndpoint(new BasicHttpBinding(),
new EndpointAddress(new Uri("http://localhost/CaryService1.xaml")));
host.AddServiceEndpoint(endpoint);
host.Open();
Console.WriteLine("Host Started:"+endpoint.Address);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
if (host != null)
{
host.Close();
}
}
}
}
}
7.客户端调用如下:
namespace CaryClient
{
class Program
{
static void Main(string[] args)
{
ResumeBookmarkEndpoint endpoint = new ResumeBookmarkEndpoint(new BasicHttpBinding(),
new EndpointAddress(new Uri("http://localhost/CaryService1.xaml")));
IWorkflowCreation client = new ChannelFactory<IWorkflowCreation>(endpoint.Binding, endpoint.Address).CreateChannel();
Guid id = client.Create(null);
Console.WriteLine("WorkflowApplication {0} Created", id);
client.ResumeBookmark(id, "cary", "Hello Wold!");
}
}
}
8.结果如下: