Process 在C#DLL生存期内运行并终止Selenium服务器单例进程

Process 在C#DLL生存期内运行并终止Selenium服务器单例进程,process,selenium,singleton,selenium-rc,Process,Selenium,Singleton,Selenium Rc,我有一个Selenium Test.DLL,它是使用NUnit加载的 当测试运行时,我悄悄地在进程中运行所需的SeleniumJava服务器 但是,我当前在测试启动时启动服务器,在测试停止时启动服务器 这会导致selenium服务器在每次测试时启动/停止 我想要的是Selenium服务器进程: 在DLL加载/初始化时或在第一次测试开始时启动 在DLL死机或垃圾回收时执行Kill()ed 我读到C#不支持捕捉DLL初始化和调用代码。(我错了吗?) 我的想法是将Selenium服务器托管在一个

我有一个Selenium Test.DLL,它是使用NUnit加载的

当测试运行时,我悄悄地在进程中运行所需的SeleniumJava服务器

但是,我当前在测试启动时启动服务器,在测试停止时启动服务器

这会导致selenium服务器在每次测试时启动/停止


我想要的是Selenium服务器进程:
  • 在DLL加载/初始化时或在第一次测试开始时启动
  • 在DLL死机或垃圾回收时执行
    Kill()
    ed


我读到C#不支持捕捉DLL初始化和调用代码。(我错了吗?)

我的想法是将Selenium服务器托管在一个singleton类中,并在第一次测试运行时对其进行初始化。然后,我会让垃圾收集通过解构器调用Dispose方法。我目前有以下代码来托管selenium服务器:

