2012-07-19 52 views
1

因此,此应用程序在Visual Studio中无缝运行,但我为遇到错误的程序创建了一个安装程序。我想我已经确定了问题所在。当收到一个POST时,它会处理一个单独的分离进程,最终会从网页处理/关闭中取消。处理POST后线程中止

程序流程是这样

  • POST接收context.Request.HttpMethod == "POST"
  • 相关XML信息提取并写入磁盘,
  • csfireEyeHandler.DonJobOnLastIp()
  • 在后台运行的监视器上的文件拾取创建事件`void OnChanged'并开始基于XML文档运行服务
  • FileAdded - >readerRef.ReadInServices(e.FullPath, false)

问题是POST处理后,它导致服务中止与ThreadAbortException。如果在服务完成后handler.ProcessRequest(context)之后放置了延迟,我推测因为该页面仍然打开。我无法弄清楚如何正确处理这种情况,它非常难以调试,因为我无法在VS中发生错误。

public partial class fireEye : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     HttpContext context = Context; 
     fireEyeHandler handler = new fireEyeHandler(); 
     handler.ProcessRequest(context);   
    } 
} 

public class fireEyeHandler : IHttpHandler 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     if (context.Request.HttpMethod == "POST") 
     { 
      var extension = context.Request.Url.AbsolutePath.Split('/')[2].ToLower(); 

      var stream = context.Request.InputStream; 
      var buffer = new byte[stream.Length]; 
      stream.Read(buffer, 0, buffer.Length); 
      var xml = Encoding.UTF8.GetString(buffer); 

      FileManage.WriteToFile(xml, @"C:\ECC_output\fireEye.xml"); 
      var csfireEyeHandler = new FireEyeService { config = extension + ".config" }; 

      csfireEyeHandler.Load(); 
      csfireEyeHandler.DonJobOnLastIp(); 

      context.Response.StatusCode = 202;    
     } 
    } 

    public bool IsReusable 
    { 
     get { return false; } 
    } 
} 

public class Monitor 
{ 
    bool monitorIsActive; 
    readonly XmlRead readerRef; // Reference to the xml reader 
    readonly FileSystemWatcher watch; 
    public bool monitorRunning; 

    public Monitor(XmlRead reader) 
    { 
     watch = new FileSystemWatcher(); 
     readerRef = reader; 

     try 
     { 
      watch.Path = @"C:\ECC_temp"; //directory to monitor 
     } 
     catch (ArgumentException ex) 
     { 
      Report.LogLine (ex.Message); 
      return; 
     } 

     watch.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; 

     watch.Filter = "*.xml"; 
     monitorIsActive = true; 

     watch.Created += OnChanged; 
     watch.Deleted += OnChanged; 
     watch.Renamed += OnRenamed; 

     watch.EnableRaisingEvents = true; 
    } 

    /// <summary> 
    /// Toggles on/off if a directory is being monitored 
    /// </summary> 
    public void ToggleMonitor() 
    { 
     monitorIsActive = !monitorIsActive; 
     var monitorState = monitorIsActive ? "on" : "false"; 

     Report.LogLine ("Monitor is " + monitorState); 
    } 

    /// <summary> 
    /// File has been added to the directory 
    /// </summary> 
    public bool FileAdded(FileSystemEventArgs e, XmlDocument xmlDocument) 
    { 
     try 
     { 
      var date = string.Format ("<br>\r\n**********************Report {0:yyyy MM-dd hh:mm tt}**********************", DateTime.Now); 
      Report.LogLine(date); 

      readerRef.Validate(e.FullPath, false); 
      readerRef.ReadInServices(e.FullPath, false); 

      Report.CreateReport(); 
     } 
     catch (Exception exception) 
     { 
      Report.LogLine(exception.Message + " id:6"); 
      Report.CreateReport(); 
      return true; 
     } 
     return true; 
    } 

    /// <summary> 
    /// When a file is added, renamed or deleted, OnChanged is called and the appropriate action is taken 
    /// </summary> 
    private void OnChanged(object source, FileSystemEventArgs e) 
    { 
     monitorRunning = true; 
     while (true) 
     { 
      if (e.ChangeType == WatcherChangeTypes.Created || e.ChangeType == WatcherChangeTypes.Renamed) 
      { 
       var xmlDocument = new XmlDocument(); 
       try 
       {       
        xmlDocument.Load(e.FullPath); 
       } 
       catch (IOException) 
       { 
        Thread.Sleep(100); 
       } 

       if (FileAdded(e, xmlDocument)) 
       { 
        break; 
       } 
      } 

     } 
     monitorRunning = false; 
    } 
} 

回答

0

除非你的应用程序知道这个监控,并且知道如何检测其当前正在处理的文件更改事件,而不是从后返回,没有什么可以做。我建议不要将Web应用程序耦合到此监视器(您没有解释它的用途)。我会建议将它从Web应用程序中提取出来并放入某种Windows服务中。或者,更详细地解释为什么此监视器位于Web应用程序中。

+0

Web应用程序对监视器一无所知。监视器从正在放入目录的xml文件启动服务。我认为,既然他们没有提到对方,也不能让另一方终止,但事实并非如此。我将尝试将FireEye处理程序移到MVC控制器,以便它不在处理的网页中。 – flaVius 2012-07-19 21:50:23

+0

我不认为移动它会让你受益良多。我相信你在这里有一个基本的设计问题。你有一些忙于尝试读取文件的背景中,而另一些忙于尝试读取或写入这些相同的文件。要么你必须让你的文件观察器处理程序退后一步,让其他代码完成,或者通过某种方式发送创建已发生且所有写入已完成的代码。 – 2012-07-20 00:30:00

+0

我真的不认为文件系统监视器是正确的解决方案;您可以在创建通知后添加暂停;但无论你选择什么时候暂停,总会是错误的。这一切都在同一个过程中,为什么不只是创建通知代码的代码来记录或执行报告。 – 2012-07-20 00:30:53

0

的第一个问题是,FileSystemWatcher能够尽快的文件是创建火,而这往往是,而ASP.NET进程仍然在写文档的中间。

我期望这会导致XML读取异常,或拒绝访问异常,但不一定是ThreadAbort异常。 ThreadAbort例外情况通常只发生在有人呼叫Thread.Abort时,您永远不应该这样做。

无论如何,您可以通过使用System.IO.FileStream来编写文件并告诉windows在写入时锁定它。

  • 当您打开文件编写它时,指定FileShare.None。这将防止监视器尝试读取文件,直到ASP.net进程完成写入。

  • 在您的显示器中,打开文件时添加一个带有小睡眠的重试循环。您应该反复获取访问被拒绝的异常(我认为这将是一个IOException),直到文件准备好供您阅读。

如果不理解你的csFireEyeHandler事情应该做什么,我真的不能帮上什么忙。您是否期望监视器服务在您的ASP.net请求中间处理文件?这不太可能发生。

什么我期望的工作流程是:

 
     ASP PAGE      Monitor Process 

    > File Uploaded     | 
    |         | 
    > Begin Write to disk    | 
    |         > Try open file 
    |         > fail to read file and retry 
    > Finish write to disk   | 
    |         > open file 
    |         | 
    |         > Begin process file 
    > csFireEyeHandler.Load   | 
    > csFireEyeHandler.DonJob   | 
    > RETURN       | 
             | 
             > Finish process file (Report.CreateReport) 

事实上,如果你需要的fireEyeHandler等待后台服务,有几种方法可以做到这一点......但为什么不干脆处理fireEyeHandler中的文件?

+0

是的,那是我之前处理的一个错误,我确实发现IOException并且让线程进入睡眠状态。 'readerRef.ReadInServices'上的'readerRef.Validate'后面发生线程流产。 validate方法根据模式验证创建的XMl,并运行XML中描述的相应服务。但它与服务无关。 – flaVius 2012-07-19 21:45:17

+0

好的。在某些时候,某人必须调用'Thread.Abort',或者显式抛出一个'ThreadAbortException';你需要弄清楚这是谁,为什么他们这样做......我会开始搜索你的代码以调用Thread.Abort ...如果没有,我会设置一些代码来创建一个内存转储过程,然后您可以将其发送到您的调试PC并找出发生了什么。 – 2012-07-19 23:21:40

+0

Thread.Abort很可能在post命令结束后由ASP.NET子系统调用 - 通常是在回收应用程序时。 – 2012-07-20 00:26:50

0

根据我对您问题的解释,您不希望等到文件监视器事件发生之后才将响应发送给客户端。您想立即发送200并在后台处理。

这是ASP.NET中的反模式,因为当所有正在运行的HTTP请求都退出时,运行时并不能保证工作进程保持活动状态。从这个意义上讲,ASP.NET符合规范:它可以随时中止自定义线程。

如果您在发送200作为HTTP响应之前一直等到“服务处理”完成,那么获得此权利会更容易。