我正在开发一个日志应用程序,它要求我有一个作为服务公开的工作流(工作流服务)。我们希望将其作为 Windows 服务托管(不想将工作流服务作为 IIS 中的 .svc 文件托管)。将其作为 Windows 服务的另一个原因是能够通过命名管道与服务进行通信。

我们可以通过命名管道公开工作流服务而不将其托管在 IIS 中吗?

最佳答案

是的,你肯定可以。至少,我在 Workflow 4 Release Candidate 中取得了同样多的成就。

考虑,

// a generic self-hosted workflow service hosting thingy. Actual
// implementation should contain more logging and thread safety, this
// is an abbreviated version ;)
public class WorkflowHost
{

    // NOTE: with Workflow, it helps to maintain a concept of
    // Workflow definition [the Activity or WorkflowService from
    // a designer] and a Workflow instance [what is running within
    // WorkflowInvoker, WorkflowApplication, WorkflowServiceHost].
    // a definition may be used to generate an instance. an instance
    // contains run-time state and cannot be recycled into a new
    // instance. therefore, to repeatedly re-host a WorkflowService
    // we need to maintain references to original definitions and
    // actual instances. ergo services and hosts maps
    //
    // if you are special purpose and require support for one and
    // only one service and endpoint\uri, then you may reduce this
    // to a simple tuple of Uri, WorkflowService, WorkflowServiceHost

    // services represents a definition of hosted services
    private readonly Dictionary<Uri, WorkflowService> _services =
        new Dictionary<Uri, WorkflowService> ();

    // hosts represents actual running instances of services
    private readonly Dictionary<Uri, WorkflowServiceHost> _hosts =
        new Dictionary<Uri, WorkflowServiceHost> ();

    // constructor accepts a map of Uris (ie service endpoints) to
    // workflow service definitions
    public WorkflowHost (IDictionary<Uri, WorkflowService> services)
    {
        foreach (KeyValuePair<Uri, WorkflowService> servicePair in services)
        {
            _services.Add (servicePair.Key, servicePair.Value);
        }
    }

    // have your windows service invoke this to start hosting
    public void Start ()
    {
        if (_hosts.Count > 0)
        {
            Stop ();
        }

        foreach (KeyValuePair<Uri, WorkflowService> servicePair in _services)
        {
            WorkflowService service = servicePair.Value;
            Uri uri = servicePair.Key;
            WorkflowServiceHost host = new WorkflowServiceHost (service, uri);

            host.Open ();

            _hosts.Add (uri, host);
        }
    }

    // have your windows service invoke this to stop hosting
    public void Stop ()
    {
        if (_hosts.Count > 0)
        {
            foreach (KeyValuePair<Uri, WorkflowService> servicePair in
                _services)
            {
                WorkflowService service = servicePair.Value;
                Uri uri = servicePair.Key;

                IDisposable host = _hosts[uri];
                host.Dispose ();
            }

            _hosts.Clear ();
        }
    }
}

我相信端点配置可以通过 App.config 中的标准 Wcf 服务配置部分设置。在我的 Workflow 实验中,我没有亲自尝试更改默认传输层。

以上代表了一个通用的纯托管类[即它自托管 WorkflowServices]。这使我们可以在控制台、WinForm、WPF 或什至是 WindowsService 应用程序中重用此托管功能。下面是利用我们的主机类的 WindowsService
// windows service. personally i would abstract service behind
// an interface and inject it, but again, for brevity ;)
public partial class WorkflowWindowsService : ServiceBase
{
    WorkflowHost _host;

    public WorkflowWindowsService ()
    {
        InitializeComponent();

        Dictionary<Uri, WorkflowService> services =
            new Dictionary<Uri, WorkflowService> ();

        // do your service loading ...

        // create host
        _host = new WorkflowHost (services);
    }

    protected override void OnStart(string[] args)
    {
        _host.Start ();
    }

    protected override void OnStop()
    {
        _host.Stop ();
    }
}

如果您在 VS2010RC 中使用过 WorkflowServices,那么您可能已经知道 WorkflowServices 不是像它们的 Workflow 表兄弟那样的一流 Xaml 类。相反,它们保存为扩展名为 .xamlx 的松散 Xaml 文件。 WorkflowServices 没有设计时智能感知支持 [据我所知] 并且不被识别为声明类型,因此我们在运行时加载 WorkflowService 的唯一选项是
  • 直接从 .xamlx 文件读取纯 Xaml 标记
  • 从其他来源[嵌入式字符串、资源或其他来源]读取纯 Xaml 标记

  • 无论哪种方式,我们都必须解释标记并创建 WorkflowService 定义。下面将把一个字符串 [可能是一个文件名或标记] 转换成一个 WorkflowService。热衷者可能还注意到,此过程与将工作流标记转换为工作流定义的过程之间存在差异。
    // converts a string value [either pure xaml or filename] to a
    // WorkflowService definition
    public WorkflowService ToWorkflowService (string value)
    {
        WorkflowService service = null;
    
        // 1. assume value is Xaml
        string xaml = value;
    
        // 2. if value is file path,
        if (File.Exists (value))
        {
            // 2a. read contents to xaml
            xaml = File.ReadAllText (value);
        }
    
        // 3. build service
        using (StringReader xamlReader = new StringReader (xaml))
        {
            object untypedService = null;
    
            // NOTE: XamlServices, NOT ActivityXamlServices
            untypedService = XamlServices.Load (xamlReader);
    
            if (untypedService is WorkflowService)
            {
                service = (WorkflowService)(untypedService);
            }
            else
            {
                throw new ArgumentException (
                    string.Format (
                    "Unexpected error reading WorkflowService from " +
                    "value [{0}] and Xaml [{1}]. Xaml does not define a " +
                    "WorkflowService, but an instance of [{2}].",
                    value,
                    xaml,
                    untypedService.GetType ()));
            }
        }
    
        return service;
    }
    

    关于wcf - 我们可以将工作流服务作为 Windows 服务托管吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2548160/

    10-11 17:31