Выполнить метод в приложении в AppPool, используя DirectoryEntry и Reflection? - PullRequest
0 голосов
/ 24 января 2011

Добрый день

У меня небольшой веб-сад с кешем StateSession.Очевидная проблема заключается в том, что когда вы хотите очистить кеш, кеш очищается только на рабочем процессе, который обрабатывает вызов.

В определенном AppPool будет по крайней мере одно приложение интерфейса пользователя и одна веб-службаЗаявка.Веб-службы выполняют большую часть кэширования, поэтому у них есть методы для очистки их кэша.

Я хотел бы создать метод, который будет получать входные данные (имя AppPool), а затем выполнять итерациютекущие процессы W3WP и получить необходимые пулы обратно.Это может быть сделано, и у меня есть способы получения этой информации.

Я застреваю, у меня есть имя AppPool, а также приложения, которые выполняются в этом рабочем процессе, но я не знаю, какиспользовать эту информацию для выполнения метода ClearCache () в определенном приложении веб-службы.

Я уверен, что это можно сделать с помощью Reflection, но я думаю, что упускаю что-то очевидное.

В настоящее время я просто использую консольное приложение, чтобы получить что-то, что работает.Затем это может быть своевременно перенесено на лучшее решение.

Пожалуйста, сообщите, если есть способ использовать текущую информацию для выполнения требуемого метода.

Ниже приведено тестовое приложение, как оностоит на данный момент.

Спасибо.

Жако

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Management;
using System.DirectoryServices;
using System.Collections;

namespace CacheCleaner
{
    class Program
    {
        const string defaultAppPoolMetabasePath = "IIS://localhost/W3SVC/AppPools/DefaultAppPool";

        static void Main(string[] args)
        {
            //show a list of all the processes.
            //GetListOfProcesses();

            //Kill all the worker processes
            //KillW3WP();

            //Refresh the application pool
            //RefreshAppPool(defaultAppPoolMetabasePath);

            //get a list of all the Applications in the DefaultAppPool
            //GetApplicationPoolInformation(defaultAppPoolMetabasePath);

            //get the apps in the apppool
            EnumerateApplicationsInPool(defaultAppPoolMetabasePath);

            Console.WriteLine("\n\nEnd of process. Press Enter.");

            Console.ReadLine();

        }

        /// <summary>
        /// Show all the processes that are currently running on the system
        /// </summary>
        static void GetListOfProcesses()
        {
            foreach (Process p in Process.GetProcesses())
            {
                Console.WriteLine("{0} {1}", p.Id, p.ProcessName);
            }
        }

        /// <summary>
        /// This will kill ALL the worker processes.
        /// Pretty much an iisreset call.
        /// Not good for Production sites :)
        /// </summary>
        static void KillW3WP()
        {
            foreach (Process p in Process.GetProcessesByName("w3wp"))
            {
                Console.WriteLine("Closing " + p.ProcessName);

                p.Kill();
                p.WaitForExit();

                if (p.HasExited)
                {
                    Console.WriteLine("Closed");
                }
                else
                {
                    Console.WriteLine("NOT Terminated");
                }
            }
        }

        /// <summary>
        /// Refresh a specific application pool
        /// </summary>
        /// <param name="metabasePath"></param>
        static void RefreshAppPool(string metabasePath)
        {
            using (DirectoryEntry applicationPool = new DirectoryEntry(metabasePath))
            {
                applicationPool.Invoke("Recycle");
            }
        }

        /// <summary>
        /// Get the Name of the worker process (AppPool Name)
        /// </summary>
        /// <param name="metabasePath"></param>
        static void GetApplicationPoolInformation(string metabasePath)
        {
            var scope = new ManagementScope(String.Format(@"\\{0}\root\cimv2", Environment.MachineName));
            var query = new SelectQuery("SELECT * FROM Win32_Process where Name = 'w3wp.exe'");
            using (var searcher = new ManagementObjectSearcher(scope, query))
            {
                foreach (ManagementObject process in searcher.Get())
                {
                    //get just the name of the application
                    var startIndex = process["CommandLine"].ToString().IndexOf("-ap ") + 5; //remove the -ap as well as the space and the "
                    var endIndex = process["CommandLine"].ToString().IndexOf("-", startIndex) - 2; //remove the closing "
                    var appPoolName = process["CommandLine"].ToString().Substring(startIndex, endIndex - startIndex);

                    var pid = process["ProcessId"].ToString();

                    Console.WriteLine("{0} - {1}", pid, appPoolName);
                }
            }
        }

        /// <summary>
        /// Get the applications in the pool
        /// From http://msdn.microsoft.com/en-us/library/ms524452%28v=vs.90%29.aspx
        /// </summary>
        /// <param name="metabasePath"></param>
        static void EnumerateApplicationsInPool(string metabasePath)
        {
            Console.WriteLine("\nEnumerating applications for the {0} pool:", metabasePath);

            try
            {
                DirectoryEntry entry = new DirectoryEntry(metabasePath);

                if (entry.SchemaClassName == "IIsApplicationPool")
                {
                    object[] param;
                    param = (object[])entry.Invoke("EnumAppsInPool", null);
                    foreach (string s in param)
                    {
                        Console.WriteLine("{0}", s);

                        //I am sure that I should be able to use this application name 
                        //with Reflection to be able to execute a method...

                    }
                    Console.WriteLine("Done.");
                }
                else
                    Console.WriteLine("Failed in EnumerateApplicationsInPool; {0} is not an app pool", metabasePath);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed in EnumerateApplicationsInPool with the following exception: \n{0}", ex);
            }
        }
    }
}

1 Ответ

0 голосов
/ 25 января 2011

Есть несколько способов подойти к этому, некоторые плохие, некоторые хорошие.

  1. Отказов каждого рабочего процесса.Это довольно эффективно и приведет к перезагрузке кэша, но приведет к очень плохому опыту для конечных пользователей, потому что существующие запросы будут остановлены (если вы обновляете базу данных без какой-либо защиты транзакций, вы можете увидеть, что ваши данные становятся непоследовательными).Вы также увидите потерю состояния сеанса, если вы используете InProc управление состоянием.

  2. Перезапуск каждого пула - лучше, чем подпрыгивание пула, поскольку существующие запросы по-прежнему будут разрешеныполный.Однако вы все равно увидите потерю состояния сеанса, если вы используете InProc управление состоянием.

  3. Использовать Зависимость кэша - многие кэши заполняются из базы данных SQL.ASP.NET поддерживает функцию под названием SqlCacheDependency.Вы можете использовать это для обновления ваших кэшированных данных в случае изменения исходных данных в базе данных.

  4. Используйте файловую зависимость кэша - если данные вашего кэша получены из (например)Файл данных XML, затем вы можете кэшировать эти данные и создать зависимость кэша от этого файла.Когда файл обновляется, кеш становится недействительным, и вы перезагружаете данные.Вы можете автоматизировать это с помощью FileSystemWatcher, поскольку сам класс CacheDependency не предоставляет никаких событий уведомлений об изменениях, и вам нужно будет проверять CacheDependency.HasChanged при каждом запросе.

Что касается вызова ClearCache() непосредственно в объекте кэша в каждом рабочем процессе, прямого способа сделать это с помощью отражения не существует.Возможно, вы сможете сделать это, используя .NET Debugging API и внедрить некоторый код для очистки кэша, но вы говорите о переходе к процессу, присоединении к нему и представлении себя отладчиком.Мне бы не хотелось писать это самому, когда есть другие механизмы, такие как зависимости кеша.

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