.NET: Сериализация объекта в файл из сторонней сборки (для ускорения Selenium WebDriver) - PullRequest
7 голосов
/ 22 марта 2012

Конечная цель для сериализации FirefoxDriver (мой вопрос здесь) = сделать WebDriver быстрее !!

Ниже приведена ссылка, которая описывает, как сериализовать объект. Но для этого нужно реализовать из ISerializable объект, который вы сериализуете. То, что я хотел бы сделать, это сериализовать объект, который я не определил - объект на основе класса в сборке стороннего производителя (из ссылки на проект), который не реализует ISerializable . Это возможно? Как это можно сделать?

http://www.switchonthecode.com/tutorials/csharp-tutorial-serialize-objects-to-a-file

Свойство (IWebDriver = тип интерфейса):

private IWebDriver driver;

Экземпляр объекта (FireFoxDriver является типом класса):

driver = new FirefoxDriver(firefoxProfile);

================

3/21/2012 обновление после опубликованного ответа

С чего бы это выдавать ошибку? Не нравится эта строка:

serializedObject.DriverInstance = (FirefoxDriver)driver;

...

Ошибка:

Cannot implicitly convert type 'OpenQA.Selenium.IWebDriver' to 'OpenQA.Selenium.Firefox.FirefoxDriver'. An explicit conversion exists (are you missing a cast?)

Вот код:

    FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
    Serializer serializer = new Serializer();
    serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
    driver = serializedObject.DriverInstance;

    if (driver == null)
    {
        driver = new FirefoxDriver(firefoxProfile);
        serializedObject.DriverInstance = (FirefoxDriverSerialized)driver;
        serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
    }

Вот два класса Serializer, которые я построил:

public class Serializer
{
   public Serializer()
   {
   }

   public void SerializeObject(string filename, FirefoxDriverSerialized objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);
      stream.Close();
   }

   public FirefoxDriverSerialized DeSerializeObject(string filename)
   {
      FirefoxDriverSerialized objectToSerialize;
      Stream stream = File.Open(filename, FileMode.Open);
      BinaryFormatter bFormatter = new BinaryFormatter();
      objectToSerialize = (FirefoxDriverSerialized)bFormatter.Deserialize(stream);
      stream.Close();
      return objectToSerialize;
   }
}

[Serializable()]
public class FirefoxDriverSerialized : FirefoxDriver, ISerializable
{
    private FirefoxDriver driverInstance;
    public FirefoxDriver DriverInstance
    {
        get { return this.driverInstance; }
        set { this.driverInstance = value; }
    }

    public FirefoxDriverSerialized()
    {
    }

    public FirefoxDriverSerialized(SerializationInfo info, StreamingContext ctxt)
    {
        this.driverInstance = (FirefoxDriver)info.GetValue("DriverInstance", typeof(FirefoxDriver));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        info.AddValue("DriverInstance", this.driverInstance);
    }
}

=================

3/23/2012 обновление № 2 - исправлена ​​сериализация / десериализация, но возникла другая проблема

Это исправило вызывающий код. Потому что мы удаляем файл * .qa при вызове WebDriver.Quit (), потому что именно тогда мы решили закрыть браузер. Это также убьет наш кэшированный драйвер. Поэтому, если мы начнем с нового окна браузера, мы попадем в блок catch, создадим новый экземпляр и сохраним его в нашем файле * .qa (в сериализованной форме).

    FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
    Serializer serializer = new Serializer();

    try
    {
        serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
        driver = serializedObject.DriverInstance;
    }
    catch
    {
        driver = new FirefoxDriver(firefoxProfile);
        serializedObject = new FirefoxDriverSerialized();
        serializedObject.DriverInstance = (FirefoxDriver)driver;
        serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
    }

Однако, все еще получаю это исключение:

Acu.QA.Main.Test_0055_GiftCertificate_UserCheckout:
SetUp : System.Runtime.Serialization.SerializationException : Type 'OpenQA.Selenium.Firefox.FirefoxDriver' in Assembly 'WebDriver, Version=2.16.0.0, Culture=neutral, PublicKeyToken=1c2bd1631853048f' is not marked as serializable.
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.

3-я строка в этом блоке кода выдает исключение:

   public void SerializeObject(string filename, FirefoxDriverSerialized objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);  // <=== this line 
      stream.Close();
   }

====================

обновление № 3 - 24.03.2012 - упрощенный экземпляр FirefoxDriver, не передавая ничего конструктору. Я сделаю это позже, передав FirefoxProfile в конструктор. Я все еще получаю то же исключение, что и обновление №2.

Телефонный код:

FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
Serializer serializer = new Serializer();
try
{
    serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
    driver = serializedObject.DriverInstance;
}
catch
{
    //driver = new FirefoxDriver(firefoxProfile);
    driver = new FirefoxDriver();
    serializedObject.DriverInstance = (FirefoxDriver)driver;
    serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
}

