ASP.net 中基于时间的事件

发布于 2024-07-23 06:39:22 字数 972 浏览 4 评论 0原文

我需要根据时间执行一些事件(发送电子邮件等)。 在托管(中等信任)环境中的 ASP.net 中实现此目的的最佳方法是什么?

例如:每天下午 4:00 发送电子邮件。
例如:登录 15 分钟后发送电子邮件。
例如:在上次状态更改 10 小时后发送电子邮件。

对于某些需求,触发逻辑可能很复杂,因此我需要构建一个灵活的系统来处理此类事件。 我被困在这段代码的核心激活方法上。

以下是我到目前为止的选项...

1) Global.asax 中的计时器
+ 简单
- 不可靠,Web 应用程序可以在 IIS 中卸载,并且事件不会触发。
? 可能使用外部 pinger 服务来保持应用程序处于活动状态(可靠?)

2) Windows 服务执行操作
- 滑动/维护单独的代码。
- 无法安装在托管环境(共享/云托管)

3) Windows Service 调用 Web App(调用 webservice 或运行页面)
+ 网络应用程序中的所有代码
- 无法安装在托管环境中。

4) SQL Server 作业调用 Web 服务(通过 CLR)
? 没看过这个..可能吗? 在托管环境中可靠吗?

5) SQL Service Broker Timer 添加消息以调用 WebService(通过 CLR)
? 没看过这个..可能吗? 在托管环境中可靠吗?

6) Windows 工作流程?
? 不知道..这项技术有什么用吗?

这似乎是一个很常见的问题,有第三方工具可以处理这个问题吗?

I need to perform some events (sending emails, etc.) based on time. What is the best way to accomplish this in ASP.net in a hosted (medium trust) environment?

ex: Send email every day at 4:00pm.
ex: Send email after 15min of login.
ex: Send email after 10 hrs of last change to status.

The triggering logic can be complex on some of the requirements, so I need to build a flexible system to handle these sorts of events. I am stuck on the core activation method for this code.

Here are the options I have so far...

1) Timer in Global.asax
+ Simple
- Is not reliable, the web application can unload in IIS and the event will not fire.
? Possibly use external pinger service to keep app alive (reliable?)

2) Windows Service to perform action
- Slip/Maintain separate code.
- Can not install in hosted environment (shared/cloud hosting)

3) Windows Service to call Web App (calls webservice or runs page)
+ All code in web app
- Can not install in hosted environment.

4) SQL Server Job to call a Webservice (via CLR)
? Haven't looked at this.. possible? reliable in hosted environment?

5) SQL Service Broker Timer to add message to call WebService (via CLR)
? Haven't looked at this.. possible? reliable in hosted environment?

6) Windows Workflow?
? No Idea.. does this technology have anything for this?

This seems like a common enough problem, are there third party tools to handle this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吲‖鸣 2024-07-30 06:39:22

我也遇到了同样的问题,非常同意你的分析。 迄今为止,我最好的解决方案是在我控制的计算机中安装外部调度应用程序; 该应用程序请求实际执行操作的网页。

丑陋但它有效,我已经寻找其他解决方案,相信我!

I have had the same problem, and I agree totally with your analysis. My best solution to date is having an external scheduling application in a computer I control; that application requests the web page that actually does the things.

Ugly but it works, and I have searched for other solutions, believe me!!

污味仙女 2024-07-30 06:39:22

我建议使用 SQL Server 作业。

它具有解决方案中所需的所有时间表,而且非常可靠并且可以使用 C# 代码进行扩展。

I would recommend using SQL Server Jobs.

It has all schedules that are required in your solution, also it's very reliable and can be extended with C# code.

东走西顾 2024-07-30 06:39:22

在 Windows 中设置计划任务的最简单方法是运行简单的控制台应用程序或批处理文件。 http://windows.microsoft.com/en-us/windows7/schedule -a-task

尝试在 IIS 中执行您所说的操作时出现问题。 阅读 Phil Haack 的帖子 在 ASP.NET 中实现重复后台任务的危险

The easiest way to to set up a scheduled task in Windows, running a simple console app or batch file. http://windows.microsoft.com/en-us/windows7/schedule-a-task

Trying to do what yo're talking about in IIS has problems. Read Phil Haack's post on The Dangers of Implementing Recurring Background Tasks In ASP.NET

允世 2024-07-30 06:39:22

