[英]FileSystemWatcher does not work on files created from windows service
我正在从在LocalSystem帐户下运行的Windows服务创建文件。 我有一个Windows应用程序,该应用程序监视在其中创建文件的指定文件夹。 我正在使用FileSystemWatcher,但不会触发。 Windows资源管理器中的文件图标是一个挂锁图标。 如何从Windows服务创建此文件,以便可以从Windows用户帐户访问该文件?
FileWatcher是片状的。 如果您正在观看网络驱动器上的文件夹,也会出现问题。 我已经看到有十几个或更多使用FileWatcher的应用程序,而且每个人中的每个人都不止一次无法识别创建文件的时间。
我将使用定时事件来备份FileWatcher,该事件检查新文件或修改过的文件。 这样,如果FileWatcher无法识别事件,计时器将捕获该事件。
我认为最好亲自构建一个服务来监视该文件夹,因为这样您就可以将该服务上的帐户设置为LocalSystem,并且如果该帐户与正在创建该文件的其他服务位于同一台计算机上,那应该没问题。 但是,我想代码应该类似于从应用程序执行的代码,但有一个额外的层:模拟。 是否使用FileSystemWatcher
确实与它无关。 权限是权限,本身就是一个单独的动物。
我对自己构建的服务进行类似文件检查的方式是通过计时器完成的。 您可以将其与查找文件属性(例如File.Exists()
和File.GetCreationTime()
以及File.GetLastWriteTime()
以确定文件是否存在,何时到达以及何时被最后修改。 您会知道是否已处理该文件,如果该文件的时间间隔超过了计时器的运行间隔。
参考: http : //www.csharp-examples.net/file-creation-modification-time/
对我来说,每当我处理该文件时,我就让我的应用程序将其删除,因此,我要做的就是File.Exists()
检查是否还有另一个文件。
下面的代码是一种用于定期查找文件的服务,并且在下一部分中,我还稍微集成了您需要做的(出于模拟目的而没有用),我将在下面进行解释。 您也许可以使它适应您的应用程序:
using System;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace MyNamespace
{
public partial class Service1: ServiceBase
{
Thread syncThread = null;
System.Timers.Timer timer1;
string filePath = @"C:\myfile.txt";
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer1 = new System.Timers.Timer();
timer1.Interval = 60000; // 1 min
timer1.Enabled = true;
timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
timer1.Start();
}
protected override void OnStop()
{
syncThread.Abort();
timer1.Stop();
}
protected void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
syncThread = new Thread(new ThreadStart(doThread));
syncThread.Start();
}
protected void doThread()
{
// This will run for each timer interval that elapses
// in its own separate thread, and each thread will
// end when the processing in this function ends
// You'll need to develop a strategy for getting these
// into your app
string username, domainName, password;
// Log the domain service account in, here...
bool returnValue = LogonUser(userName, domainName, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
if (!returnValue) return; // not logged in - report this
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
bool fileAbsent = true;
string myFileText = String.Empty;
if (File.Exists(filePath))
{
fileAbsent = false;
FileStream fs = new FileStream(filePath, FileMode.Open);
StreamReader sr = new StreamReader(fs)
myFileText = sr.ReadToEnd();
sr.Close();
fs.Close();
File.Delete(filePath);
}
else
{
// report that file does not exist
}
if (myFileText != String.Empty) // content found
{
// do processing here
}
else
{
//if (fileAbsent == false)
// report file was found, but empty
}
}
}
}
}
}
请注意,如果有人没有打开您的应用程序正在监视的文件的权限,并且他们已经登录并且运行了您正在构建的该应用程序,那么您将无法打开它。 该应用程序使用与登录用户相同的文件权限,除非您实施代码以其他方式对确实拥有该文件权限的用户使用WindowsImpersonationContext
。 但是您将无法在应用程序中模拟Windows LocalSystem帐户,因为您没有该帐户的凭据,因此,最佳做法是在需要额外权限的域帐户下运行服务,因为这样。 而是,应将服务设置为在新的或现有的域服务帐户下运行,该帐户应具有您知道其密码的文件的权限。 然后,您可以在您的应用程序中模拟该域帐户,就像您实际使用该帐户登录一样。
下面的类是从MSDN站点复制并格式化的 ,类似于您必须适应应用程序的类-您必须将其与上面的计时器代码结合起来。 这将是您必须提示或存储有权访问该文件的域帐户的凭据的位置。 在using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) { ... }
区域内,您将以模拟用户的身份进行文件读取和处理。 我已经在上面的代码中添加了LogonUser()
并对其进行了LogonUser()
,但是您将必须包括该函数,常量以及下面所有我没有提供的其他缺少的引用:
public class ImpersonationDemo
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
// Test harness.
// If you incorporate this code into a DLL, be sure to demand FullTrust.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public static void Main(string[] args)
{
SafeTokenHandle safeTokenHandle;
try
{
string userName, domainName;
// Get the user token for the specified user, domain, and password using the
// unmanaged LogonUser method.
// The local machine name can be used for the domain name to impersonate a user on this machine.
Console.Write("Enter the name of the domain on which to log on: ");
domainName = Console.ReadLine();
Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
userName = Console.ReadLine();
Console.Write("Enter the password for {0}: ", userName);
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
Console.WriteLine("LogonUser called.");
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
throw new System.ComponentModel.Win32Exception(ret);
}
using (safeTokenHandle)
{
Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);
// Check the identity.
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Use the token handle returned by LogonUser.
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
// Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
}
}
// Releasing the context object stops the impersonation
// Check the identity.
Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred. " + ex.Message);
}
}
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
参考: https : //msdn.microsoft.com/zh-cn/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.