Почему у меня возникла исключительная ситуация TypeInitializationException, вызывающая метод при выполнении метода DAO, только когда я вызываю его из тестового метода NUnit? - PullRequest
0 голосов
/ 31 декабря 2018

Я довольно новичок в .NET и SharePoint (я пришел из среды Java EE), и у меня возникает следующая странная проблема при работе над SharePoint 2013 .

По сути, в моем приложении SharePoint я получаю доступ к базе данных SQL Server, используя некоторые классы в проекте DAO (что есть в моем решении).Этот проект DAO основан на ADO.NET .Работает нормально.Проблема заключается в том, что я создал новый проект NUnit в своем решении, потому что я хочу протестировать этот метод DAO, определенный в моем проекте DAO, выполняя некоторый интеграционный тест.В этом случае я получаю странное исключение.

Я пытаюсь объяснить вам мою ситуацию в деталях.

В моем решении у меня есть проект, который действует как DAO (он содержит весь запрос базы данныхи обрабатывать соединение с БД).Этот проект называется что-то вроде MyPrjSqlEngine .Затем у меня есть другой проект под названием MyMainPrj , который содержит некоторое задание таймера .В этом основном проекте у меня есть задание таймера, содержащее следующую логику:

namespace MyMainPrj.TimerJob.Notifiche
{
    public class NotificheGiornaliereView : SPJobDefinition
    {


        public NotificheGiornaliereView() : base() { }

        public NotificheGiornaliereView(string jobName, SPService service) :
                  base(jobName, service, null, SPJobLockType.None)
        {
            this.Title = "Notifiche giornaliere protocollo View";
        }

        public NotificheGiornaliereView(string jobName, SPWebApplication webapp) :
                base(jobName, webapp, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "Notifiche giornaliere protocollo View";
        }

        public override void Execute(Guid targetInstanceId)
        {
            List<string> tenantList = ProtUtils.GetTenantList();

            DBConnection dbConfig = new DBConnection();
            dbConfig.Tenant = "XXX";

            ArrayList listaUtenti = new ArrayList();

            List<string> urlList = IndirizziProtocolliSQL.GetListaIndirizziSiti(dbConfig);
        }
    }
}

Логика реализована в методе Execute () , который извлекает список строк из БД. IndirizziProtocolliSQL является классом моего MyPrjSqlEngine DAO проекта.

Это код вызываемого метода, реализованного в этом проекте DAO:

public static List<string> GetListaIndirizziSiti(DBConnection dbConf)
{
    string url = null;

    List<string> urlList = new List<string>();

    string query = PROT_INDIRIZZI_PROTOCOLLI.SELECT_LISTA_INDIRIZZI_SITI;
    using (SqlConnection con = PrjConnection.getStringConnection(dbConf.Tenant + "_PROTOCOLLO"))
    {
        using (SqlCommand cmd = new SqlCommand(query, con))
        {
            try
            {
                con.Open();

                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            url = reader.GetString(reader.GetOrdinal("Url"));
                            urlList.Add(url);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                con.Close();
            }
        }
    }
    return urlList;
}

Как видите, здесь он получает соединение с БД:

using (SqlConnection con = PrjConnection.getStringConnection(dbConf.Tenant + "_PROTOCOLLO"))

Это код метода getStringConnection () (определяется всегда в одном и том же проекте DAO):

