void OnOutcomeReported(ServiceOutcome outcome, bool save = true) { OutcomeProperty.SetValue(this, outcome); if (save) { this.Save(); } if (this.OutcomeReported != null) { OutcomeReported(this, EventArgs.Empty); } // Service is done, so unsubscribe to the engine's events if (_commChannel != null) { if (_commChannel.State == CommunicationState.Opened) { _commChannel.Engine.Unsubscribe(); } else { _commChannel.Abort(); } } /* * // Remove event handlers from child services * foreach (ServiceInstance child in _childServices.Keys) * { * StateChanged -= _childStateHandler; * OutcomeReported -= _childOutcomeHandler; * } */ }
/*=========================*/ #endregion #region Setup /*=========================*/ public void Initialize() { // EXCEPTION: if (State != ServiceState.Uninitialized) { throw new InvalidOperationException("Service can only be initialized once per lifetime."); } // Change state to initializing - will invoke save, thus getting a new instanceID State = ServiceState.Initializing; // Get the service URL based on the instance ID6 if (this.ServiceUrl == null) { string baseUrl = AppSettings.Get(typeof(Service), "BaseListeningUrl"); ServiceUrlProperty.SetValue(this, String.Format(baseUrl, this.InstanceID)); } // Check whether the service is accessible via WCF. If it is, skip the Appdomain loading try { OpenChannelAndSubscribe(); } catch { // Communcation test failed, meaning we need to set up the service (assumisng it's down) _commChannel.Abort(); AppDomainSetup setup = new AppDomainSetup(); string assemblyDir = AppSettings.Get(typeof(Service), "AssemblyDirectory"); setup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; setup.PrivateBinPath = Path.IsPathRooted(assemblyDir) ? assemblyDir : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyDir); // Load the AppDomain in a different thread Action loadAppDomain = new Action(delegate() { try { _appDomain = AppDomain.CreateDomain(this.ToString(), null, setup); } catch (Exception ex) { // Report failure State = ServiceState.Ended; OnOutcomeReported(ServiceOutcome.Failure); // EXCEPTION: throw new Exception(String.Format("Failed to create a new AppDomain for the service. Service name: {0}.", Configuration.Name), ex); } }); // Once the app domain loading create the instance loadAppDomain.BeginInvoke(new AsyncCallback(delegate(IAsyncResult result) { try { _appDomain.CreateInstance(typeof(ServiceStart).Assembly.FullName, typeof(ServiceStart).FullName, false, BindingFlags.CreateInstance, null, new object[] { new ServiceInstanceInfo(this) }, null, null, null); } catch (Exception ex) { // Unload app domain because we can't use it anymore AppDomain.Unload(_appDomain); // Report failure State = ServiceState.Ended; OnOutcomeReported(ServiceOutcome.Failure); // EXCEPTION: throw new Exception(String.Format("Failed to initialize the service. Service name: {0}.", Configuration.Name), ex); } // Try to open it again now that the service is running OpenChannelAndSubscribe(); } ), null); } }