Также пришлось добавить ": base ()" в мой конструктор в моем сериализованном объектном классе:

[Serializable()]
public class FirefoxDriverSerialized : FirefoxDriver, ISerializable
{
    private FirefoxDriver driverInstance;
    public FirefoxDriver DriverInstance
    {
        get { return this.driverInstance; }
        set { this.driverInstance = value; }
    }

    public FirefoxDriverSerialized() : base()
    {
    }

    public FirefoxDriverSerialized(SerializationInfo info, StreamingContext ctxt)
    {
        this.driverInstance = (FirefoxDriver)info.GetValue("DriverInstance", typeof(FirefoxDriver));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        info.AddValue("DriverInstance", this.driverInstance);
    }
}

=============

Обновление № 4 - просто документирование подписей заглушки для класса OpenQA.Selenium.Firefox.FirefoxDriver

using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using System;

namespace OpenQA.Selenium.Firefox
{
    public class FirefoxDriver : RemoteWebDriver, ITakesScreenshot
    {
        // CLASS DATA MEMBERS 

        //public static readonly bool AcceptUntrustedCertificates;
        //public static readonly string BinaryCapabilityName;
        //public static readonly bool DefaultEnableNativeEvents;
        //public static readonly int DefaultPort;
        //public static readonly string ProfileCapabilityName;

        // CONSTRUCTORS

        //public FirefoxDriver();
        //public FirefoxDriver(FirefoxProfile profile);
        //public FirefoxDriver(ICapabilities capabilities);
        //public FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile);
        //public FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile, TimeSpan commandTimeout);

        // PROPERTIES

        protected FirefoxBinary Binary { get; }
        protected FirefoxProfile Profile { get; }

        // METHODS

        //protected override RemoteWebElement CreateElement(string elementId);
        //public Screenshot GetScreenshot();
        //protected void PrepareEnvironment();
        //protected override void StartClient();
        //protected override void StopClient();
    }
}

Ответы [ 2 ]

5 голосов
/ 22 марта 2012

Создайте свой собственный пользовательский объект, производный от ISerializable, и объект, который вы хотите сериализовать и сериализовать этот пользовательский объект. Этот конкретный пример не будет работать, если сторонний объект - Sealed (есть другие способы, которые все еще могут использоваться с ISerializable).

Обновлено по запросу

Обновлено за вопрос Обновление

public class MyFirefoxDriver : FirefoxDriver, ISerializable
{
  public MyFirefoxDriver(<Interface/Class> firefoxProfile)
    :base(firefoxProfile)
  {
  }

  void GetObjectData(SerializationInfo info, StreamingContext context)
  {
    // Properties needing to be serialized
    info.AddValue("SomeProperty", base.SomeProperty);
  }
}

Обновление 2

Ваш новый код вводит меня в заблуждение. Я думаю, что вы ищете ..

serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
driver = serializedObject;

Это потому, что FirefoxDriverSerialized это FireFoxDriver.

Обновление 3

Важно отметить, что конструкторы не вызываются при десериализации объекта . Это означает, что вещи, которые обычно создаются / устанавливаются в конструкторе, не будут подвергаться десериализации, что обычно приводит к NullReferenceException. Обходной путь - реализовать ISerializable и explicity установить объекты, необходимые для работы класса (как для GetObjectData, так и для специального конструктора десериализатора). Это может быть наиболее трудным, если понимание рассматриваемого объекта не является простым, или если у нас нет источника для него.

Важно подчеркнуть, что вам нужно реализовать как GetObjectData, так и специальный конструктор, когда ISerializable добавляется в класс. Компилятор предупредит вас, если GetObjectData отсутствует, но, поскольку невозможно реализовать реализацию конструктора, не будет выдано никаких предупреждений, если конструктор отсутствует, и будет выдано исключение при попытке десериализации класса без конструктор.

public class MyObject
{
  public MyObject()
  {
    this.SomeOtherObject = new MyObject2();
  }
  public string Name { get; set; }
  public MyObject2 SomeOtherObject { get; set; }
}

public class MyObjectSerializable : MyObject, ISerializable
{
  protected MyObjectSerializable(SerializationInfo si, StreamingContext context) 
  {
    // base() is never called during deserialization
    // so use the special ISerializable constructor to set the value of the object
    // why not add it to the si.AddValue?
    // because, most likely in this question, it is not a [Serializable] object either
    // so we have to treat it differently as well
    this.SomeOtherObject = new MyObject2();
  }

  public override void GetObjectData(SerializationInfo si, StreamingContext context)
  {
    si.AddValue("Name", Name);
  }
}
1 голос
/ 22 марта 2012

Не требуется наследовать от ISerializable.По умолчанию объект должен либо наследоваться от ISerializable, либо быть украшенным атрибутом SerializableAttribute.Без них лучше всего использовать SurrogateSelector .Это позволит вам указать сериализатору сериализовать другой объект на его место в зависимости от того, как вы определяете свой заменитель.

...