Can we host a Workflow Service as a Windows Service?

前端 未结 2 2060
一个人的身影
一个人的身影 2021-02-06 16:03

I am working on a logging application that requires me to have a Workflow that is exposed as a Service (Workflow Service). We want to host it as a Windows Service (don\'t want t

相关标签:
2条回答
  • 2021-02-06 16:38

    Yep bep, you sure can. At least, I have accomplished as much with Workflow 4 Release Candidate.

    Consider,

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

    I believe endpoint configuration may be set via standard Wcf service configuration sections in App.config. I have not personally attempted a change to default transport layer in my experiments with Workflow.

    The above represents a generic pure hosting class [ie it self-hosts WorkflowServices]. This allows us to re-use this hosting functionality within a console, WinForm, WPF, or yes, even a WindowsService application. Below is a WindowsService that leverages our host class

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

    If you have fiddled with WorkflowServices in VS2010RC, then you may already know that WorkflowServices are not first class Xaml classes like their Workflow cousins. Instead, they are saved as loose Xaml files with the .xamlx extension. There is no design-time intellisense support for WorkflowServices [as far as I know] and are not recognized as declared types, so our only options to load a WorkflowService at run-time are

    • Read pure Xaml markup from .xamlx file directly
    • Read pure Xaml markup from some other source [embedded string, resource, or other source]

    Either way, we must interpret markup and create a WorkflowService definition. The following will transform a string [that may be a filename or markup] into a WorkflowService. Keeners may also note that there is a difference between this process and the process for transforming Workflow markup to Workflow definitions.

    // 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;
    }
    
    0 讨论(0)
  • 2021-02-06 16:43

    Yes it is possible. You will have to create your own service. See Hosting and Consuming WCF Services on MSDN, especially the section Hosting in Windows Services.

    0 讨论(0)
提交回复
热议问题