【问题标题】:Windows Service ConnectionString property has not been initialized?Windows 服务 ConnectionString 属性尚未初始化?
【发布时间】:2015-10-12 16:26:52
【问题描述】:

我正在尝试使用 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 failed (System.InvalidOperationException: the ConnectionString property has not been initialized.)

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 服务中工作?

如果有人有问题帮助我查明我的问题,我可以在下面的 cmets 中提供更多信息,在此先感谢!

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

#Region "  Constructors  "

    Public Sub New()

    End Sub


#End Region

【问题讨论】:

  • 为什么你的连接字符串硬编码在你的代码中间?它应该在您的配置文件中。异常发生在哪一行?
  • 嗨,肖恩,我尝试添加一个配置文件,它也动态地转到该文件,但是当我将它放在 Windows 服务下的 app.config 中时,我得到了所有相同的错误。此行发生异常:futurePayment.FutureTransactionID = sqlReader.GetInt32(sqlReader.GetOrdinal("BMW_TRANSACTION_ID"))
  • 你确定吗?这行:Dim futurePayment As New FuturePayment 对我来说只是可疑的。 FuturePayment 构造函数中有什么?
  • 这只是一个默认构造函数,我已经编辑了我的帖子并将构造函数添加到底部。 FuturePayment 的所有属性也是公开的。
  • 有人在这里有类似的问题(查看异常)stackoverflow.com/questions/1129479/… 并且答案可能对他有帮助。也许尽量不要使用 using statemant 来测试它。

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


【解决方案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 &lt; timeout And x 行上设置一个断点以供以后使用。

您的OnStart 处理程序应该做的第一件事是调用WaitForDebugging 方法。

有了这些,您就可以像平常一样编译和安装 Windows 服务了。安装服务后,只需像往常一样启动它。

这里的情况会与您习惯的有所不同。而不是您的服务快速启动,进度条会出现挂起,这是完全正常和预期的。您需要做的是在启动服务时在 VS 中打开您的解决方案。启动服务后,立即切换到 VS(甚至在进度条挂起之前),然后转到 Tools -&gt; Attach to Process。如果您使用的是 VB.NET 的默认组合键设置,那么使用 Ctrl + Alt + P 将使您进入相同的界面。

附加到进程界面如下所示:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多