1

所以这个应用程序在 Visual Studio 中无缝运行,但是我为遇到错误的程序创建了一个安装程序。我想我已经确定了问题所在。当收到一个 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;
    }
}
4

3 回答 3

0

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

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

如果您等到“服务处理”完成后再发送 200 作为 HTTP 响应,则更容易做到这一点。

于 2012-07-19T22:47:56.803 回答
0

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

于 2012-07-19T20:30:39.837 回答
0

第一个问题是文件一创建FileSystemWatcher就会触发,这通常是在 ASP.NET 进程仍在编写文档的过程中

我希望这会导致 XML 读取异常或拒绝访问异常,但不一定是ThreadAbort异常。ThreadAbort异常通常只有在有人调用时才会发生Thread.Abort,而你永远不应该这样做。

无论如何,您可以通过使用System.IO.FileStream写入文件并告诉 Windows 在写入文件时锁定它来解决此问题。

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

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

如果不了解您的 csFireEyeHandler 应该做什么,我真的无能为力。您是否希望监视服务在您的 ASP.net 请求中间完成对文件的处理?这不太可能发生。

我期望的工作流程是:

         ASP PAGE 监控进程

     > 文件上传 |
     | |
     > 开始写入磁盘 |
     | > 尝试打开文件
     | > 无法读取文件并重试
     > 完成写入磁盘|
     | > 打开文件
     | |
     | > 开始处理文件
     > csFireEyeHandler.Load |
     > csFireEyeHandler.DonJob |
     > 返回 |
                                       |
                                       > 完成流程文件(Report.CreateReport)

如果实际上您需要 fireEyeHandler 来等待后台服务,有几种方法可以做到这一点……但为什么不直接在 fireEyeHandler 中处理文件呢?

于 2012-07-19T21:02:44.143 回答