[MethodImpl(MethodImplOptions.Synchronized)]
public static SqlConnection gettringConnection(string name)
{
    SqlConnectionStringBuilder bu = new SqlConnectionStringBuilder();

    XmlDocument config = new XmlDocument();
    config.Load(@"C:\Program Files\Information Workers Group\MyPrj\" + MyPrjSqlEngine.Properties.Resources.Progetto + @"\cfg\config.xml");

    XmlNode xmlRoot = config.SelectSingleNode("connection_config");
    XmlNode root = xmlRoot.SelectSingleNode("database");
    string user = root.SelectSingleNode("user").InnerText;
    string passwordCrypted = root.SelectSingleNode("password").InnerText;
    string password = Crypto.Crypto.DecriptAes(passwordCrypted);
    string server = root.SelectSingleNode("server").InnerText;
    string database = name;

    bu.DataSource = @server;

    bu.InitialCatalog = database;

    bu.IntegratedSecurity = false; // Sql Server Authentification

    bu.UserID = user;

    bu.Password = password;
    bu.MultipleActiveResultSets = true;
    SqlConnection mycon = new SqlConnection();
    mycon.ConnectionString = bu.ConnectionString;

    return mycon;
}

Как видно из этого метода, он извлекает и загружает XMLфайл конфигурации, который содержит информацию о соединении с базой данных, что-то вроде этого:

<connection_config>
   <database>
      <user>MY-USER</user>
      <password>CRYPTED-PSWD</password>
      <server>DB-SERVER-NAME</server>
   </database>
</connection_config>

, а затем извлекает эту информацию из этого XML-файла и использует ее для создания строки соединения с БД.

Как объяснено в начале поста, он отлично работает, выполняя запрос из приложения SharePoint (я выполняю задание, и запрос выполняется, как я ожидаю, без проблем).

проблема заключается в следующем: тогда я определил новый NUnit в своем решении, чтобы протестировать методы DAO в качестве интеграционного теста, поэтому в этом тестовом проекте у меня есть этот класс:

namespace Tests
{
    public class Tests
    {
        [SetUp]
        public void Setup()
        {
        }

        [Test]
        public void Test1()
        {
            Assert.Pass("PASSED");
        }


        [Test]
        public void GetIndirizzoProtocollo_XXX_YYY_ReturnSingleValue()
        {
            DBConnection dbConfig = new DBConnection();
            dbConfig.Tenant = "XXX";

            List<string> urlList = IndirizziProtocolliSQL.GetListaIndirizziSiti(dbConfig);

            Assert.Pass("OK");
        }

    }
}

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

Отладка выполнения этого метода теста у меня:

  1. Я правильно ввожу в IndirizziProtocolliSQL.GetListaIndirizziSiti () метод DAO.

  2. Здесь он правильно входит в метод getStringConnection () , где начинается для правильного получения информациииз файла конфигурации XML.

  3. Теперь переменная passwordCrypted содержит зашифрованный пароль, полученный из документа XML.Затем он пытается выполнить эту строку для расшифровки зашифрованного пароля:

    string password = Crypto.Crypto.DecriptAes(passwordCrypted);
    

    и теперь я получаю следующее исключение в трассировке стека:

    Exception thrown: 'System.TypeInitializationException' in MyPrjSqlEngine.dll
    An exception of type 'System.TypeInitializationException' occurred in MyPrjSqlEngine.dll but was not handled in user code
    The type initializer for '<Module>' threw an exception.
    

Ввсплывающее окно в строке, где происходит исключение, у меня есть сообщение, подобное этому:

    System.TypeInitializationException: 'The type initializer for '<Module>' threw an exception.'
    EntryPointNotFoundException: A library name must be specified in a DllImport attribute applied to non-IJW methods.

Внутреннее исключение :

-       InnerException  {<CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load.
 ---> System.EntryPointNotFoundException: A library name must be specified in a DllImport attribute applied to non-IJW methods.
   at _getFiberPtrId()
   at <CrtImplementationDetails>.LanguageSupport._Initialize(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String errorMessage, Exception innerException)
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   at .cctor()} System.Exception {<CrtImplementationDetails>.ModuleLoadException}

Отладка этого модульного теста у меня естьчто когда он пытается выполнить эту строку:

string password = Crypto.Crypto.DecriptAes(passwordCrypted);

я не могу сделать Step Into этот метод DecriptAes () .Я не знаю почему, потому что он входит в класс, определенный в том же проекте MyPrjSqlEngine .

Кажется, что он не может найти этот Crypto класс или что-то в этом роде.

Этот Cyrpto класс определен в том же MyPrjSqlEngine pèroject, но в другом пространстве имен:

namespace MyPrjSqlEngine.Crypto
{
    public class Crypto
    {
        ........................
        ........................
        ........................
    }
}

Почему у меня возникает эта проблема при вызове из модульного теста, и у меня нет вызова непосредственно из задания таймера SharePoint?Как я могу попытаться это исправить?

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