More in this section

Forums / Developing with Sitefinity / Background process or Interval service process

Background process or Interval service process

11 posts, 0 answered
  1. KWong
    KWong avatar
    8 posts
    Registered:
    24 Nov 2008
    08 Aug 2009
    Link to this post
    Hi,
    I am looking to have some kind of background or timer base interval service process to perform some operations to the sitefinity content. I know that we can create a new background thread to the regular .NET threading API, but I just wonder is sitefinity already have something in place where I missed in the documenation. I also wonder a custom service is the way to go, but don't see how it will be running intervally or scheduled. Any ideas and directions would be appreciated.

    Thanks.

    Ken Wong.
  2. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    12 Aug 2009
    Link to this post
    Hi KWong,

    Thank you for your question.

    We do not have such background tasks yet. In fact, we have developed such service for the next major version - 4.0. I am not sure what your task will be. You can ask your hosting provider if they support some kind of configurable cron jobs.

    Regards,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the newTelerik Support Portal.
    Check out the tipsfor optimizing your support resource searches.
  3. MB
    MB avatar
    302 posts
    Registered:
    09 Jan 2005
    29 Jan 2010
    Link to this post
    I just stumbled accoss this.

    I developed a simple asp.net task scheduler, that I wrote using code located in the app_code folder.

    It's quite crude and I won't make any guarantees (or offer any support) but people are free to mess about with it and see if it fits their requirements.

    I had to hack the code below from my implementation, removing references to utility functions, namespaces, etc... but hopefully it's close enough to working that people can fix any bugs caused.

    Obviously, the nature of the code means that it's not bullet-proof, but I managed to get it reliable enough for my own purposes.

    Equally obvious, except for the individual WebTasks, it could be written as a .dll rather than locating in app_code, but I never got around to it.

    Feel free to modify, improve (it wouldn't be hard) and/or extend as you see fit.

    -- MB.

    The idea is that you have a global object that reads an XML file (no reason this could not be read from a database) and fires off WebTasks at set intervals.

    You can choose how often they should be started, and the WebTask might do its own checking to see if it should actually run, or just sliently abort.

    You can call the file whatever you like, as it's referenced by an AppSetting in the web.config

    I used this structure for my WebTasks file
    <?xml version="1.0"?>  
    <Tasks> 
        <Task name="SomeTask" 
                    type="MyNameSpace.Tasks.SomeTask" 
                    interval="300000" 
                    delay="0" 
                    enabled="true" 
                    priority="medium" 
                    errormode="ignore" 
                    /> 
    </Tasks> 


    The Task Scheduler is started/stopped from the global.asax
    public class Global : System.Web.HttpApplication  
    {  
        private MyNameSpace.TaskManager.Scheduler scheduler;  
     
        protected void Application_Start(Object sender, EventArgs e)  
        {  
            try 
            {  
                MyNameSpace.TaskManager.StartScheduler(ref this.scheduler);  
            }  
            catch 
            {  
            }  
        }  
     
        protected void Application_End(Object sender, EventArgs e)  
        {  
            try 
            {  
                MyNameSpace.TaskManager.StopScheduler(ref this.scheduler);  
            }  
            catch 
            {  
            }  
        }  

    which Instantiates the Scheduler object
    using System;  
    using System.IO;  
    using System.Web;  
    using System.Xml;  
    using System.Collections.Generic;  
    using System.Web.Compilation;  
     
    namespace MyNameSpace  
    {  
        public partial class TaskManager  
        {  
            public class Scheduler  
            {  
                public static List<Task> _tasks = null;  
                private XmlNodeList _nodes = null;  
     
                public Scheduler(XmlNodeList nodes)  
                {  
                    this._nodes = nodes;  
     
                    Initialize();  
                }  
     
                public void StartTasks()  
                {  
                    foreach (Task task in _tasks)  
                    {  
                        if (!task.Config.IsRunning)  
                        {  
                            task.Start();  
                        }  
                    }  
                }  
     
                public void StopTasks()  
                {  
                    foreach (Task task in _tasks)  
                    {  
                        task.Stop();  
                    }  
                }  
     
                private void Initialize()  
                {  
                    string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                    _tasks = new List<Task>();  
     
                    foreach (XmlNode node in this._nodes)  
                    {  
                        if (node.Name.ToLower() == "task")  
                        {  
                            try 
                            {  
                                XmlAttributeCollection attributes = node.Attributes;  
     
                                if (bool.Parse(attributes["enabled"].Value))  
                                {  
                                    Task task = new Task(double.Parse(attributes["interval"].Value));  
     
                                    task.Config.Name = attributes["name"].Value;  
                                    task.Config.TaskType = BuildManager.GetType(attributes["type"].Value, truetrue);  
                                    task.Config.IsEnabled = bool.Parse(attributes["enabled"].Value);  
                                    task.Config.Delay = double.Parse(attributes["delay"].Value);  
                                    task.Config.Priority = (MyNameSpace.TaskManager.Priority) Enum.Parse(typeof(MyNameSpace.TaskManager.Priority), attributes["priority"].Value, true);  
                                    task.Config.ErrorMode = (MyNameSpace.TaskManager.ErrorMode) Enum.Parse(typeof(MyNameSpace.TaskManager.ErrorMode), attributes["errormode"].Value, true);  
                                    task.Config.ConfigurationNode = node;  
     
                                    _tasks.Add(task);  
                                }  
                            }  
                            catch (Exception ex)  
                            {  
                                File.AppendAllText(_DebugFile, "TaskManager:Scheduler:Initialize:Error: " + ex.Message.ToString() + "\r\n");  
                            }  
                        }  
                    }  
                }  
     
            }  
     
     
        }  

    There is a TaskManager object
    using System;  
    using System.IO;  
    using System.Web;  
    using System.Xml;  
     
    namespace MyNameSpace  
    {  
        public partial class TaskManager  
        {  
            public enum Priority  
            {  
                Low = 0,  
                Medium = 1,  
                High = 2  
            }  
     
            public enum ErrorMode  
            {  
                Exit = 0,  
                Ignore = 1  
            }  
     
            public TaskManager()  
            {  
            }  
     
            public static MyNameSpace.TaskManager.Scheduler CreateScheduler()  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                MyNameSpace.TaskManager.Scheduler scheduler = null;  
     
                try 
                {  
                    LoadScheduler(ref scheduler);  
                }  
                catch (Exception ex)  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:Scheduler:Create:Error: " + ex.Message + "\r\n");  
                }  
                return scheduler;  
            }  
     
     
            public static void LoadScheduler(ref MyNameSpace.TaskManager.Scheduler scheduler)  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                try 
                {  
                    XmlDocument xml = new XmlDocument();  
                    xml.Load(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyTaskXmlFile"]));  
     
                    XmlNode root = xml.DocumentElement;  
                    XmlNodeList nodes = root.SelectNodes("//Tasks/Task");  
     
                    if (nodes.Count > 0)  
                    {  
                        scheduler = new MyNameSpace.TaskManager.Scheduler(nodes);  
                    }  
     
                }  
                catch (Exception ex)  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:Scheduler:Load:Error: " + ex.Message + "\r\n");  
                }  
            }  
     
     
            public static void StartScheduler(ref MyNameSpace.TaskManager.Scheduler scheduler)  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                try 
                {  
                    if (scheduler == null)  
                    {  
                        scheduler = CreateScheduler();  
                    }  
     
                    if (scheduler != null)  
                    {  
                        scheduler.StartTasks();  
                    }  
     
                }  
                catch (Exception ex)  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:Scheduler:Start:Error: " + ex.Message + "\r\n");  
                }  
            }  
     
     
            public static void StopScheduler(ref MyNameSpace.TaskManager.Scheduler scheduler)  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                try 
                {  
                    if (scheduler != null)  
                    {  
                        scheduler.StopTasks();  
                    }  
     
                }  
                catch (Exception ex)  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:Scheduler:Stop:Error: " + ex.Message + "\r\n");  
                }  
            }  
     
        }  
    }  
     
     
     

    A Task Configuration object
    using System;  
    using System.Xml;  
     
    namespace MyNameSpace  
    {  
        public partial class TaskManager  
        {  
            public class TaskConfiguration  
            {  
                string _taskName = null;  
     
                double _taskInterval = 0;  
                double _taskDelay = 0;  
     
                bool _taskIsRunning = false;  
                bool _taskIsStarted = false;  
                bool _taskIsStopped = true;  
                bool _taskIsEnabled = false;  
                bool _taskIsLastRunSuccessful = false;  
     
                DateTime _taskStartedTime = DateTime.Now;  
                DateTime _taskStoppedTime = DateTime.Now.AddYears(10);  
                DateTime _taskLastRunTime = DateTime.Now;  
     
                System.Type _taskType = null;  
                XmlNode _taskConfigurationNode = null;  
                MyNameSpace.TaskManager.Priority _taskPriority = MyNameSpace.TaskManager.Priority.Low;  
                MyNameSpace.TaskManager.ErrorMode _taskErrorMode = MyNameSpace.TaskManager.ErrorMode.Ignore;  
     
                public string Name  
                {  
                    get 
                    {  
                        return _taskName;  
                    }  
                    set 
                    {  
                        _taskName = value;  
                    }  
                }  
     
                public Type TaskType  
                {  
                    get 
                    {  
                        return _taskType;  
                    }  
                    set 
                    {  
                        _taskType = value;  
                    }  
                }  
     
                public bool IsStarted  
                {  
                    get 
                    {  
                        return _taskIsStarted;  
                    }  
                    set 
                    {  
                        _taskIsStarted = value;  
                    }  
                }  
     
                public bool IsStopped  
                {  
                    get 
                    {  
                        return _taskIsStopped;  
                    }  
                    set 
                    {  
                        _taskIsStopped = value;  
                    }  
                }  
     
                public bool IsRunning  
                {  
                    get 
                    {  
                        return _taskIsRunning;  
                    }  
                    set 
                    {  
                        _taskIsRunning = value;  
                    }  
                }  
     
                public bool IsEnabled  
                {  
                    get 
                    {  
                        return _taskIsEnabled;  
                    }  
                    set 
                    {  
                        _taskIsEnabled = value;  
                    }  
                }  
     
                public bool IsLastRunSuccessful  
                {  
                    get 
                    {  
                        return _taskIsLastRunSuccessful;  
                    }  
                    set 
                    {  
                        _taskIsLastRunSuccessful = value;  
                    }  
                }  
     
                public DateTime LastRunTime  
                {  
                    get 
                    {  
                        return _taskLastRunTime;  
                    }  
                    set 
                    {  
                        _taskLastRunTime = value;  
                    }  
                }  
     
                public DateTime StartedTime  
                {  
                    get 
                    {  
                        return _taskStartedTime;  
                    }  
                    set 
                    {  
                        _taskStartedTime = value;  
                    }  
                }  
     
                public DateTime StoppedTime  
                {  
                    get 
                    {  
                        return _taskStoppedTime;  
                    }  
                    set 
                    {  
                        _taskStoppedTime = value;  
                    }  
                }  
     
                public double Interval  
                {  
                    get 
                    {  
                        return _taskInterval;  
                    }  
                    set 
                    {  
                        _taskInterval = value;  
                    }  
                }  
     
                public double Delay  
                {  
                    get 
                    {  
                        return _taskDelay;  
                    }  
                    set 
                    {  
                        _taskDelay = value;  
                    }  
                }  
     
     
                public XmlNode ConfigurationNode  
                {  
                    get 
                    {  
                        return _taskConfigurationNode;  
                    }  
                    set 
                    {  
                        _taskConfigurationNode = value;  
                    }  
                }  
     
                public Priority Priority  
                {  
                    get 
                    {  
                        return _taskPriority;  
                    }  
                    set 
                    {  
                        _taskPriority = value;  
                    }  
                }  
     
                public ErrorMode ErrorMode  
                {  
                    get 
                    {  
                        return _taskErrorMode;  
                    }  
                    set 
                    {  
                        _taskErrorMode = value;  
                    }  
                }  
     
            }  
     
        }  
    }  
     
     
     

    A Task object
    using System;  
    using System.Threading;  
    using System.Reflection;  
    using System.Timers;  
     
    namespace MyNameSpace  
    {  
        public partial class TaskManager  
        {  
            public class Task  
            {  
                TaskConfiguration _taskConfig = null;  
                System.Timers.Timer _taskTimer = null;  
     
                public Task(double interval)  
                {  
                    this.Config = new TaskConfiguration();  
                    this.Config.Interval = interval;  
                    Initialize();  
                }  
     
                public void Start()  
                {  
                    this.Config.IsStopped = false;  
                    this.StartTask();  
                }  
     
                public void Stop()  
                {  
                    this.Config.IsStopped = true;  
                    this.Config.StoppedTime = DateTime.Now;  
                }  
     
                private void Initialize()  
                {  
                    this.Config.IsStopped = false;  
                    this.Config.IsEnabled = true;  
     
                    _taskTimer = new System.Timers.Timer(this.Config.Interval);  
                    _taskTimer.Elapsed += new ElapsedEventHandler(timer_Elapsed);  
                    _taskTimer.Enabled = true;  
                }  
     
                private void StartTask()  
                {  
                    if (!this.Config.IsStopped)  
                    {  
                        this.Config.IsStarted = false;  
                        Thread thread = new Thread(new ThreadStart(Execute));  
                        thread.Start();  
                        this.Config.IsStarted = true;  
                        this.Config.StartedTime = DateTime.Now;  
                    }  
                }  
     
                private void Execute()  
                {  
                    try 
                    {  
                        this.Config.IsRunning = true;  
     
                        this.Config.LastRunTime = DateTime.Now;  
     
                        MethodInfo method = this.Config.TaskType.GetMethod("Execute");  
                        object[] arguments = { this.Config };  
     
                        object obj = Activator.CreateInstance(this.Config.TaskType);  
     
                        method.Invoke(obj, new object[] { this.Config });  
     
                        this.Config.IsLastRunSuccessful = true;  
                    }  
                    catch 
                    {  
                        this.Config.IsLastRunSuccessful = false;  
     
                        if (this.Config.ErrorMode == MyNameSpace.TaskManager.ErrorMode.Exit)  
                        {  
                            this.Stop();  
                        }  
                    }  
                    finally 
                    {  
                        this.Config.IsRunning = false;  
                    }  
                }  
     
                void timer_Elapsed(object sender, ElapsedEventArgs e)  
                {  
                    if (!this.Config.IsRunning)  
                    {  
                        StartTask();  
                    }  
                }  
     
                public TaskConfiguration Config  
                {  
                    get 
                    {  
                        return _taskConfig;  
                    }  
                    set 
                    {  
                        _taskConfig = value;  
                    }  
                }  
     
            }  
     
        }  

    A WebTask interface - extend as you see fit
    namespace MyNameSpace  
    {  
        public partial class TaskManager  
        {  
            public interface IWebTask  
            {  
                void Execute(TaskConfiguration taskConfiguration);  
            }  
     
        }  
    }  
     

    Which is implemented by a WebTask object
    using System;  
    using System.Data.Common;  
    using System.IO;  
    using System.Xml;  
     
    namespace MyNameSpace.Tasks  
    {  
        public class SomeTask : MyNameSpace.TaskManager.IWebTask  
        {  
            public SomeTask()  
            {  
            }  
     
            public void Execute(MyNameSpace.TaskManager.TaskConfiguration taskConfiguration)  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                try 
                {  
                    SomeAction(taskConfiguration);  
                }  
                catch (Exception ex)  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:NewsFeed:Execute:Error: " + ex.Message + "\r\n");  
     
                    if (taskConfiguration.ErrorMode == MyNameSpace.TaskManager.ErrorMode.Exit)  
                    {  
                        throw;  
                    }  
                }  
            }  
     
     
            private void SomeAction(MyNameSpace.TaskManager.TaskConfiguration taskConfiguration)  
            {  
                string _DebugFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["MyDebugFile"]);  
     
                try 
                {  
                    // Do Stuff Here  
                    // Here we can also check if we need to run, or should just exit.  
                }  
                catch (Exception ex) // All General Errors  
                {  
                    File.AppendAllText(_DebugFile, "Tasks:NewsFeed:InitFeed:Error: " + ex.Message + "\r\n");  
     
                    if (taskConfiguration.ErrorMode == MyNameSpace.TaskManager.ErrorMode.Exit)  
                    {  
                        throw;  
                    }  
                }  
                finally 
                {  
                    // Cleanup as required  
                }  
            }  
        }  
     
  4. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    12 Sep 2017
    29 Jan 2010
    Link to this post
    Hello MB,

    Another option is shown here Implementing scheduled services in Sitefinity 3.x

    All the best,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  5. MB
    MB avatar
    302 posts
    Registered:
    09 Jan 2005
    29 Jan 2010
    Link to this post
    Hi Ivan,

    Yes, however, the problem I was faced with was how to schedule "tasks" (such as periodic updating from an external data-feed) in an environment where you don't have access to the windows task scheduler... such as a commercial hosting environment.

    Although it's a bit clunky, my solution was to just fire up a bunch of worker threads whose job it is to sleep most of the time, but wake up at set intervals, say every 15mins, to invoke the WebTask they are responsible for, and then go back to sleep.

    Having been invoked, the WebTask can check some schedule (in my case it was a database record, but it might be some external file or other information source) to decide if they need to do something or just exit quietly.

    It's not a slick solution, but at least you can schedule things to happen from within the ASP.NET environment.

    NOTE: Obviously, to make it a more generic task scheduler, one improvement could be to extend out the XML config to contain the various settings for actual task scheduling (first instance, last instance, repeat cycle, last run, etc etc) and implement some logic for testing that, in the section responsible for invoking the WebTask, rather than simply invoking the WebTask and leaving it with the job of deciding whether to work or stop... but my needs were simple, and I was too lazy to write that part.
  6. Radoslav Georgiev
    Radoslav Georgiev avatar
    3370 posts
    Registered:
    01 Feb 2016
    29 Jan 2010
    Link to this post
    Hi MB,

    In Sitefinity 4.0 we will use classes that wrap the functionality of the ASP.NET Timer classes. What we will do would be to create a list of all scheduled tasks. Since each task has a timer and this timer will cause an event to be fired we will know when this task is due. Here comes the problem with when the application is sleeping or recycled. This can be handled by providing a flag which will be set when the event of the timer expiring is fired. This means that if the application just goes to sleep or is recycled these flags will not be set. Then in Application start in Global.asax you will go through all scheduled tasks and check the flags and determine if they have to be executed.

     Consider sample code that wraps in functionality of System.Timers:

    Copy Code
    using System;
    using System.Timers;
     
    /// <summary>
    /// Summary description for SampleTimer
    /// </summary>
    public class SampleTimer: IDisposable
    {
        public SampleTimer()
        {
            this.timer = new Timer();
            this.timer.AutoReset = false;
            this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        }
     
        #region Methods
     
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.timer.Stop();
     
            //call webservice logic here
     
            this.timer.Start();
        }
     
        public void Start(TimeSpan interval)
        {
            this.timer.Interval = interval.TotalMilliseconds;
            this.timer.Start();
        }
     
        public void Stop()
        {
            timer.Stop();
        }
     
        #endregion
     
        #region IDisposable Members
     
        public void Dispose()
        {
            if (this.timer != null)
                this.timer.Dispose();
        }
     
        #endregion
     
        #region Private Fields
     
        private Timer timer;
     
        #endregion
    }

    Then you can instantiate this in the Application_Start method in Global.asax like this:

    Copy Code
    void Application_Start(object sender, EventArgs e)
    {
        
        SampleTimer timer = new SampleTimer();
        timer.Start(new TimeSpan(4,0,0));
    }


    You can use this skeleton to implement the flags,etc.

    Sincerely yours,
    Radoslav Georgiev
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  7. MB
    MB avatar
    302 posts
    Registered:
    09 Jan 2005
    29 Jan 2010
    Link to this post
    Yes, that looks pretty much like how I'm doing it.

    My TaskManager.Task class uses the System.Timer to trigger an Elapsed event

                private void Initialize()     
                {     
                    this.Config.IsStopped = false;     
                    this.Config.IsEnabled = true;     
        
                    _taskTimer = new System.Timers.Timer(this.Config.Interval);     
                    _taskTimer.Elapsed += new ElapsedEventHandler(timer_Elapsed);     
                    _taskTimer.Enabled = true;     
                }    

                void timer_Elapsed(object sender, ElapsedEventArgs e)  
                {  
                    if (!this.Config.IsRunning)  
                    {  
                        StartTask();  
                    }  
                }  
     

    at which point the object can invoke the specified class to run... the trick being in the use of reflection.
                private void StartTask()        
                {        
                    if (!this.Config.IsStopped)        
                    {        
                        this.Config.IsStarted = false;        
                        Thread thread = new Thread(new ThreadStart(Execute));        
                        thread.Start();        
                        this.Config.IsStarted = true;        
                        this.Config.StartedTime = DateTime.Now;        
                    }        
                }        
     

    The main issue I found was managing the granularity of the timer, relative to the task schedule. e.g. if the timer for a specific task is triggering every 5mins, then the task might start up to 5mins after the scheduled time... but on the flip side, you don't want the timers to be triggering every millisecond... so you need to assess what is a critical interval for eash task.
  8. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    12 Sep 2017
    29 Jan 2010
    Link to this post
    Hi MB,

    Both approaches are good, but no one of the consider what will happen if your website goes to sleep if no one has access it - your tasks will not be executed if you do not use another code to ping the website  on a certain time. But this will cause timer inconstancy. The only way to hack this is through web service and windows task scheduler. However you can control the correct timing by getting the execution complete time and then set the next execution time - so you run the task at 5:00 pm it completes at 5:02 pm and then the next execution will not be at 5:05pm, it will be at  5:07pm. Basically you have to do the scheduling in the code.

    Sincerely yours,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  9. MB
    MB avatar
    302 posts
    Registered:
    09 Jan 2005
    29 Jan 2010
    Link to this post
    Yes, correct on both points.

    As I said earlier, my example code can be improved exactly that way, by adding such logic that checks a task schedule and adjusts the timer so that it elapses at the correct time... at the time, my needs were simple and I was lazy.

    The problem with the application exiting is a trade-off I guess. In a hosted environment, you don't normally get access to the Windows Task Scheduler, or the ability to install a pinger app... so I used an external service to ping the site on a regular basis.
  10. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    12 Sep 2017
    29 Jan 2010
    Link to this post
    Hi MB,

    I agree with you about the shared hosts, but if you use WebService, you can access it from everywhere. The trigger could be on your home/office computer where you can use the Windows scheduler.

    Best wishes,
    Ivan Dimitrov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  11. Pierre
    Pierre avatar
    433 posts
    Registered:
    16 Feb 2006
    29 Jan 2010
    Link to this post
    Hi,

    Why not use ArtofTest to ping your solution on regular base from internal resource. I have used in another project to extracting and is very well and lighweight or Nuint. You can try Quartz.net using very nice solutions of Crons and Triggest. It can be used in Trusted env with some modifications.I have implemented a complete backup suite for sitefinity :).

    Regards.
Register for webinar
11 posts, 0 answered