您是否看过 quartz 调度程序 它可以进行作业调度。 它是java版本的.Net移植版。 请参阅这篇入门文章 http://geekswithblogs.net/TarunArora/archive/2012/04/10/walkthrough-scheduling-jobs-using-quartz.net-ndash-part-1-what-is.aspx< /a>.

我们还使用 Azure 并使用工作角色来执行计划任务。 您可以在此处查看有关使用 Azure 工作角色构建基本计划任务的文章 http://blog.smarx.com/posts/building-a-task-scheduler-in-windows-azure

过去我们也设置了调用任务的网页并使用了类似的服务https://www.pingdom.com/ 定期调用该页面。

Have you looked at quartz scheduler it does job scheduling. It is a.Net port of the java version. See this getting started article http://geekswithblogs.net/TarunArora/archive/2012/04/10/walkthrough-scheduling-jobs-using-quartz.net-ndash-part-1-what-is.aspx.

We also use Azure and use workers roles for scheduled tasks. You can see this article here on building basic scheduled tasks with Azure work roles http://blog.smarx.com/posts/building-a-task-scheduler-in-windows-azure

In the past we have also set up web page that calls the task and used a service like https://www.pingdom.com/ to call the page on a scheduled basis.

自演自醉 2024-07-30 06:39:22

如果您确实想使用 ASP.NET,那么我会结合使用 SQL Server、WCF 和 ASP.NET 缓存来完成您的计划任务。 您可以轻松修改它以执行更短或更长的时间间隔(例如每小时或每周)。这将仅在选定的时间执行日常任务。

1. 为您的任务设置 SQL 表

列名称数据类型    
  整数 ID 
  名称 varchar(100)  
  上次运行日期时间 
  区间整数  
  运行时间日期时间 
  

2.向表中添加一些数据

<前><代码>1
我的每日电子邮件任务
08/15/08(旧日期)
300(5分钟)
09:00

间隔基本上告诉服务器检查时间的频率。 时间越短,运行时就越准确,但需要更频繁地检查数据库。

3. 如果使用 ORM,请创建类映射

public class Task
{
    public virtual int Id { get; set; }

    public virtual string Name { get; set; }

    public virtual DateTime? LastRun { get; set; }

    public virtual int Interval { get; set; }

    public virtual TimeSpan? RunTime { get; set; }
}

这将使用 Fluent nhibernate。 实体框架也很好用。

4. 创建服务调用以获取/保存任务

public Task[] GetTasks()
{

    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    {
        return session.Query<Task>().ToArray();
    }

}

public bool SaveTask(Task task)
{
    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    using (var trans = session.BeginTransaction())
    {
        session.SaveOrUpdate(task);
        trans.Commit();

        return trans.WasCommitted;
    }
}

这使用 WCF 进行服务调用。 从技术上讲,您不需要 Web 服务,但我认为当您将数据库查询与 ASP.NET 站点分开时,它有助于组织。

5. 在 global.asax 文件中设置调度

protected void Application_Start(object sender, EventArgs e)
{
    var service = new MyService.MyServiceClient();
    var tasks = service.GetTasks();

    foreach (var task in tasks)
    {
        AddTask(task);
    }

    service.Close();
}

上面的函数基本上获取所有任务并将其放入缓存循环中。

private void AddTask(PortalService.Task task)
{
        var onCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
        HttpRuntime.Cache.Insert(task.Name, task, null,
            DateTime.Now.AddSeconds(task.Interval), Cache.NoSlidingExpiration,
            CacheItemPriority.NotRemovable, onCacheRemove);
}

上面的函数将数据库中的每个任务添加到 ASP.NET 运行时缓存中,该缓存根据您在数据库中指定的时间间隔进行循环。

public void CacheItemRemoved(string k, object taskObj, CacheItemRemovedReason r)
{
    var task = (MyService.Task)taskObj;



    //Run the task if it is the next day and greater than or equal to the runtime
    if (task.LastRun.HasValue && task.LastRun.Value.Day != DateTime.Now.Day && task.RunTime.HasValue && task.RunTime.Value.Hours <= DateTime.Now.Hour && task.RunTime.Value.Minutes <= DateTime.Now.Minute))
    {
        RunTask(ref task);
    }


    //Add the task again so that this method gets called again
    AddTask(task);
}

当我们的间隔到期时,将调用上面的函数来运行我们的任务。

