Windows Service ConnectionString属性尚未初始化?

时间:2015-10-12 16:26:52

标签: sql-server vb.net windows-services csla

我正在尝试使用Windows服务每天午夜运行,然后检查SQL表以查看未来交易的日期是否与今天的日期相符。然后它应该将这些记录作为对象获取并将它们发送到另一个服务进行处理。然而,在我完成这一步之前,我在错误日志中从Windows服务中收到一些奇怪的错误,我不确定如何正确调试或缩小正在发生的事情。

起初我只是在Windows服务中调用了类的一般类型初始化程序错误,直到我将错误日志记录更改为包含内部异常,现在它看起来像是一个初始化connectionString的问题,即使我现在直接在我的Windows服务中调用连接字符串。

我不确定为什么在使用纯文本连接字符串创建新的SQLConnection时会出现连接字符串问题,我的Windows服务和其他解决方案之间是否存在某种转换错误?

这是我的Windows服务代码:

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服务来触发方法,并将所有这些方法放入Web服务中......而不是解决所有这些问题,或者应该他们在Windows服务中工作?

如果有人有任何问题可以帮助我查明我的问题,我可以在下面的评论中提供更多信息,提前感谢!

编辑1:以下是FuturePayment的构造函数

#Region "  Constructors  "

    Public Sub New()

    End Sub


#End Region

1 个答案:

答案 0 :(得分: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将使您进入相同的界面。

Attach to Process界面如下所示:

enter image description here

确保在界面中选中了蓝色突出显示的复选框。完成后,在列表中搜索您的服务名称。找到服务后,只需在列表中选择该服务,然后点击Attach按钮即可。 VS会经历一些事情,一旦完成,程序应该在我们之前设置的断点处中断。

然后你可以将x设置为false以提前退出或等待30秒并像平常一样单步执行代码。

你有它。按照这些步骤,您应该能够通过您创建的任何Windows服务进行调试。