如何在 EF(DB 优先)实体上实施计划任务?
How to implement scheduled task on EF (DB first) entities?
我是 Asp.net
的新手,并且有一个使用 Entity Framework
的网站。每天晚上,我都需要对我的 Person
个实体做一些工作。
因此我安装了 Quartz.Net
并尝试在 Global.asax
中以这种方式使用它:
<%@ Application Language="C#" %>
<%@ Import Namespace="Quartz" %>
<%@ Import Namespace="Quartz.Impl" %>
<script runat="server">
private IScheduler Scheduler { get; set; }
void Application_Start(object sender, EventArgs e)
{
Scheduler = StdSchedulerFactory.GetDefaultScheduler();
Scheduler.Start();
IJobDetail dailyReset = JobBuilder.Create<ApplicationJobs.DailyReset>()
.WithIdentity("dailyReset", "group1")
.Build();
ITrigger dailyResetTrigger = TriggerBuilder.Create()
.WithIdentity("dailyResetTrigger", "group1")
.StartAt(DateBuilder.DateOf(3, 0, 0))
.WithSimpleSchedule(x => x
.WithIntervalInHours(24)
.RepeatForever())
.Build()
Scheduler.ScheduleJob(dailyReset, dailyResetTrigger);
}
</script>
然后我的 ApplicationJobs class :
public class ApplicationJobs : System.Web.HttpApplication
{
public class DailyReset : IJob
{
public void Execute(IJobExecutionContext context)
{
using (var uow = new UnitOfWork())
{
foreach (Person person in uof.Context.Persons)
{
//do something
}
}
}
}
}
最后是工作单元:
public class UnitOfWork : IDisposable
{
private const string _httpContextKey = "_unitOfWork";
private MyEntities _dbContext;
public static UnitOfWork Current
{
get { return (UnitOfWork)HttpContext.Current.Items[_httpContextKey]; }
}
public UnitOfWork()
{
HttpContext.Current.Items[_httpContextKey] = this;
}
public MyEntities Context
{
get
{
if (_dbContext == null)
_dbContext = new MyEntities();
return _dbContext;
}
}
}
但是 using (var uow = new UnitOfWork())
不工作,因为 uow 的构造函数中有 HttpContext.Current.Items[_httpContextKey] = this;
;我读到 HttpContext.Current
在 Application_Start
中不可用。
在阅读相关帖子中,特别是 this one but I don't really understand if I do need to create something like UnitOfWorkScope
described here,或者是否有办法像现在这样做到这一点。
那么有没有干净安全的方法来安排一些使用我的 UnitOfWork
来更新实体的任务?
非常感谢。
你的问题来自这样一个事实,当你的工作 运行 时,它会被石英调度程序调用,而不是来自 http 请求(即使工作在 ASP 网站中).
因此 HttpContext.Current 很可能为空。
请记住,在使用 Quartz 时,您应该将其视为与您的网站完全平行的进程,几乎就像一项单独的服务。
如果你需要将"argument"传递给你的job,你可以使用job数据映射
JobDataMap dataMap = jobContext.JobDetail.JobDataMap;
(有关详细信息,请参阅此处:http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-jobs.html)
如果您需要访问您的工作,只需在创建工作密钥时使用相同的密钥和组(您在 WithIdentity
中使用的密钥和组
请注意,建议实体上下文仅在您需要它的操作时处于活动状态,因此您可能只需在作业开始时实例化一个新上下文并在结束时将其处置。
问题是您没有在网络请求中执行作业。例如,Web 请求开始,您检查未完成的工作,如果需要则进行工作,请求结束。没有 Web 请求,您就没有上下文 - 因为上下文在 Web 请求的生命周期内存在,并且可以通过请求线程访问。
您将遇到的另一个问题是应用程序池,使用默认设置,如果没有 activity 可能会结束。所以你需要一种让它存活的方法。
另一种方法是使用诸如 win task scheduler 之类的工具访问网站以开始工作。
我是 Asp.net
的新手,并且有一个使用 Entity Framework
的网站。每天晚上,我都需要对我的 Person
个实体做一些工作。
因此我安装了 Quartz.Net
并尝试在 Global.asax
中以这种方式使用它:
<%@ Application Language="C#" %>
<%@ Import Namespace="Quartz" %>
<%@ Import Namespace="Quartz.Impl" %>
<script runat="server">
private IScheduler Scheduler { get; set; }
void Application_Start(object sender, EventArgs e)
{
Scheduler = StdSchedulerFactory.GetDefaultScheduler();
Scheduler.Start();
IJobDetail dailyReset = JobBuilder.Create<ApplicationJobs.DailyReset>()
.WithIdentity("dailyReset", "group1")
.Build();
ITrigger dailyResetTrigger = TriggerBuilder.Create()
.WithIdentity("dailyResetTrigger", "group1")
.StartAt(DateBuilder.DateOf(3, 0, 0))
.WithSimpleSchedule(x => x
.WithIntervalInHours(24)
.RepeatForever())
.Build()
Scheduler.ScheduleJob(dailyReset, dailyResetTrigger);
}
</script>
然后我的 ApplicationJobs class :
public class ApplicationJobs : System.Web.HttpApplication
{
public class DailyReset : IJob
{
public void Execute(IJobExecutionContext context)
{
using (var uow = new UnitOfWork())
{
foreach (Person person in uof.Context.Persons)
{
//do something
}
}
}
}
}
最后是工作单元:
public class UnitOfWork : IDisposable
{
private const string _httpContextKey = "_unitOfWork";
private MyEntities _dbContext;
public static UnitOfWork Current
{
get { return (UnitOfWork)HttpContext.Current.Items[_httpContextKey]; }
}
public UnitOfWork()
{
HttpContext.Current.Items[_httpContextKey] = this;
}
public MyEntities Context
{
get
{
if (_dbContext == null)
_dbContext = new MyEntities();
return _dbContext;
}
}
}
但是 using (var uow = new UnitOfWork())
不工作,因为 uow 的构造函数中有 HttpContext.Current.Items[_httpContextKey] = this;
;我读到 HttpContext.Current
在 Application_Start
中不可用。
在阅读相关帖子中,特别是 this one but I don't really understand if I do need to create something like UnitOfWorkScope
described here,或者是否有办法像现在这样做到这一点。
那么有没有干净安全的方法来安排一些使用我的 UnitOfWork
来更新实体的任务?
非常感谢。
你的问题来自这样一个事实,当你的工作 运行 时,它会被石英调度程序调用,而不是来自 http 请求(即使工作在 ASP 网站中).
因此 HttpContext.Current 很可能为空。
请记住,在使用 Quartz 时,您应该将其视为与您的网站完全平行的进程,几乎就像一项单独的服务。
如果你需要将"argument"传递给你的job,你可以使用job数据映射
JobDataMap dataMap = jobContext.JobDetail.JobDataMap;
(有关详细信息,请参阅此处:http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-jobs.html)
如果您需要访问您的工作,只需在创建工作密钥时使用相同的密钥和组(您在 WithIdentity
中使用的密钥和组请注意,建议实体上下文仅在您需要它的操作时处于活动状态,因此您可能只需在作业开始时实例化一个新上下文并在结束时将其处置。
问题是您没有在网络请求中执行作业。例如,Web 请求开始,您检查未完成的工作,如果需要则进行工作,请求结束。没有 Web 请求,您就没有上下文 - 因为上下文在 Web 请求的生命周期内存在,并且可以通过请求线程访问。
您将遇到的另一个问题是应用程序池,使用默认设置,如果没有 activity 可能会结束。所以你需要一种让它存活的方法。
另一种方法是使用诸如 win task scheduler 之类的工具访问网站以开始工作。