2015-10-12 2 views
0

Я пытаюсь использовать службу Windows для запуска в полночь каждый день, а затем проверяет таблицу SQL, чтобы увидеть, соответствуют ли даты будущих транзакций сегодняшней дате. Затем предполагается получить эти записи как объекты и отправляет их в другую службу для обработки. Однако, прежде чем я даже дошел до этого шага, я получаю некоторые странные ошибки из службы Windows в своем журнале ошибок, что я не уверен, как правильно отлаживать или сузить то, что происходит.Свойства службы Windows ConnectionString не были инициализированы?

Сначала я просто получил типичную ошибку инициализатора типа с классами, которые я вызывал в службе Windows, до тех пор, пока я не изменил свой журнал ошибок, чтобы включить внутреннее исключение, и теперь это выглядит как проблема, инициализирующая connectionString, хотя Я сейчас вызывал строку подключения непосредственно в моей службе Windows.

Я не уверен, почему у него возникнут проблемы с строкой соединения, когда я создаю новый SQLConnection со строкой открытого текста, существует ли какая-то ошибка перевода между моей службой Windows и остальной частью моего решения ?

Вот мой Windows Service Code:

Imports System.IO 
Imports System.Threading 
Imports System.Configuration 
Imports Afi.BusinessObjects.Billing 
Imports System.Data.SqlClient 


Public Class Service1 

