我正在尝试使用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
答案 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界面如下所示:
确保在界面中选中了蓝色突出显示的复选框。完成后,在列表中搜索您的服务名称。找到服务后,只需在列表中选择该服务,然后点击Attach
按钮即可。 VS会经历一些事情,一旦完成,程序应该在我们之前设置的断点处中断。
然后你可以将x
设置为false以提前退出或等待30秒并像平常一样单步执行代码。
你有它。按照这些步骤,您应该能够通过您创建的任何Windows服务进行调试。