namespace Tests.Server
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Security;
    using System.Windows.Forms;
    using Microsoft.Win32;

    /// <summary>
    /// A singleton class to host and control the selenium server.
    /// </summary>
    public class SeleniumServer : IDisposable
    {
        #region Fields
        /// <summary>
        /// The singleton instance
        /// </summary>
        private static volatile SeleniumServer instance;

        /// <summary>
        /// An object to perform double-check locking upon instance creation to 
        /// avoid dead-locks. 
        /// See <see href="SeleniumServer.Instance"/> for more information.
        /// </summary>
        private static object syncRoot = new Object();

        /// <summary>
        /// The current selenium server.
        /// </summary>
        private Process seleniumServer = null;

        /// <summary>
        /// A flag for the disposal of the class.
        /// </summary>
        private bool isDisposed = false;
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the SeleniumServer class.  Starts the 
        /// Selenium Java server in a background hidden thread.
        /// </summary>
        private SeleniumServer()
        {
            // Get the java install folder.
            string javaFileLocation = this.GetJavaFileLocation();

            // Get the selenium server java executable
            string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar""";

            // Start the selenium server
            seleniumServer = new Process();
            seleniumServer.StartInfo.FileName = javaFileLocation;
            seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertification";
            seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\"));
            seleniumServer.StartInfo.UseShellExecute = true;
            seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            seleniumServer.Start();
        }
        #endregion

        #region Deconstructor
        ~SeleniumServer()
        {
            Dispose(false);
        }
        #endregion

        #region Properties
        /// <summary>
        /// A thread safe
        /// </summary>
        public static SeleniumServer Instance
        {
            get
            {
                // This approach ensures that only one instance is created and 
                // only when the instance is needed. Also, the variable is 
                // declared to be volatile to ensure that assignment to the 
                // instance variable completes before the instance variable can 
                // be accessed. Lastly, this approach uses a syncRoot instance 
                // to lock on, rather than locking on the type itself, to avoid 
                // deadlocks.
                // This double-check locking approach solves the thread 
                // concurrency problems while avoiding an exclusive lock in 
                // every call to the Instance property method. It also allows 
                // you to delay instantiation until the object is first 
                // accessed. In practice, an application rarely requires this 
                // type of implementation. In most cases, the static 
                // initialization approach is sufficient.
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new SeleniumServer();
                        }
                    }
                }

                return instance;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Stops the process.
        /// </summary>   
        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Code to dispose the managed resources of the class
                // Not needed right now.
            }

            // Code to dispose the un-managed resources of the class
            // TODO: Handle the exceptions
            Instance.seleniumServer.Kill();

            // All done!
            isDisposed = true;
        }

        /// <summary>
        /// Dispose of the class and stop the Selenium server process.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Stops the Selenium Server.
        /// </summary>
        public void Stop()
        {
            this.Dispose();
        }

        /// <summary>
        /// Attempts to get the Java installation folder from the registry.  If 
        /// it cannot be found the default installation folder is checked before 
        /// failing.
        /// </summary>
        /// <returns>The Java executable file path.</returns>
        /// <exception cref="System.Exception">
        /// Thrown when the user does not have permission to access the 
        /// registry.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// Thrown if the registry key object is disposed of.
        /// </exception>
        /// <exception cref="System.IOException">
        /// Thrown if the registry key object is marked for deletion.
        /// </exception>
        private string GetJavaFileLocation()
        {
            string javaFileLocation = string.Empty;
            RegistryKey regKey = Registry.LocalMachine;
            RegistryKey subKey = null;
            try
            {
                // Check for Java in the native bitness
                string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\";
                subKey = regKey.OpenSubKey(javaRegistryLocation);

                // Check if we are running in WOW64 and only 32 bit Java is installed.
                if (subKey == null)
                {
                    javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\";
                    subKey = regKey.OpenSubKey(javaRegistryLocation);
                }

                // If Java was not found in either of these location the user 
                // needs to install it.  Note that Java 32 bit is a prerequisite 
                // for the installer so should always be installed.
                if (subKey == null)
                {
                    MessageBox.Show(
                        "You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.",
                        "Please Install Java",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);

                    throw new Exception("No installation of Java was detected to run the selenium server.");
                }

                // Get all the sub keys (could be multiple versions of Java 
                // installed) and get the most recent (last one)
                string[] subKeyNames = subKey.GetSubKeyNames();
                subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]);

                // Specify the java executable location
                javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe";
            }
            catch (SecurityException e)
            {
                // Attempt to find the java executable at the default location.
                javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
                if (!File.Exists(javaFileLocation))
                {
                    MessageBox.Show(
                        "The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
                        "Java Executable Not Found",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);

                    throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e);
                }
            }
            catch (UnauthorizedAccessException e)
            {
                // Attempt to find the java executable at the default location.
                javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
                if (!File.Exists(javaFileLocation))
                {
                    MessageBox.Show(
                        "The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
                        "Java Executable Not Found",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);

                    throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e);
                }
            }
            catch (ObjectDisposedException e)
            {
                // This hopefully shouldn't happen so ask the user to report it.
                MessageBox.Show(
                    "The Java registry object was closed, resulting in the Java server not being started.  Please report this error.",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                throw new ObjectDisposedException("The Java registry object was closed.  Please report this error.", e);
            }
            catch (IOException e)
            {
                // This hopefully shouldn't happen so ask the user to report it.
                MessageBox.Show(
                    "The Java registry object was marked for deletion, resulting in the Java server not being started.  Please report this error.",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                throw new ObjectDisposedException("The Java registry object was marked for deletion.  Please report this error.", e);
            }

            return javaFileLocation;
        }
        #endregion
    }
}
namespace Tests.Server
{
使用制度;
使用系统诊断;
使用System.IO;
使用系统安全;
使用System.Windows.Forms;
使用Microsoft.Win32;
/// 
///一个单例类来承载和控制selenium服务器。
/// 
公共类SeleniumServer:IDisposable
{
#区域字段
/// 
///单例实例
/// 
私有静态易失性SeleniumServer实例;
/// 
///要在创建实例时执行双重检查锁定的对象
///避免死锁。
///有关更多信息,请参阅。
/// 
私有静态对象syncRoot=新对象();
/// 
///当前的selenium服务器。
/// 
私有进程seleniumServer=null;
/// 
///用于处置该类的旗帜。
/// 
私有bool isDisposed=false;
#端区
#区域构造函数
/// 
///初始化SeleniumServer类的新实例。启动
///后台隐藏线程中的Selenium Java服务器。
/// 
私有SeleniumServer()
{
//获取java安装文件夹。
字符串javaFileLocation=this.GetJavaFileLocation();
//获取selenium服务器java可执行文件
字符串jarFileLocation=''''+目录.GetCurrentDirectory()+@“\SeleniumServer\selenium服务器.jar”“”;
//启动selenium服务器
seleniumServer=新进程();
seleniumServer.StartInfo.FileName=javaFileLocation;
seleniumServer.StartInfo.Arguments=“-jar”+jarFileLocation+”-browserSessionReuse-trustAllSSLCertification”;
seleniumServer.StartInfo.WorkingDirectory=jarFileLocation.Substring(0,jarFileLocation.LastIndexOf(“\\”);
seleniumServer.StartInfo.UseShellExecute=true;
seleniumServer.StartInfo.WindowsStyle=ProcessWindowsStyle.Hidden;
seleniumServer.Start();
}
#端区
#区域解构器
~SeleniumServer()
{
处置(虚假);
}
#端区
#区域属性
/// 
///线程安全的
/// 
公共静态SeleniumServer实例
{
得到
{
//这种方法确保只创建一个实例,并且
//仅当需要实例时。此外,变量
//声明为易失性,以确保
//实例变量完成后,实例变量才能运行
//最后,此方法使用syncRoot实例
//锁定,而不是锁定类型本身,以避免
//僵局。
//这种双重检查锁定方法解决了线程问题
//避免独占锁定时的并发问题
//对实例属性方法的每次调用。它还允许
//您需要延迟实例化,直到对象第一次被初始化
//实际上,应用程序很少需要这样做
//实现的类型。在大多数情况下,静态
//初始化方法就足够了。
if(实例==null)
{
锁定(同步根)
{
if(实例==null)
{
实例=新的SeleniumServer();
}
}
}
返回实例;
}
}
#端区
#区域方法
/// 
///停止进程。
///    
受保护的无效处置(bool处置)
{
如果(处置)
{
//用于处置类的托管资源的代码
//现在不需要。
}
//用于处置类的未管理资源的代码
//TODO:处理异常
Instance.seleniumServer.Kill();
//全部完成!
isDisposed=true;
}
/// 
///处置该类并停止Selenium服务器进程。
/// 
公共空间处置()
{
处置(真实);
总干事(本);
}
/// 
///停止Selenium服务器。
/// 
公共停车场()
{
这个。Dispose();
}
/// 
///尝试从注册表获取Java安装文件夹。如果
///找不到默认安装文件夹,因为之前已选中该文件夹
///失败。
/// 
///Java可执行文件路径。
/// 
///当用户没有权限t时引发
// <copyright file="SeleniumServer.cs" company="Your Company">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <summary>
// Provides a singleton class for hosting and running the selenium server.
// </summary>

namespace YourCompany.Tests.Server
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Security;
    using System.Windows.Forms;
    using Microsoft.Win32;

    /// <summary>
    /// A singleton class to host and control the selenium server.
    /// </summary>
    public sealed class SeleniumServer : IDisposable
    {
        #region Fields
        /// <summary>
        /// The singleton instance
        /// </summary>
        private static volatile SeleniumServer instance;

        /// <summary>
        /// An object to perform double-check locking upon instance creation to 
        /// avoid dead-locks. 
        /// See <see href="SeleniumServer.Instance"/> for more information.
        /// </summary>
        private static object syncRoot = new object();

        /// <summary>
        /// The current selenium server.
        /// </summary>
        private Process seleniumServer = null;

        /// <summary>
        /// A flag for the disposal of the class.
        /// </summary>
        private bool isDisposed = false;
        #endregion

        #region Constructor
        /// <summary>
        /// Prevents a default instance of the SeleniumServer class from being created.  Starts the Selenium Java server in a background hidden thread.
        /// </summary>
        private SeleniumServer()
        {
            // Get the java install folder.
            string javaFileLocation = this.GetJavaFileLocation();

            // Get the selenium server java executable
            string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar""";

            // Start the selenium server
            this.seleniumServer = new Process();
            this.seleniumServer.StartInfo.FileName = javaFileLocation;
            this.seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertificates";
            this.seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\"));
            this.seleniumServer.StartInfo.UseShellExecute = true;
            this.seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            this.seleniumServer.Start();

            // The class is no long disposed
            this.isDisposed = false;
        }
        #endregion

        #region Deconstructor
        /// <summary>
        /// Finalizes an instance of the SeleniumServer class.
        /// </summary>
        ~SeleniumServer()
        {
            this.Dispose(false);
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets a thread safe instance of the Selenium Server class.
        /// </summary>
        public static SeleniumServer Instance
        {
            get
            {
                // This approach ensures that only one instance is created and 
                // only when the instance is needed. Also, the variable is 
                // declared to be volatile to ensure that assignment to the 
                // instance variable completes before the instance variable can 
                // be accessed. Lastly, this approach uses a syncRoot instance 
                // to lock on, rather than locking on the type itself, to avoid 
                // deadlocks.
                // This double-check locking approach solves the thread 
                // concurrency problems while avoiding an exclusive lock in 
                // every call to the Instance property method. It also allows 
                // you to delay instantiation until the object is first 
                // accessed. In practice, an application rarely requires this 
                // type of implementation. In most cases, the static 
                // initialization approach is sufficient.
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new SeleniumServer();
                        }
                    }
                }

                return instance;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Dispose of the class and stop the Selenium server process.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Stops the process.
        /// </summary>
        /// <param name="disposing">
        /// True if managed resources need to be disposed
        /// </param>
        private void Dispose(bool disposing)
        {
            if (!this.isDisposed)
            {
                if (disposing)
                {         
                    // If this class is expanded:
                    // Code to dispose the managed resources of the class
                }

                // Kill the server
                if (this.seleniumServer != null)
                {
                    try
                    {
                        this.seleniumServer.Kill();
                        this.seleniumServer = null;
                    }
                    catch (Exception)
                    {
                        MessageBox.Show(
                            "The Selenium Java Server could not be stopped, please start Task Manager and killed \"java.exe\"",
                            "Failed to Stop Jave Server",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                }
            }

            // All done!
            this.isDisposed = true;
        }

        /// <summary>
        /// Attempts to get the Java installation folder from the registry.  If 
        /// it cannot be found the default installation folder is checked before 
        /// failing.
        /// </summary>
        /// <returns>The Java executable file path.</returns>
        /// <exception cref="System.Exception">
        /// Thrown when the user does not have permission to access the 
        /// registry.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// Thrown if the registry key object is disposed of.
        /// </exception>
        /// <exception cref="System.IOException">
        /// Thrown if the registry key object is marked for deletion.
        /// </exception>
        private string GetJavaFileLocation()
        {
            string javaFileLocation = string.Empty;
            RegistryKey regKey = Registry.LocalMachine;
            RegistryKey subKey = null;
            try
            {
                // Check for Java in the native bitness
                string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\";
                subKey = regKey.OpenSubKey(javaRegistryLocation);

                // Check if we are running in WOW64 and only 32 bit Java is installed.
                if (subKey == null)
                {
                    javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\";
                    subKey = regKey.OpenSubKey(javaRegistryLocation);
                }

                // If Java was not found in either of these location the user 
                // needs to install it.  Note that Java 32 bit is a prerequisite 
                // for the installer so should always be installed.
                if (subKey == null)
                {
                    MessageBox.Show(
                        "You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.",
                        "Please Install Java",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);

                    throw new Exception("No installation of Java was detected to run the selenium server.");
                }

                // Get all the sub keys (could be multiple versions of Java 
                // installed) and get the most recent (last one)
                string[] subKeyNames = subKey.GetSubKeyNames();
                subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]);

                // Specify the java executable location
                javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe";
            }
            catch (SecurityException e)
            {
                // Attempt to find the java executable at the default location.
                javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
                if (!File.Exists(javaFileLocation))
                {
                    MessageBox.Show(
                        "The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
                        "Java Executable Not Found",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);

                    throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e);
                }
            }
            catch (UnauthorizedAccessException e)
            {
                // Attempt to find the java executable at the default location.
                javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
                if (!File.Exists(javaFileLocation))
                {
                    MessageBox.Show(
                        "The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
                        "Java Executable Not Found",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);

                    throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e);
                }
            }
            catch (ObjectDisposedException e)
            {
                // This hopefully shouldn't happen so ask the user to report it.
                MessageBox.Show(
                    "The Java registry object was closed, resulting in the Java server not being started.  Please report this error.",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                throw new ObjectDisposedException("The Java registry object was closed.  Please report this error.", e);
            }
            catch (IOException e)
            {
                // This hopefully shouldn't happen so ask the user to report it.
                MessageBox.Show(
                    "The Java registry object was marked for deletion, resulting in the Java server not being started.  Please report this error.",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                throw new ObjectDisposedException("The Java registry object was marked for deletion.  Please report this error.", e);
            }

            return javaFileLocation;
        }
        #endregion
    }
}
SeleniumServer seleniumServer = SeleniumServer.Instance;