FileSystemWatcher не работает с файлами, созданными из службы Windows - PullRequest
1 голос
/ 26 января 2011

Я создаю файл из службы Windows, запущенной под учетной записью LocalSystem.У меня есть приложение Windows, которое отслеживает указанную папку, в которой создается файл.Я использую FileSystemWatcher, но он не срабатывает.Значок файла в проводнике Windows является значком замка.Как я могу создать этот файл из службы Windows, чтобы он был доступен из учетной записи пользователя Windows?

Ответы [ 2 ]

1 голос
/ 26 января 2011

FileWatcher ненадежен.Есть также проблемы, если вы просматриваете папку на сетевом диске.Я видел дюжину или более приложений, которые используют FileWatcher, и каждому из них не раз не удалось распознать, когда был создан файл.

Я бы сделал резервную копию FileWatcher с синхронизированным событием, которое проверяет наличие новых или измененных файлов.Таким образом, если FileWatcher не сможет распознать событие, таймер его перехватит.

0 голосов
/ 14 декабря 2016

Я думаю, что было бы лучше создать сервис для личного просмотра этой папки, поскольку с тех пор вы можете установить для этой учетной записи значение 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() к приведенному выше коду, но вам нужно будет включить эту функцию, константы и все остальные отсутствующие ссылки снизу, которые я не включил:

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/en-us/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...