private void OnStateChanged(ServiceState state) { ServiceState before = this.State; StateProperty.SetValue(this, state); if (state == ServiceState.Ended) { TimeEndedProperty.SetValue(this, DateTime.Now); } this.Save(); if (this.StateChanged != null) { StateChanged(this, new ServiceStateChangedEventArgs(before, state)); } // Abort child services that are still running if (state == ServiceState.Aborting) { foreach (ServiceInstance instance in _childServices.Keys) { if (instance.State != ServiceState.Aborting && instance.State != ServiceState.Ended) { instance.Abort(); } } } }
void OnOutcomeReported(ServiceOutcome outcome) { OutcomeProperty.SetValue(this, outcome); 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; * } */ }
/// <summary> /// Shortcut for mapping a list from a subquery. /// </summary> public static Mapping <ParentT> MapListFromSubquery <ParentT, ItemT>( this Mapping <ParentT> mapping, EntityProperty <ParentT, List <ItemT> > listProperty, string subqueryName, Action <Mapping <ParentT> > parentMappingFunction, Action <Mapping <ItemT> > itemMappingFunction ) { mapping.Map <List <ItemT> >(listProperty, list => list .Subquery <ItemT>(subqueryName, subquery => subquery .Map <ParentT>("parent", parentMappingFunction) .Map <ItemT>("item", itemMappingFunction) .Do(context => { var parent = context.GetVariable <ParentT>("parent"); var item = context.GetVariable <ItemT>("item"); var l = listProperty.GetValue(parent); if (l == null) { l = new List <ItemT>(); listProperty.SetValue(parent, l); } l.Add(item); // This has no real value but helps makes sense of this cruel world context.Target = item; }) ) ); return(mapping); }
/// <summary> /// Shortcut for mapping a collection from a subquery. /// </summary> public static Mapping <ParentT> MapListFromSubquery <ParentT, ItemT>( this Mapping <ParentT> mapping, EntityProperty <ParentT, List <ItemT> > listProperty, string subqueryName, Action <Mapping <ParentT> > parentMappingFunction, Action <Mapping <ItemT> > itemMappingFunction ) { mapping.Map <List <ItemT> >(listProperty, list => list .Subquery <ItemT>(subqueryName, subquery => subquery .WhenInbound(inbound => inbound .Map <ParentT>("parent", parentMappingFunction) .Map <ItemT>("item", itemMappingFunction) .Do(context => { var parent = context.GetVariable <ParentT>("parent"); var item = context.GetVariable <ItemT>("item"); var l = listProperty.GetValue(parent); if (l == null) { l = new List <ItemT>(); listProperty.SetValue(parent, l); } l.Add(item); // This has no real purpose but helps makes sense of this cruel world context.MappedValue = item; }) ) .WhenOutbound(outbound => { // Define the outbound source from the context, since in outbound mode we have the parent context // TODO: check significance of IsDeferred outbound.OutboundSource(context => { List <ItemT> l = list.FromContext(context); if (l == null) { return(null); } else { return(l.GetEnumerator()); } }); // Apply the item mappings to the outbound definition itemMappingFunction(outbound); } ) ) ); return(mapping); }
void OnProgressReported(float progress) { float before = progress; ProgressProperty.SetValue(this, progress); this.Save(); if (ProgressReported != null) { ProgressReported(this, EventArgs.Empty); } }
/// <summary> /// /// </summary> public void Start() { // Make sure the underlying service is available ThrowIfServiceUnavailable(); // EXCEPTION: if (State != ServiceState.Ready) { throw new InvalidOperationException("Service can only be started when it has reached a Ready state."); } // Change set to starting State = ServiceState.Starting; // Mark the time we started (this is only set once) TimeStartedProperty.SetValue(this, DateTime.Now); // Start the engine _commChannel.Engine.Run(); }
/*=========================*/ #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); } }
public new void Save() { bool isInsert = this.InstanceID < 0; string cmdText = isInsert ? @" insert into CORE_ServiceInstance (AccountID, ParentInstanceID, ServiceName, TimeScheduled, TimeStarted, TimeEnded, Priority, State, Progress, Outcome, ServiceUrl, Configuration, ActiveRule) values (@accountID:Int, @parentInstanceID:BigInt, @serviceName:NVarChar, @timeScheduled:DateTime, @timeStarted:DateTime, @timeEnded:DateTime, @priority:Int, @state:Int, @progress:Float, @outcome:Int, @serviceUrl:NVarChar, @configuration:Xml, @activeRule:Xml); select scope_identity(); " : this.State == ServiceState.Uninitialized || this.State == ServiceState.Initializing ? @" update CORE_ServiceInstance set ServiceName = @serviceName:NVarChar, TimeScheduled = @timeScheduled:DateTime, TimeStarted = @timeStarted:DateTime, TimeEnded = @timeEnded:DateTime, Priority = @priority:Int, State = @state:Int, Progress = @progress:Float, Outcome = @outcome:Int, ServiceUrl = @serviceUrl:NVarChar, Configuration = @configuration:Xml, ActiveRule = @activeRule:Xml where InstanceID = @instanceID:BigInt " : @" update CORE_ServiceInstance set TimeStarted = @timeStarted:DateTime, TimeEnded = @timeEnded:DateTime, State = @state:Int, Progress = @progress:Float, Outcome = @outcome:Int, ServiceUrl = @serviceUrl:NVarChar where InstanceID = @instanceID:BigInt " ; SqlCommand cmd = DataManager.CreateCommand(cmdText); // Always set these cmd.Parameters["@state"].Value = this.State; cmd.Parameters["@progress"].Value = this.Progress; cmd.Parameters["@outcome"].Value = this.Outcome; cmd.Parameters["@timeStarted"].Value = this.TimeStarted == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeStarted; cmd.Parameters["@timeEnded"].Value = this.TimeEnded == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeEnded; cmd.Parameters["@serviceUrl"].Value = this.ServiceUrl == null ? (object)DBNull.Value : (object)this.ServiceUrl; // Set only when uninitialized if (this.State == ServiceState.Uninitialized || this.State == ServiceState.Initializing) { cmd.Parameters["@serviceName"].Value = Configuration.Name; cmd.Parameters["@timeScheduled"].Value = this.TimeScheduled == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeScheduled; cmd.Parameters["@priority"].Value = this.Priority; cmd.Parameters["@configuration"].Value = this.Configuration.GetXml(); cmd.Parameters["@activeRule"].Value = this.ActiveSchedulingRule == null ? (object)DBNull.Value : (object)this.ActiveSchedulingRule.GetXml(); } if (isInsert) { cmd.Parameters["@accountID"].Value = this.AccountID; cmd.Parameters["@parentInstanceID"].Value = this.ParentInstance == null ? (object)DBNull.Value : (object)this.ParentInstance.InstanceID; } else { cmd.Parameters["@instanceID"].Value = this.InstanceID; } using (SqlConnection cn = new SqlConnection(AppSettings.GetAbsolute("Easynet.Edge.Services.DataRetrieval.BaseService.SourceConnectionString"))) { cmd.Connection = cn; cn.Open(); object newID; if (isInsert) { newID = cmd.ExecuteScalar(); if (newID is DBNull) { throw new Exception("Save failed to return a new InstanceID."); } InstanceIDProperty.SetValue(this, Convert.ToInt64(newID)); } else { if (cmd.ExecuteNonQuery() < 1) { throw new Exception("Save did not affect any rows."); } } } }
/*=========================*/ #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)); } AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = Directory.GetCurrentDirectory(); // 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: Log.Write( String.Format("{0} ({1})", this.Configuration.Name, this.InstanceID), "Failed to create a new AppDomain for the service.", ex); return; } }); // Once the app domain loading create the instance loadAppDomain.BeginInvoke(new AsyncCallback(delegate(IAsyncResult result) { try { ServiceStart start = (ServiceStart)_appDomain.CreateInstanceAndUnwrap( typeof(ServiceStart).Assembly.FullName, typeof(ServiceStart).FullName, false, BindingFlags.Default, null, new object[] { EdgeServicesConfiguration.CurrentFileName }, null, null ); // cross-domain invoke start.Start(new ServiceInstanceInfo(this)); } 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: Log.Write( String.Format("{0} ({1})", this.Configuration.Name, this.InstanceID), "Failed to initialize the service", ex); return; } // Try to open it again now that the service is running OpenChannelAndSubscribe(); } ), null); }
public new void Save() { bool isInsert = this.InstanceID < 0; string cmdText = isInsert ? @" insert into ServiceInstance (AccountID, ParentInstanceID, ServiceName, TimeScheduled, TimeStarted, TimeEnded, Priority, State, Progress, Outcome, ServiceUrl, Configuration, ActiveRule) values (@accountID:Int, @parentInstanceID:BigInt, @serviceName:NVarChar, @timeScheduled:DateTime, @timeStarted:DateTime,@timeEnded:DateTime, @priority:Int, @state:Int, @progress:Float, @outcome:Int, @serviceUrl:NVarChar, @configuration:Xml, @activeRule:Xml); select scope_identity(); " : this.State == ServiceState.Uninitialized || this.State == ServiceState.Initializing ? @" update ServiceInstance set ServiceName = @serviceName:NVarChar, TimeScheduled = @timeScheduled:DateTime, TimeStarted = @timeStarted:DateTime, TimeEnded = @timeEnded:DateTime, Priority = @priority:Int, State = @state:Int, Progress = @progress:Float, Outcome = @outcome:Int, ServiceUrl = @serviceUrl:NVarChar, Configuration = @configuration:Xml, ActiveRule = @activeRule:Xml where InstanceID = @instanceID:BigInt " : @" update ServiceInstance set TimeStarted = @timeStarted:DateTime, TimeEnded = @timeEnded:DateTime, State = @state:Int, Progress = @progress:Float, Outcome = @outcome:Int, ServiceUrl = @serviceUrl:NVarChar where InstanceID = @instanceID:BigInt " ; SqlCommand cmd = DataManager.CreateCommand(cmdText); // Always set these cmd.Parameters["@state"].Value = this.State; cmd.Parameters["@progress"].Value = this.Progress; cmd.Parameters["@outcome"].Value = this.Outcome; cmd.Parameters["@timeStarted"].Value = this.TimeStarted == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeStarted; cmd.Parameters["@timeEnded"].Value = this.TimeEnded == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeEnded; cmd.Parameters["@serviceUrl"].Value = this.ServiceUrl == null ? (object)DBNull.Value : (object)this.ServiceUrl; // Set only when uninitialized if (this.State == ServiceState.Uninitialized || this.State == ServiceState.Initializing) { cmd.Parameters["@serviceName"].Value = Configuration.Name; cmd.Parameters["@timeScheduled"].Value = this.TimeScheduled == DateTime.MinValue ? (object)DBNull.Value : (object)this.TimeScheduled; cmd.Parameters["@priority"].Value = this.Priority; cmd.Parameters["@configuration"].Value = this.Configuration.GetXml(); cmd.Parameters["@activeRule"].Value = this.ActiveSchedulingRule == null ? (object)DBNull.Value : (object)this.ActiveSchedulingRule.GetXml(); } if (isInsert) { cmd.Parameters["@accountID"].Value = this.AccountID; cmd.Parameters["@parentInstanceID"].Value = this.ParentInstance == null ? (object)DBNull.Value : (object)this.ParentInstance.InstanceID; } else { cmd.Parameters["@instanceID"].Value = this.InstanceID; } const int maxTries = 2; int tries = 0; while (tries < maxTries) { try { using (SqlConnection cn = new SqlConnection(AppSettings.GetConnectionString("Edge.Core.Services", "SystemDatabase", configFile: EdgeServicesConfiguration.Current.ConfigurationFile))) { cmd.Connection = cn; cn.Open(); object newID; if (isInsert) { newID = cmd.ExecuteScalar(); if (newID is DBNull) { throw new Exception("Save failed to return a new InstanceID."); } else { InstanceIDProperty.SetValue(this, Convert.ToInt64(newID)); break; } } else { if (cmd.ExecuteNonQuery() < 1) { throw new Exception("Save did not affect any rows."); } else { break; } } } } catch (Exception ex) { tries++; if (tries == maxTries) { Log.Write( String.Format("{0} ({1})", this.Configuration.Name, this.InstanceID), "Failed to save ServiceInstance.", ex); if (this.InstanceID < 0) { OnStateChanged(ServiceState.Ended, false); OnOutcomeReported(ServiceOutcome.Failure, false); } } } } }