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.");
                    }
                }
            }
        }
예제 #9
0
        /*=========================*/
        #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);
        }
예제 #10
0
        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);
                        }
                    }
                }
            }
        }