6. 创建运行各种任务逻辑的函数

        private void RunTask(ref PortalService.Task task)
        {

            var service = new MyService.MyServiceClient();

            switch (task.Name)
            {
                case "My Daily Email Task":
                    service.SendDailyEmail();
                    break;
                case "Another Daily Task":
                    service.DoAnotherOperation();
                    break;
                case "Yet Another Daily Task":
                    service.DoYetAnotherOperation();
                    break;
            }

            //Update the task to indicate that it ran
            task.LastRun = DateTime.Now;
            service.SaveTask(task);


            service.Close();
        }

总体而言,考虑到可以对其进行的许多改进,该解决方案工作得很好。 如果自上次运行状态存储在数据库中以来将间隔设置得相当低,应用程序池回收不应影响此解决方案。

If you really want to use ASP.NET, then I would use a combination of SQL Server, WCF, and ASP.NET caching to do your scheduled tasks. You can easily modify it to do shorter or longer intervals (e.g. hourly or weekly) This one will only do daily tasks at a selected time.

1. Setup a SQL Table for Your Tasks

Column Name        Data Type   
Id                 int
Name               varchar(100) 
LastRun            datetime
Interval           int 
RunTime            datetime

2. Add Some Data to the Table

1 
My Daily Email Task 
08/15/08 (old date)
300 (5 minutes)
09:00

The interval basically tells the server how often to check the time. The shorter the time, the more accurate the runtime will be with the cost of having to check the database more often.

3. If using an ORM, Create a Class Mapping

public class Task
{
    public virtual int Id { get; set; }

    public virtual string Name { get; set; }

    public virtual DateTime? LastRun { get; set; }

    public virtual int Interval { get; set; }

    public virtual TimeSpan? RunTime { get; set; }
}

This uses fluent nhibernate. Entity Framework works great too.

4. Create Service Calls to Get/Save the Tasks

public Task[] GetTasks()
{

    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    {
        return session.Query<Task>().ToArray();
    }

}

public bool SaveTask(Task task)
{
    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    using (var trans = session.BeginTransaction())
    {
        session.SaveOrUpdate(task);
        trans.Commit();

        return trans.WasCommitted;
    }
}

This uses WCF for the service calls. Technically, you don't need a web service, but I think it helps with organization when you keep your database queries separate from your ASP.NET site.

5. Setup the scheduling in your global.asax file

protected void Application_Start(object sender, EventArgs e)
{
    var service = new MyService.MyServiceClient();
    var tasks = service.GetTasks();

    foreach (var task in tasks)
    {
        AddTask(task);
    }

    service.Close();
}

The above function basically grabs all the tasks and puts it through a caching cycle.

private void AddTask(PortalService.Task task)
{
        var onCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
        HttpRuntime.Cache.Insert(task.Name, task, null,
            DateTime.Now.AddSeconds(task.Interval), Cache.NoSlidingExpiration,
            CacheItemPriority.NotRemovable, onCacheRemove);
}

The above function adds each task in the database to the ASP.NET runtime cache that loops through based on the interval you specified in the database.

public void CacheItemRemoved(string k, object taskObj, CacheItemRemovedReason r)
{
    var task = (MyService.Task)taskObj;



    //Run the task if it is the next day and greater than or equal to the runtime
    if (task.LastRun.HasValue && task.LastRun.Value.Day != DateTime.Now.Day && task.RunTime.HasValue && task.RunTime.Value.Hours <= DateTime.Now.Hour && task.RunTime.Value.Minutes <= DateTime.Now.Minute))
    {
        RunTask(ref task);
    }


    //Add the task again so that this method gets called again
    AddTask(task);
}

When our interval expires the above function is called that runs our task.

6. Create the Function that Runs your Various Tasks' Logic

        private void RunTask(ref PortalService.Task task)
        {

            var service = new MyService.MyServiceClient();

            switch (task.Name)
            {
                case "My Daily Email Task":
                    service.SendDailyEmail();
                    break;
                case "Another Daily Task":
                    service.DoAnotherOperation();
                    break;
                case "Yet Another Daily Task":
                    service.DoYetAnotherOperation();
                    break;
            }

            //Update the task to indicate that it ran
            task.LastRun = DateTime.Now;
            service.SaveTask(task);


            service.Close();
        }

Overall, this solutions works decently, given the many improvements that can be made upon it. App pool recycling shouldn't affect this solution if you have your interval set fairly low since the last run state is stored in the database.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文