Protected Overrides Sub OnStart(ByVal args() As String) 
    ' Add code here to start your service. This method should set things 
    ' in motion so your service can do its work. 

    Dim PaymentsToBeProcessed As New FuturePaymentsCollection 


    Me.WriteToFile("Future Transaction Processor started at " + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")) 

    Try 

     PaymentsToBeProcessed = GetFutureTransactionsByDate(DateTime.Now.Date) 

     Dim ProcessedPaymentsString As String = String.Format("{0} payments were processed during this session.", PaymentsToBeProcessed.Count) 

     Me.WriteToFile(ProcessedPaymentsString) 

    Catch ex As Exception 
     If Not ex.InnerException Is Nothing Then 

      WriteToFile("Future Transaction Processing Error on: {0} " + ex.Message + ex.StackTrace + ex.InnerException.ToString()) 
     Else 

      'Log any errors we get. 
      WriteToFile("Future Transaction Processing Error on: {0} " + ex.Message + ex.StackTrace) 

     End If 

    End Try 

    Me.ScheduleService() 

End Sub 

Protected Overrides Sub OnStop() 
    ' Add code here to perform any tear-down necessary to stop your service. 
    Me.WriteToFile("Future Transaction Processor stopped at " + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")) 
    Me.Schedular.Dispose() 
End Sub 

Protected mFuturePayment As AFI.BusinessObjects.Billing.FuturePayment 
Public Property Payment() As AFI.BusinessObjects.Billing.FuturePayment 
    Get 
     Return mFuturePayment 
    End Get 
    Set(ByVal value As AFI.BusinessObjects.Billing.FuturePayment) 
     mFuturePayment = value 

    End Set 
End Property 

Private Schedular As Timer 

Public Sub ScheduleService() 
    Try 

     'Initialize a new Timer called Schedular and give it the callback of SchedularCallback 
     Schedular = New Timer(New TimerCallback(AddressOf SchedularCallback)) 

     'Set our run mode as daily, so the service will run itself every day. 
     Dim runMode As String = "DAILY" 


     'Sets scheduledTime to a DateTime value 
     Dim scheduledTime As DateTime = DateTime.MinValue 


     If runMode = "DAILY" Then 

      'Gets our scheduled time from the app settings if the mode is equal to Daily and sets it equal to ScheduledTime 
      scheduledTime = DateTime.Parse("09:20") 

      'If the time has already been passed then we'll schedule our service to run for tomorrow at the same time previously set. 
      If DateTime.Now > scheduledTime Then 
       scheduledTime = scheduledTime.AddDays(1) 

      End If 
     End If 

     'Gets the difference in time between now and the scheduled time for the service to run. 
     Dim timeSpan As TimeSpan = scheduledTime.Subtract(DateTime.Now) 

     'Creates a string of our timeSpan to the next time the service should run. 
     Dim schedule As String = String.Format("{0} day(s) {1} hour(s) {2} minute(s) {3} seconds", timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds) 

     'Prints our next scheduled run to our log file. 
     Me.WriteToFile((Convert.ToString("Future Transaction Processor scheduled to run after: ") & schedule) + " {0}") 

     'Get the difference in milliseconds between the Scheduled and Current Time. 
     Dim dueTime As Integer = Convert.ToInt32(timeSpan.TotalMilliseconds) 

     'Change the Timer's Due Time 
     Schedular.Change(dueTime, Timeout.Infinite) 

     'If there are any errors write them to the log. 
    Catch ex As Exception 
     WriteToFile("Future Transaction Error on: {0} " + ex.Message + ex.StackTrace) 

     'Stop the Windows Service 
     Using serviceController As New System.ServiceProcess.ServiceController("FutureTransactionProcessor") 
      serviceController.[Stop]() 
     End Using 
    End Try 
End Sub 

Public Shared Function GetFutureTransactionsByDate(ByVal dateToday As DateTime) As FuturePaymentsCollection 

    Dim FuturePaymentsToBeProcessed As FuturePaymentsCollection = New FuturePaymentsCollection 

     Using cnSQL As SqlConnection = New SqlConnection("Server=rdbashq01;Database=AFI_SYSTEM;User ID=*****;Password=****;Trusted_Connection=False;") 

      Using cmdSP As New SqlCommand("PROC_FUTURE_TRANSACTIONS_SEL_BY_TODAY", cnSQL) 

       cmdSP.CommandType = System.Data.CommandType.StoredProcedure 
       cmdSP.Parameters.AddWithValue("DATETODAY", dateToday) 

       cmdSP.Connection.Open() 
       Dim sqlReader As SqlDataReader = cmdSP.ExecuteReader() 

       If sqlReader.HasRows Then 
        While (sqlReader.Read()) 
         Dim futurePayment As New FuturePayment 

         futurePayment.FutureTransactionID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_TRANSACTION_ID")) 
         futurePayment.GroupID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_CNTC_GROUP_ID")) 
         futurePayment.PayorAccountID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_PAYOR_ACCOUNT_ID")) 
         futurePayment.PolicyID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_POLICY_ID")) 
         futurePayment.AccountTypeID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_ACCOUNT_TYPE_ID")) 
         futurePayment.TransationTypeID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_TRANSACTION_TYPE_ID")) 
         futurePayment.TransactionDate = sqlReader.GetDateTime(sqlReader.GetOrdinal("BMW_TRANSACTION_DATE")).ToString("MM/dd/yyyy") 
         futurePayment.TransactionSubmitter = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_TRANSACTION_SUBMITTER")) 
         futurePayment.TransactionAmount = sqlReader.GetDecimal(sqlReader.GetOrdinal("BMW_TRANSACTION_AMOUNT")) 
         futurePayment.TransactionLast4 = sqlReader.GetString(sqlReader.GetOrdinal("BMW_TRANSACTION_LAST4")) 
         futurePayment.TransactionEmail = sqlReader.GetString(sqlReader.GetOrdinal("BMW_TRANSACTION_EMAIL")) 
         futurePayment.PaymentInfo1 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo1")) 
         futurePayment.PaymentInfo2 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo2")) 
         futurePayment.PaymentInfo3 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo3")) 
         futurePayment.PaymentInfo4 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo4")) 
         futurePayment.PaymentInfo5 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo5")) 
         futurePayment.PaymentInfo6 = sqlReader.GetString(sqlReader.GetOrdinal("PaymentInfo6")) 
         futurePayment.TransactionUpdateDate = sqlReader.GetDateTime(sqlReader.GetOrdinal("BMW_TRANSACTION_UPDATE_DATE")) 

         FuturePaymentsToBeProcessed.Add(futurePayment) 

        End While 
       End If 

      cmdSP.Connection.Close() 

      End Using 

    End Using 

     For Each Payment As FuturePayment In FuturePaymentsToBeProcessed 

      Dim PaymentToBeProcessed As OneTimePayment 

      PaymentToBeProcessed.PayorAccountId = Payment.PayorAccountID 
      PaymentToBeProcessed.PolicyID = Payment.PolicyID 
      PaymentToBeProcessed.AccountTypeID = Payment.AccountTypeID 

      PaymentToBeProcessed.PayTypeID = 1 
      PaymentToBeProcessed.BankInfoName = Payment.PaymentInfo1 
      PaymentToBeProcessed.BankInfoRoutingNum = Payment.PaymentInfo2 
      PaymentToBeProcessed.BankInfoAccountNum = Payment.PaymentInfo3 

      If PaymentToBeProcessed.BankInfoAccountNum >= 4 Then 
       PaymentToBeProcessed.Last4 = PaymentToBeProcessed.BankInfoAccountNum.Substring(PaymentToBeProcessed.BankInfoAccountNum.Length - 4, 4) 
      Else 
       PaymentToBeProcessed.Last4 = "XXXX" 
      End If 

      PaymentToBeProcessed.TransactionTypeID = 1 
      PaymentToBeProcessed.Email = Payment.TransactionEmail 
      PaymentToBeProcessed.TransactionAmount = Payment.TransactionAmount 


      PaymentToBeProcessed.Save() 
      PaymentToBeProcessed.SendPaymentToGateway() 

      'Run our method to remove the future payment from the Future_Transactions table and enter it into the Future_transactions_History table as processed 
     Payment.ProcessFuturePayment(Payment.FutureTransactionID) 

     Next 

     Return FuturePaymentsToBeProcessed 

End Function 



Private Sub SchedularCallback(e As Object) 
    Me.WriteToFile("Future Transaction Log: " + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")) 
    Me.ScheduleService() 

End Sub 


Private Sub WriteToFile(text As String) 
    Dim path As String = "C:\FutureTransactionLog.txt" 
    Using writer As New StreamWriter(path, True) 
     writer.WriteLine(String.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt"))) 
     writer.Close() 
    End Using 

End Sub 

End Class 

Следующая ниже мой стек след ... Я считаю, что моя проблема заключается в csla.DataPortalException: DataPortal.Fetc не удалось (System.InvalidOperationException: ConnectionString свойство не инициализирован.)

Future Transaction Processor stopped at 12/10/2015 10:49:23 AM 
Future Transaction Processor started at 12/10/2015 10:49:46 AM 
Future Transaction Processing Error on: 12/10/2015 10:49:46 AM The type  initializer for 'AFI.BusinessObjects.Billing.FuturePayment' threw an exception. at AFI.BusinessObjects.Billing.FuturePayment..ctor() 

at FutureTransactionProcessor.Service1.GetFutureTransactionsByDate(DateTime dateToday) in C:\TFS ITD\Console\Main\Source\FutureTransactionProcessor\Service1.vb:line 159 

at FutureTransactionProcessor.Service1.OnStart(String[] args) in C:\TFS ITD\Console\Main\Source\FutureTransactionProcessor\Service1.vb:line 27Csla.DataPortalException: DataPortal.Fetch failed (System.InvalidOperationException: The ConnectionString property has not been initialized. 

at System.Data.SqlClient.SqlConnection.PermissionDemand() 

at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 

at System.Data.SqlClient.SqlConnection.Open() 

at Afi.Data.ConnectionManager.ExecuteQuery(String Query) in C:\TFS ITD\Console\Main\Source\AFI\Data\ConnectionManager.vb:line 20 

at Afi.Configuration.SystemSetting.SystemSettingsCollection.DataPortal_Fetch(Object v_Criteria) in C:\TFS ITD\Console\Main\Source\AFI\Configuration\SystemSettings.vb:line 169) ---> Csla.Server.CallMethodException: DataPortal_Fetch method call failed ---> System.InvalidOperationException: The ConnectionString property has not been initialized. 

at System.Data.SqlClient.SqlConnection.PermissionDemand() 

at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 

at System.Data.SqlClient.SqlConnection.Open() 

at Afi.Data.ConnectionManager.ExecuteQuery(String Query) in C:\TFS ITD\Console\Main\Source\AFI\Data\ConnectionManager.vb:line 20 

    at Afi.Configuration.SystemSetting.SystemSettingsCollection.DataPortal_Fetch(Object v_Criteria) in C:\TFS ITD\Console\Main\Source\AFI\Configuration\SystemSettings.vb:line 169 

--- End of inner exception stack trace --- 

at System.Data.SqlClient.SqlConnection.PermissionDemand() 

at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 

at System.Data.SqlClient.SqlConnection.Open() 

at Afi.Data.ConnectionManager.ExecuteQuery(String Query) in C:\TFS ITD\Console\Main\Source\AFI\Data\ConnectionManager.vb:line 20 

at Afi.Configuration.SystemSetting.SystemSettingsCollection.DataPortal_Fetch(Object v_Criteria) in C:\TFS ITD\Console\Main\Source\AFI\Configuration\SystemSettings.vb:line 169 

at Csla.MethodCaller.CallMethod(Object obj, MethodInfo info, Object[] parameters) 

at Csla.Server.SimpleDataPortal.Fetch(Type objectType, Object criteria, DataPortalContext context) 

--- End of inner exception stack trace --- 

at System.Data.SqlClient.SqlConnection.PermissionDemand() 

at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 

at System.Data.SqlClient.SqlConnection.Open() 

at Afi.Data.ConnectionManager.ExecuteQuery(String Query) in C:\TFS ITD\Console\Main\Source\AFI\Data\ConnectionManager.vb:line 20 

at Afi.Configuration.SystemSetting.SystemSettingsCollection.DataPortal_Fetch(Object v_Criteria) in C:\TFS ITD\Console\Main\Source\AFI\Configuration\SystemSettings.vb:line 169 

at Csla.MethodCaller.CallMethod(Object obj, MethodInfo info, Object[] parameters) 

at Csla.Server.SimpleDataPortal.Fetch(Type objectType, Object criteria, DataPortalContext context) 

at Csla.DataPortal.Fetch(Type objectType, Object criteria) 

at Csla.DataPortal.Fetch[T](Object criteria) 

at Afi.Configuration.SystemSetting.get_Collection() in C:\TFS ITD\Console\Main\Source\AFI\Configuration\SystemSettings.vb:line 97 

at Afi.Security.SecSystem.get_Collection() in C:\TFS ITD\Console\Main\Source\AFI\Security\SecSystem.vb:line 127 

at Afi.Security.AFISecurityIdentifier.LoadObjects() in C:\TFS ITD\Console\Main\Source\AFI\Security\AFISecurityIdentifier.vb:line 21 

at AFI.BusinessObjects.Billing.FuturePayment..cctor() in C:\TFS ITD\Console\Main\Source\AFI_BusinessObjects\Billing\FuturePayment.vb:line 26 

Если я правильно понять этот проект не может создать свою строку соединения для извлечения данных из SQL? Может кто-то, пожалуйста, помогите мне понять больше о том, что происходит, или помочь мне сузить место, где можно устранить эту проблему? Мне также предложила одна из наших более старших разработчиков, возможно, мне нужно просто использовать службу Windows для запуска методов и поместить все эти методы в веб-службу, а не ... устранить все эти проблемы или они работают в службе Windows?

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

EDIT 1: Ниже конструктор FuturePayment

#Region " Constructors " 

    Public Sub New() 

    End Sub 


#End Region 
+0

Почему ваша строка соединения жестко закодирована в середине вашего кода? Он должен быть в вашем файле конфигурации. В какой строке происходит исключение? –

+0

Привет, Шон, я попытался добавить файл конфигурации, в котором он динамически перешел к этому, но я получаю все те же ошибки, когда поместил его в app.config под службу Windows. Исключение происходит на этой линии: futurePayment.FutureTransactionID = sqlReader.GetInt32 (sqlReader.GetOrdinal ("BMW_TRANSACTION_ID")) – mcloud313

+0

Вы уверены? Эта строка: Dim futurePayment Поскольку новый FuturePayment выглядит только подозрительно для меня. Что в конструкторе FuturePayment? – Arkadiusz

ответ

1

Как отлаживать службы Windows:

Перед тем, как собрать и установить службу вы хотите добавить код в свой OnStart обработчик. Идея состоит в том, что мы напишем метод, который в основном помещает поток в режим сна и дает нам время для присоединения отладчика. Обычно я добавляю вспомогательную процедуру в класс службы и называю ее WaitForDebugging или что-то в этом роде. Ваш метод должен выглядеть примерно так:

Private Sub WaitForDebugging() 
    #If DEBUG Then 
     Dim timeout = Now.AddSeconds(30) 
     Dim x As Boolean = True 
     While Now < timeout And x 
      'Set x to false while debugging to jump out of this early' 
      System.Threading.Thread.Sleep(500) 
     End While 
    #End If 
End Sub 

#if DEBUG then Предложение заключается в защите от этого запущен в производство. Вам нужно будет установить точку останова на линии While Now < timeout And x для последующего использования.

Первое, что должен сделать ваш обработчик OnStart, это вызвать метод WaitForDebugging.

Таким образом, с учетом этого вы готовы скомпилировать и установить свой сервис Windows, как обычно. После установки службы просто запустите его, как обычно.

Здесь все будет немного отличаться, чем вы привыкли. Вместо того, чтобы ваша служба запускалась быстро, индикатор выполнения покажется зависающим, это вполне нормально и ожидается. Что вам нужно сделать, так это открыть свое решение в VS, когда вы начнете свою службу. После того, как вы начнете свою услугу, немедленно переключитесь на VS (даже до того, как индикатор прогресса повиснет), а затем перейдите к Tools -> Attach to Process. Если вы используете настройку комбинации клавиш по умолчанию для VB.NET, то использование Ctrl + Alt + P приведет вас к тому же интерфейсу.

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

enter image description here

Убедитесь, что подсвеченные флажок в интерфейсе. После этого выполните поиск в списке для имени вашей службы. Как только вы найдете свою услугу, просто выберите ее в списке и нажмите кнопку Attach. VS будет проходить через какой-то материал, и как только он закончит, программа должна сломаться в точке останова, которую мы установили ранее.

Затем вы можете установить x в false, чтобы выскочить рано или подождать 30 секунд и выполнить свой код, как обычно.

И у вас оно есть. После этих шагов вы сможете отлаживать любую созданную службу Windows.