ASP.. NET实体框架和FileWatcher事件



我有一个关于我们ASP中的EF的问题。. NET Web应用程序。对于我们的特定用例,我们必须监听一个目录以获取添加的XML文件。使用System.IO.FileSystemWatcher可以正确工作。所有内容都包装在一个类中,如下所示:

namespace Server.Data
{
using System;
using System.IO;
using System.Threading;
using Server.Events;
public class FileWatcher
{
/// <summary>
///     The watcher which listens to the directory. This variable has to be a property to ensure, that it is not destroyed
///     after its local lifecycle.
/// </summary>
private readonly FileSystemWatcher watcher;
public FileWatcher(string directory)
{
this.watcher = new FileSystemWatcher
{
Path = directory,
NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime
     | NotifyFilters.FileName | NotifyFilters.LastAccess
     | NotifyFilters.LastWrite | NotifyFilters.Size
     | NotifyFilters.Security,
Filter = "*.xml",
};
this.watcher.Created += this.OnCreate;
this.watcher.EnableRaisingEvents = true;
}
/// <summary>
///     The event, which is fired when a new XML file is found.
/// </summary>
public event EventHandler<NewFileEventArgs> NewXmlFile;
/// <summary>
///     The function which gets called by the system watcher as soon as a new XML file is found.
///     Fetches the file and waits until it is completely loaded. The problem is, that the file watcher immediately
///     triggers, as soon as the file is created. Big files therefore might run into some issues without waiting.
/// </summary>
private void OnCreate(object source, FileSystemEventArgs args)
{
var autoEvent = new AutoResetEvent(false);
var fileChecker = new FileChecker(args.FullPath);
new Timer(fileChecker.CheckStatus, autoEvent, 1000, 500);
autoEvent.WaitOne();
this.NewXmlFile?.Invoke(this, new NewFileEventArgs(args.FullPath));
}
}
}

在订阅事件NewXmlFile之后,应该将文件传递给自定义XML数据提取器,该提取器基本上可以获取数据并在EF的帮助下将数据插入到数据库中。(我们已经有了数据库初始化器,它在程序启动时做同样的事情。但是在这种情况下,只要在上述目录中收到一个新文件,它就应该自动再次运行这个完全相同的进程。

在我的Program.cs中,我像这样订阅NewXmlFile事件。

fileWatcher = new FileWatcher("C:/myPath");
fileWatcher.NewXmlFile += OnNewFile;

其中Program::OnNewFile看起来像这样:

private static void OnNewFile(object sender, NewFileEventArgs args)
{
//INJECT DEPENDENCIES HERE
var xmlDataImport = new XmlDataImport();
var success = xmlDataImport.Import(args.FilePath).Result;

if (success)
{
File.Delete(args.FilePath);
}
}

如评论中所示,我需要在xmldataiport类中传递我的依赖项。不管怎样,我不知道该怎么做。因为我总是得到异常Cannot access a disposed object. Object name: 'IMyService'.

我尝试过的事情:

  • 注入IServiceProvider到我的Program.cs中,当我创建Filewatchernew FileWatcher(serviceProvider, path)时,将其存储在私有属性中,并在触发NewXmlFile事件时将其作为自定义EventArgs属性传递下去。然后,我从传入的EventArgs中获取IServiceProvider,并在Program::OnNewFile方法中将它们手动注入XmlDataImport(args.provider)的构造函数中。
  • 使IServiceProviderProgram.cs内为静态,并在Program::OnNewFile方法中手动注入XmlDataImport(provider)

无论如何,对象已经被处理是完全有意义的。但是在文档中,我没有找到让它工作的方法。也许有人遇到了类似的问题,可以提供帮助。谢谢!

我找到了解决方案,感谢@King King。对于任何有类似问题的人:

您必须创建一个新的hostdservice并将其添加到您的Startup.cs

this.services.AddHostedService<FileImportTask>();
之后,您的托管服务可以在其构造函数中导入IServiceProvider。在我的特定用例中,我可以直接绑定到我在StartAsync方法中触发的事件(确保您也取消订阅它)。然后,在事件方法中,我可以创建一个新的作用域,从中我可以访问所有的服务。
public class FileImportTask: IHostedService, IDisposable
{
private readonly IConfiguration configuration;
private readonly ILogger<FileImportTask> logger;
private readonly IServiceProvider serviceProvider;
private FileWatcher fileWatcher;
public FileImportTask(ILogger<FileImportTask> logger, IConfiguration configuration, IServiceProvider serviceProvider)
{
this.logger = logger;
this.configuration = configuration;
this.serviceProvider = serviceProvider;
}
public void Dispose()
{
}
public Task StartAsync(CancellationToken stoppingToken)
{
var path = this.configuration.GetValue<string>("AppSettings:XmlPath");
Directory.CreateDirectory(path);
this.fileWatcher = new FileWatcher(path);
this.fileWatcher.NewXmlFile += this.OnNewFile;
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken stoppingToken)
{
this.fileWatcher.NewXmlFile -= this.OnNewFile;
return Task.CompletedTask;
}
private void OnNewFile(object sender, NewFileEventArgs args)
{
using (var scope = this.serviceProvider.CreateScope())
{
var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
//USE SERVICE HERE!
}
}
}

最新更新