System.Io.Directory::GetFiles()从AX 2009轮询,每10秒才看到新文件

时间:2017-02-16 16:18:58

标签: axapta polling dynamics-ax-2009

我在AX 2009中编写代码,每1秒轮询一次网络驱动器上的目录,等待来自另一个系统的响应文件。我注意到使用文件浏览器窗口,我可以看到文件出现,但我的代码没有看到并处理文件几秒钟 - 文件出现后最多9秒(和9个民意调查)!

AX代码使用System.IO.Directory::GetFiles()调用ClrInterop

interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
files = System.IO.Directory::GetFiles(#POLLDIR,'*.csv');
// etc...
CodeAccessPermission::revertAssert();

经过多次实验,它出现在我的程序生命周期中第一次,我打电话给::GetFiles(),它开始一个10秒钟的名义“滴答时钟”。只有每隔10秒钟才能找到可能出现的新文件,尽管他们仍会报告自第一次调用::GetFiles()以来在早期10秒“滴答”中找到的文件。

如果,当我启动程序时,文件不存在,则所有其他调用::GetFiles(),第一次调用后1秒,2秒后等,最多9秒后,只需看不到文件,即使它可能在第一次通话后0.5秒就坐在那里!

然后,可靠且可重复地,在第一次呼叫之后的呼叫10s将找到该文件。然后,从11s到19s的任何呼叫都不会看到可能出现的任何新文件,但是在第一次呼叫后20s的呼叫将可靠地看到任何新文件。等等,每10秒钟一次。

进一步调查显示,如果轮询目录位于AX AOS计算机上,则不会发生这种情况,并且在文件出现在目录中后,会立即找到该文件(如预期的那样)。

但这个10s的数字是可靠且可重复的,无论我使用什么网络驱动器进行轮询,无论它在哪个服务器上。

我们的网络肯定没有10秒的延迟来查看文件;正如我所说,轮询目录上的文件浏览器窗口会立即看到该文件。

发生了什么事?

3 个答案:

答案 0 :(得分:2)

听起来您的问题是由于SMB缓存 - 来自this technet page

  

名称,类型和ID
  目录缓存[DWORD] DirectoryCacheLifetime

     

注册表项缓存设置由   HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters

     

这是由最近执行的目录枚举的缓存   客户。客户端应用程序作为后续枚举请求   以及可以满足目录中文件的元数据查询   从缓存。客户端还使用目录高速缓存来确定   目录中是否存在文件并使用该文件   防止客户反复尝试打开的信息   已知服务器上不存在的文件。这个缓存很可能   影响在多台计算机上运行的分布式应用程   访问服务器上的一组文件 - 应用程序使用的文件   带外机制相互发出信号   修改/添加/删除服务器上的文件。

简而言之,尝试设置注册表项

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters\DirectoryCacheLifetime

0

答案 1 :(得分:2)

感谢@Jan B. Kjeldsen,我能够使用FileSystemWatcher解决我的问题。这是我在X ++中的实现:

class SelTestThreadDirPolling
{
}

public server static Container SetStaticFileWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
    InteropPermission interopPerm;
    System.IO.FileSystemWatcher fw;
    System.IO.WatcherChangeTypes watcherChangeType;
    System.IO.WaitForChangedResult res;
    Container cont;
    str fileName;
    str oldFileName;
    str changeType;
    ;

    interopPerm = new InteropPermission(InteropKind::ClrInterop);
    interopPerm.assert();
    fw = new System.IO.FileSystemWatcher();
    fw.set_Path(_dirPath);
    fw.set_IncludeSubdirectories(false);
    fw.set_Filter(_filenamePattern);

    watcherChangeType = ClrInterop::parseClrEnum('System.IO.WatcherChangeTypes', 'Created');
    res = fw.WaitForChanged(watcherChangeType,_timeoutMs);
    if (res.get_TimedOut()) return conNull();

    fileName = res.get_Name();
    //ChangeTypeName can be: Created, Deleted, Renamed and Changed
    changeType = System.Enum::GetName(watcherChangeType.GetType(), res.get_ChangeType());

    fw.Dispose();
    CodeAccessPermission::revertAssert();

    if (changeType == 'Renamed') oldFileName = res.get_OldName();

    cont += fileName;
    cont += changeType;
    cont += oldFileName;
    return cont;
}

void waitFileSystemWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
    container cResult;
    str filename,changeType,oldFilename;
    ;

    cResult=SelTestThreadDirPolling::SetStaticFileWatcher(_dirPath,_filenamePattern,_timeoutMs);
    if (cResult)
    {
        [filename,changeType,oldFilename]=cResult;
        info(strfmt("filename=%1, changeType=%2, oldFilename=%3",filename,changeType,oldFilename));
    }
    else
    {
        info("TIMED OUT");
    }
}

void run()
{;
    this.waitFileSystemWatcher(@'\\myserver\mydir','filepattern*.csv',10000);
}

我应该承认以下内容构成了我的X ++实现的基础:

https://blogs.msdn.microsoft.com/floditt/2008/09/01/how-to-implement-filesystemwatcher-with-x/

答案 2 :(得分:1)

我猜DAXaholic的答案是正确的,但您可以尝试其他解决方案,例如EnumerateFiles

在您的情况下,我宁愿等待文件而不是轮询文件。 使用FileSystemWatcher,从文件创建到您的进程唤醒将会有最小的延迟。使用起来比较棘手,但避免轮询是好事。我从未在网络上使用它。