我是C#的新手,最近使用.NET 4.0构建了一个小型webapp。这个应用程序有两个部分:一个设计为永久运行,并将不断从Web上的给定资源获取数据。另一个根据请求访问该数据以进行分析。我正在努力完成第一部分。
我最初的方法是设置一个Timer
对象来执行一个提取操作(无论那个操作在这里真的没什么关系),比如5分钟。我会在Application_Start
上定义该计时器并让它在此之后生效。
但是,我最近意识到应用程序是根据用户请求创建/销毁的(根据我的观察,它们似乎在一段时间不活动后被破坏)。因此,我的后台活动将停止/恢复我的控制,我希望它能够连续运行,绝对没有中断。
所以这是我的问题:是否可以在网络应用中实现?或者我绝对需要一个单独的Windows服务来处理这类事情?
提前感谢您的宝贵帮助!
纪尧姆
答案 0 :(得分:2)
虽然在网络应用上执行此操作并不理想.. 可以实现,因为该网站始终处于运行状态。
以下是一个示例:我在global.asax中创建了一个带有过期的Cache项。当它到期时,会触发一个事件。您可以在OnRemove()事件中获取数据或其他任何内容。
然后你可以设置一个页面调用(最好是一个非常小的页面),它将触发Application_BeginRequest中的代码,该代码会将Cache项目过期加回。
global.asax中:
private const string VendorNotificationCacheKey = "VendorNotification";
private const int IntervalInMinutes = 60; //Expires after X minutes & runs tasks
protected void Application_Start(object sender, EventArgs e)
{
//Set value in cache with expiration time
CacheItemRemovedCallback callback = OnRemove;
Context.Cache.Add(VendorNotificationCacheKey, DateTime.Now, null, DateTime.Now.AddMinutes(IntervalInMinutes), TimeSpan.Zero,
CacheItemPriority.Normal, callback);
}
private void OnRemove(string key, object value, CacheItemRemovedReason reason)
{
SendVendorNotification();
//Need Access to HTTPContext so cache can be re-added, so let's call a page. Application_BeginRequest will re-add the cache.
var siteUrl = ConfigurationManager.AppSettings.Get("SiteUrl");
var client = new WebClient();
client.DownloadData(siteUrl + "default.aspx");
client.Dispose();
}
private void SendVendorNotification()
{
//Do Tasks here
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
//Re-add if it doesn't exist
if (HttpContext.Current.Request.Url.ToString().ToLower().Contains("default.aspx") &&
HttpContext.Current.Cache[VendorNotificationCacheKey] == null)
{
//ReAdd
CacheItemRemovedCallback callback = OnRemove;
Context.Cache.Add(VendorNotificationCacheKey, DateTime.Now, null, DateTime.Now.AddMinutes(IntervalInMinutes), TimeSpan.Zero,
CacheItemPriority.Normal, callback);
}
}
如果您的预定任务很快,这很有效。 如果这是一个漫长的过程......你肯定需要将它从你的网络应用程序中删除。
只要第一个请求启动了应用程序......即使网站上没有访问者,也会每60分钟继续点击一次。
答案 1 :(得分:2)
我建议把它放在Windows服务中。你避免了上面提到的所有箍,最重要的是IIS重启。 Windows服务还具有以下优点:
答案 2 :(得分:1)
使用构造函数创建静态类,创建计时器事件。 不过像史蒂夫·斯洛卡(Steve Sloka)所提到的那样,IIS有一个超时时间你必须操纵以保持网站运行。
using System.Runtime.Remoting.Messaging;
public static class Variables
{
static Variables()
{
m_wClass = new WorkerClass();
// creates and registers an event timer
m_flushTimer = new System.Timers.Timer(1000);
m_flushTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnFlushTimer);
m_flushTimer.Start();
}
private static void OnFlushTimer(object o, System.Timers.ElapsedEventArgs args)
{
// determine the frequency of your update
if (System.DateTime.Now - m_timer1LastUpdateTime > new System.TimeSpan(0,1,0))
{
// call your class to do the update
m_wClass.DoMyThing();
m_timer1LastUpdateTime = System.DateTime.Now;
}
}
private static readonly System.Timers.Timer m_flushTimer;
private static System.DateTime m_timer1LastUpdateTime = System.DateTime.MinValue;
private static readonly WorkerClass m_wClass;
}
public class WorkerClass
{
public delegate WorkerClass MyDelegate();
public void DoMyThing()
{
m_test = "Hi";
m_test2 = "Bye";
//create async call to do the work
MyDelegate myDel = new MyDelegate(Execute);
AsyncCallback cb = new AsyncCallback(CommandCallBack);
IAsyncResult ar = myDel.BeginInvoke(cb, null);
}
private WorkerClass Execute()
{
//do my stuff in an async call
m_test2 = "Later";
return this;
}
public void CommandCallBack(IAsyncResult ar)
{
// this is called when your task is complete
AsyncResult asyncResult = (AsyncResult)ar;
MyDelegate myDel = (MyDelegate)asyncResult.AsyncDelegate;
WorkerClass command = myDel.EndInvoke(ar);
// command is a reference to the original class that envoked the async call
// m_test will equal "Hi"
// m_test2 will equal "Later";
}
private string m_test;
private string m_test2;
}
答案 3 :(得分:0)
我认为您可以使用BackgroundWorker来实现它,但我建议您去寻求服务。
答案 4 :(得分:0)
只要IIS中的工作进程正常运行,您的应用程序上下文就会存在。在IIS中,工作进程何时回收会有一些默认超时(例如,空闲分钟数(20)或定期间隔(1740)。
也就是说,如果您在IIS中调整这些设置,您应该可以使用这些请求,但是,使用服务的其他答案也可以正常工作,这只是您想要实现的方式。
答案 5 :(得分:0)
我最近制作了一个文件上传功能,用于将Access文件上传到数据库(不是最好的方法,只是对长期问题的临时修复)。
我通过创建一个贯穿ProcessAccess
函数的后台线程来解决它,并在完成时被删除。
除非IIS有一个设置,它会在一段时间内杀死一个线程而不管是不活动的,你应该能够创建一个调用永不结束的函数的线程。不要使用递归,因为开放函数的数量最终会在你面前爆炸,但只有for(;;)循环5,000,000次,所以它会保持忙碌:)
答案 6 :(得分:0)
IIS 7.5的应用程序初始化模块正是这种类型的init工作。有关该模块的更多详细信息,请访问Application Initialization Module