处理POST后线程中止

时间:2012-07-19 18:06:24

标签: c# asp.net multithreading

因此,此应用程序在Visual Studio中无缝运行,但我已为遇到错误的程序创建了一个安装程序。我想我已经确定了问题所在。当收到POST时,它会被处理,从而启动一个单独的解耦过程,该过程最终会从网页处理/关闭中止。

程序流程是这样的

  • POST收到context.Request.HttpMethod == "POST"
  • 提取并写入磁盘的相关xml信息,
  • csfireEyeHandler.DonJobOnLastIp()
  • 在后台运行的监视器选择文件创建事件`void OnChanged'并开始基于XML doc运行服务
  • 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;
    }
}

3 个答案:

答案 0 :(得分:0)

除非您的应用程序知道此Monitor并且知道如何检测其当前正在处理文件更改事件而不是从帖子返回,否则您无能为力。我建议不要将Web应用程序耦合到此Monitor(您没有解释其用途)。我建议将其从Web应用程序中取出并将其放入某种Windows服务中。或者,更详细地解释为什么此监视器位于Web应用程序中。

答案 1 :(得分:0)

第一个问题是,FileSystemWatcher可以在创建文件时立即触发,这通常可以是,而ASP.NET进程仍处于写入过程中文件

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

无论如何,您可以通过使用System.IO.FileStream来编写文件并告诉窗口在写入文件时将其锁定来解决这个问题。

  • 当您打开文件进行编写时,请指定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中处理文件?

答案 2 :(得分:0)

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

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

如果您在发送200作为HTTP响应之前等待“服务处理”完成,那么更容易做到这一点。