2011-04-20 108 views
1

我开发了一个基于长轮询方法或Comet的实时打分应用程序,因为他们也称之为。我已经使用在IIS 6上运行的ASP.NET 4.0(windows 2003 - 只有两个CPU,这对池中线程的可用性没有多大帮助)。在asp.net中处理.csv文件的异步http处理程序

数据以.csv格式显示,粘贴到Web服务器上的源文件夹中,然后使用Microsoft JET 4.0 OleDb Provider导入并使用不同方法显示,具体取决于应用程序的一部分。

长轮询部分的引擎依赖于IHttpAsyncHandler.由于它是一个实时评分应用程序,用户访问网站,获取当前数据的常规响应,并在body load上通过jquery ajax发送一个新请求给异步http处理程序。

该处理程序然后将请求存储在队列中,并且(通常)将该线程返回到线程池。一旦发生这种情况,我会创建一个手动重置事件,并保留该操作,同时创建一个文件系统观察器对象并发送它以查找csv数据源文件夹中的更改。

一旦它触发onChange事件,我设置手动重置事件,并允许异步操作恢复,获取新的,刷新的csv文件并用新数据响应客户端。

如果我一直没有收到错误,这将会很好。一般来说,非常非常普遍的方式,应用程序正在工作,但我有一个问题,我不能很明确地指出。

也就是说,我不确定问题是否与访问csv文件有关,因为它们可能会被进入服务器的进程锁定(ftp从运动场所转移)。或者它可能是我的(ab)使用IHttpAsyncHandler,也可能只是我没有足够的CPU和线程(我很难相信,因为我每天只有大约3000位独立访问者,吨知道小时数)。

是否有可能具有两个CPU的IIS 6 Windows 2003不能支持这种类型的应用程序?

这里就是我不断收到错误:

事件类型:错误事件来源: ASP.NET 4.0.30319.0事件类别: 无事件ID:1325日期:20/04/2011 时间:15:33:14用户:N/A计算机:xxx 说明:未处理的异常 发生,并且进程终止了 。

应用程序ID:/ LM/W3SVC/1/ROOT 进程ID:5264例外: System.Data.OleDb.OleDbException 消息:未指定的错误

堆栈跟踪:在 System.Data.OleDb.OleDbConnectionInternal ..ctor(OleDbConnectionString 构造,OleDbConnection的连接)
在 System.Data.OleDb.OleDbConnectionFactory.CreateConnection(DbConnectionOptions 选项,对象poolGroupProviderInfo, 池类DBConnectionPool,的DbConnection owningOb ject) System.Data.ProviderBase.DbConnectionFactory。CreateNonPooledConnection(的DbConnection owningConnection, DbConnectionPoolGroup poolGroup)在 System.Data.ProviderBase.DbConnectionFactory.GetConnection(的DbConnection owningConnection)在 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(的DbConnection outerConnection,DbConnectionFactory connectionFactory的)在 系统。 Data.OleDb.OleDbConnection.Open() 在Broker.brCSV.readCSV(字符串 文件名)在 SwatchTiming.AsynchOperation.StartAsyncTask(对象 workItemState)在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(对象 状态)在 System.Threading.ExecutionContext.runTryCode(对象 的UserData)在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup在 System.Threading.ExecutionContext.RunInternal(ExecutionContext中 的ExecutionContext(TryCode 代码,CleanupCode backoutCode,对象 的UserData), ContextCallback 回调在 System.Threading.ExecutionContext.Run(的ExecutionContext 的ExecutionContext,ContextCallback 回调,对象的状态,对象的状态),布尔 ignoreSyncCtx)在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

而且也:

事件类型:错误事件来源:.NET运行时 4.0错误报告事件 类别:无事件ID:5000日期: 20/04/2011时间:15:33:14用户: N/AComputer:xxx说明:EventType clr20r3,P1 w3wp.exe,P2 6.0。 3790 .3959,P3 45d6968e,P4 system.data,P5 4.0.0.0,P6 4ba1e064, P7 1ea3,P8 87,P9 system.data.oledb.oledbexception,P10 NIL。有关详细信息,请参阅帮助 和支持中心 http://go.microsoft.com/fwlink/events.asp.Data:0000: 63 00 6C 00 72 00 32 00
clr2.0008:30 00 72 00 33 00 2C 00 0.r.3,0010:20 00 77 00 33 00 77 00 .w.3.w.0018:70 00 2e 00 65 00 78 00
p ... ex0020:65 00 2c 00 20 00 36 00 e。,。 .6.0028:2e 00 30 00 2e 00 33 00 ..0 ... 3.0030:37 00 39 00 30 00 2e 00 7.9.0 ... 0038:33 00 39 00 35 00 39 00 3.9.5.9.0040 :2c 00 20 00 34 00 35 00,。 .4.5.0048:64 00 36 00 39 00 36 00 d.6.9.6.0050:38 00 65 00 2c 00 20 00 8.e。,。 .0058:73 00 79 00 73 00 74 00 syst0060:65 00 6d 00 2e 00 64 00 em..d.0068:61 00 74 00 61 00 2c 00 ata,.0070:20 00 34 00 2e 00 30 00 .4 ... 0.0078:2e 00 30 00 2e 00 30 00
..0 ... 0.0080:2c 00 20 00 34 00 62 00 ,...。 .4.b.0088:61 00 31 00 65 00 30 00 a.1.e.0.0090:36 00 34 00 2c 00 20 00 6.4。,。 .0098:31 00 65 00 61 00 33 00 1.e.a.3.00a0:2c 00 20 00 38 00 37 00,。 .8.7.00a8:2c 00 20 00 73 00 79 00 ,。 .s.y.00b0:73 00 74 00 65 00 6d 00 s.t.e.m.00b8:2e 00 64 00 61 00 74 00 ..d.a.t。00c0:61 00 2e 00 6f 00 6c 00 a ... ol00c8:65 00 64 00 62 00 2e 00 edb..00d0:6f 00 6c 00 65 00 64 00 oled00d8:62 00 65 00 78 00 63 00 bexc00e0:65 00 70 00 74 00 69 00 epti00e8:6f 00 6e 00 20 00 4e 00 .N.00f0:49 00 00 4C 0D 0A 00 00 IL ....

和...

事件类型:错误事件来源:.NET运行时 事件类别:无事件ID: 1026日期:20/04/2011时间:15时34分26秒 用户:N/A计算机:XXX 描述:应用程序:w3wp.exe的 Framework版本:v4.0.30319 说明:这个过程是 终止由于未处理 exception.Exception信息: System.Data.OleDb.OleDbException

堆栈:在 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(System.Data.Common.DbConnection, System.Data.ProviderBase.DbConnectionFactory) 在 System.Data。 OleDb.OleDbConnection.Open() 在Broker.brCSV.readCSV在 [ProjectNamespace] .AsynchOperation.StartAsyncTask(System.Object的)(System.String) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object的) 在 System.Threading.ExecutionContext.runTryCode(System.Object) 在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode,System.Object的)在 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object的)在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object的,布尔值)在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 系统.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.P erformWaitCallback()

最后几条信息。我试图微调IIS 6,但似乎没有太多帮助。

因此,有没有人有一个想法是什么,以及为什么我的网站每五分钟崩溃?

编辑:这是我在处理程序代码,希望这有助于

BeginProcessRequest如下(比我只设置IsReusable为false等):

Public Function BeginProcessRequest(_ 
    ByVal context As System.Web.HttpContext, _ 
    ByVal cb As System.AsyncCallback, _ 
    ByVal extraData As Object) _ 
    As System.IAsyncResult _ 
    Implements System.Web.IHttpAsyncHandler.BeginProcessRequest 

    Dim asynch As New AsynchOperation(cb, context, extraData) 
    asynch.StartAsyncWork() 

    Return asynch 
End Function 

,然后::

Class AsynchOperation 
Implements IAsyncResult 
Private _completed As Boolean 
Private _state As [Object] 
Private _callback As AsyncCallback 
Private _context As HttpContext 
Private mre As New ManualResetEvent(False) 
Dim br As New Broker.brCSV 
Dim brLiveGames As New Broker.brLiveGames 

ReadOnly Property IsCompleted() As Boolean _ 
     Implements IAsyncResult.IsCompleted 
    Get 
     Return _completed 
    End Get 
End Property 

ReadOnly Property AsyncWaitHandle() As WaitHandle _ 
     Implements IAsyncResult.AsyncWaitHandle 
    Get 
     Return Nothing 
    End Get 
End Property 

ReadOnly Property AsyncState() As [Object] _ 
     Implements IAsyncResult.AsyncState 
    Get 
     Return _state 
    End Get 
End Property 

ReadOnly Property CompletedSynchronously() As Boolean _ 
     Implements IAsyncResult.CompletedSynchronously 
    Get 
     Return False 
    End Get 
End Property 

Public Sub New(ByVal callback As AsyncCallback, _ 
     ByVal context As HttpContext, _ 
     ByVal state As [Object]) 
    _callback = callback 
    _context = context 
    _state = state 
    _completed = False 
End Sub 

Public Sub StartAsyncWork() 
    ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf StartAsyncTask), Nothing) 
End Sub 

Private Sub StartAsyncTask(ByVal workItemState As [Object]) 


    Dim fsw As New FileSystemWatcher("D:\ClientRoot\Swatchtiming\bv\ReadData\") 
    fsw.NotifyFilter = NotifyFilters.LastWrite 
    AddHandler fsw.Changed, AddressOf OnChanged 
    fsw.EnableRaisingEvents = True 
    fsw.IncludeSubdirectories = False 

    Dim aTimer As New System.Timers.Timer 
    AddHandler aTimer.Elapsed, AddressOf OnTimerChanged 
    aTimer.Interval = 60000 
    aTimer.Enabled = True 
    mre.WaitOne() 

    Dim rdr As OleDbDataReader 
    Dim i As Integer = 0 
    Dim eventName As String = "" 
    Dim dsFiles As DataSet = brLiveGames.getFileNameWithEventTitle() 
    Dim teamClass As String = "TeamA" 
    Dim serveIndicator As String = "" 
    Dim serveImage As String = "" 
    Dim serveSpeed As String = "" 
    Dim fileName As String = "" 
    Dim fileNumber As String = "" 
    Dim matchID As String = "" 
    Dim venueLocation As String = "" 
    Dim set1, set2, set3 As String 

    For i = 0 To Convert.ToInt16(dsFiles.Tables(0).Rows.Count) - 1 
     If eventName <> dsFiles.Tables(0).Rows(i).Item("EventTitle") Then 
      eventName = dsFiles.Tables(0).Rows(i).Item("EventTitle") 
      _context.Response.Write("<div class='eventTitle'>" & eventName.ToString() & " <span class='bracketLink'>- <a href='Brackets.aspx?Brackets=" & dsFiles.Tables(0).Rows(0).Item("BracketsFile") & "'>View brackets</a></span></div>") 
     End If 
     rdr = br.readCSV(dsFiles.Tables(0).Rows(i).Item("fileName")) 

     _context.Response.Write("<div class='matchView'>") 
     While (rdr.Read) 
      matchID = rdr.Item("Current_Match_Index") 
      If venueLocation <> "" Then 
       venueLocation = "" 
      Else 
       venueLocation = br.getVenueLocation(matchID) 
       _context.Response.Write("<div class='matchTitle'>" + venueLocation + "</div>") 
      End If 
      set1 = IIf(IsDBNull(rdr.Item("SET_1")), "&nbsp;", rdr.Item("SET_1")) 
      set2 = IIf(IsDBNull(rdr.Item("SET_2")), "&nbsp;", rdr.Item("SET_2")) 
      set3 = IIf(IsDBNull(rdr.Item("SET_3")), "&nbsp;", rdr.Item("SET_3")) 
      _context.Response.Write("<div class='" & teamClass & "'>") 
      If teamClass <> "TeamB" Then 
       teamClass = "TeamB" 
      Else 
       teamClass = "TeamA" 
      End If 
      serveIndicator = IIf(IsDBNull(rdr.Item("Service_Indicator")), "", rdr.Item("Service_Indicator")) 
      If serveIndicator = "" Then 
       serveImage = "<img src='images/css/serveIndicatorNone.png' alt='#' width='14' height='14' />" 
      Else 
       serveImage = "<img src='images/css/serveIndicator.png' alt='#' width='14' height='14' />" 
      End If 
      serveSpeed = IIf(IsDBNull(rdr.Item("Serve_Speed")), "&nbsp;", "Serve: " & rdr.Item("Serve_Speed") & " km/h") 
      _context.Response.Write("<div class='flag'><img src='images/flags/" & rdr.Item("NOC") & ".jpg' alt='" & rdr.Item("NOC") & "' width='22' height='14' /></div><div class='NOC'>" & rdr.Item("NOC") & "</div><div class='serveIndicator'>" & serveImage & "</div><div class='teamName'>" & rdr.Item("Short_Team_Name") & "</div><div class='set1'>" & set1 & "</div><div class='set2'>" & set2 & "</div><div class='set3'>" & set3 & "</div><div class='serveSpeed'>" & serveSpeed & "</div>") 
      _context.Response.Write("</div>") 
     End While 
     _context.Response.Write("</div>") 
     rdr.Close() 
    Next 
    fsw.Dispose() 
    dsFiles.Dispose() 
    _context.Response.End() 

    _completed = True 
    _callback(Me) 

End Sub 

Private Sub OnChanged(ByVal sender As Object, ByVal e As FileSystemEventArgs) 
    mre.Set() 
End Sub 

Private Sub OnTimerChanged(ByVal sender As Object, ByVal e As ElapsedEventArgs) 
    mre.Set() 
End Sub 

End Class 

编辑#2:用于Broker.brCSV.readCSV(文件名)的代码

Public Function readCSV(ByVal fileName As String) As OleDbDataReader 
    Dim rdr As OleDbDataReader = Nothing 
    Dim folderName = ("FolderName") 
    Dim cnString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & folderName & ";Extended Properties='text;HDR=Yes;FMT=Delimited';Mode=3" 

    Dim cn As New OleDb.OleDbConnection(cnString) 
    Dim cm As New OleDb.OleDbCommand("Select * from " & fileName, cn) 
    cm.Connection.Open() 
    rdr = cm.ExecuteReader(System.Data.CommandBehavior.CloseConnection) 

    Return rdr 
End Function 

请注意连接字符串的结束,特别是Mode参数。 msdn指出,这是您如何指定文件访问权限,但可能是因为我没有以正确的方式解释指令......即,mode=3应该指定文件访问为读/写,但我是不知道它是否有效。

编辑#3:新Broker.brCSV.readCSV()引发InvalidOperationException

按照那种帮手Smudge202我已经改变了Broker.brCSV.readCSV方法的代码的建议如下:

Public Function readCSV(ByVal fileName As String) As OleDbDataReader 
    Dim folderName = ("Folder Name") 
    Dim cnString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & folderName & ";Extended Properties='text;HDR=Yes;FMT=Delimited';Mode=3" 

    Using cn As New OleDb.OleDbConnection(cnString) 
     Using cm As New OleDb.OleDbCommand("Select * from " & fileName, cn) 
      cm.Connection.Open() 
      Dim rdr As OleDbDataReader = cm.ExecuteReader(System.Data.CommandBehavior.CloseConnection) 
      Return rdr 
     End Using 
    End Using 

End Function 

然而,测试时这些代码引起以下错误:

事件类型:错误 事件来源:ASP.NET 4.0 .30319.0 事件类别:无 事件ID:1325 日期:22/04/2011 时间:8点46分33秒 用户:N/A 计算机:EUW0002184 描述: 未处理的异常发生,并且该过程是终止。

应用程序ID:/ LM/W3SVC/1/ROOT

进程ID:6408

异常:System.InvalidOperationException

消息:无效试图调用读取时读取器被关闭。

堆栈跟踪:在System.Data.OleDb.OleDbDataReader.Read() 在SwatchTiming.AsynchOperation.StartAsyncTask(对象workItemState) 在System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(对象状态) 在System.Threading.ExecutionContext。 runTryCode(对象的UserData) 在System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode代码,CleanupCode backoutCode,对象的UserData) 在System.Threading.ExecutionContext.RunInternal(的ExecutionContext的ExecutionContext,ContextCallback回调,对象状态) 在的System.Threading .ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态,布尔ignoreSyncCtx) 在System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem。ExecuteWorkItem() 在System.Threading.ThreadPoolWorkQueue.Dispatch() 在System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

还有:

事件类型:错误 事件来源:.NET运行 事件类别:无 事件ID:1026 日期:22/04/2011 时间:8时47分53秒 用户:N/A 计算机:EUW0002184 说明: 应用程序:w3wp.exe的 Framework版本:v4.0.30319 描述:由于未处理的异常而终止该进程。 异常信息信息:System.InvalidOperationException 堆栈: 在System.Data.OleDb.OleDbDataReader.Read() 在SwatchTiming.AsynchOperation.StartAsyncTask(System.Object的) 在System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object的) 在系统.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,系统。)System.Threading.ExecutionContext.runTryCode(System.Object) 在System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode,CleanupCode,System.Object) (System.Threading.ExecutionContext,System.Threading.ContextCallback,System.Object,Boolean) 在System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在System.Threading.ThreadPoolWorkQueue.Dispatch() 在System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

所以,当处理程序试图使用新的readCSV方法我得到这些错误...任何进一步的建议? :)谢谢涂抹,谢谢其他人!

+0

你的异常的堆栈跟踪,似乎在OLEDB提供程序予以指点,我相信这是你用来读取传入的CSV文件的供应商?您在什么阶段从CSV文件中获取数据?从你的描述中可以看出,有几个线程试图同时使用提供程序,这会导致提供程序中出现IoException异常(尽管我希望在栈跟踪中看到这种说法是诚实的)。另外,(请原谅冗长的评论),IHttpAsyncHandler的等待句柄持有的线程在接收到信号时仍然存在? (超时?) – Smudge202 2011-04-20 19:08:27

+0

@ Smudge202 谢谢您的回复涂抹。一旦文件系统观察者注意到源文件夹中的更改,我将获取数据。我将编辑我的文章,以便我可以添加代码,以便您可以仔细查看它,如果您愿意......再次感谢! – pzelenovic 2011-04-20 21:30:45

+0

感谢您添加您的代码。您是否也可以添加“Broker.brCSV.readCSV(String fileName)”的代码,这是您在StartAsyncTask中调用的导致问题的函数(请参阅stacktrace)。夫妇多点。循环不需要转换为Int16,Rows.Count已经是一个整数。此外,您可以完全清除计时器并使用重载的mre.WaitOne(msTimeout)。将它与Dim filesChanged组合为Boolean = mre.WaitOne(60000)来确定文件是否确实发生了变化? – Smudge202 2011-04-21 08:26:33

回答

1

除了一个两个评论到目前为止我已经添加了.... =)

,正如你在第3编辑已经注意到,一旦读者已经设置,您将无法取回来自它的数据。

这个想法是你创建并打开你的连接。连接打开时尽可能早地获取数据,然后处理一旦获得数据后使用的所有资源。

在你的情况下,你打开和关闭readCSV函数内的连接,然后将封闭的阅读器传递回“StartAsyncTask”。你也许可以做的是轻微的重构...而不是使用OleDbDataReader你可以使用OleDbDataAdapter。使用适配器,您可以调用Fill method来填充数据集。

一旦数据集被填充,它就在内存中。您可以关闭适配器,关闭连接,处理这两个('使用'语句)并将数据集传递回StartAsync方法?

评论这里如果你需要任何这样的例子。

祝你好运!

编辑:

关于您正在进行的多线程工作的简要说明...

关于IIS设置,如果你是在一个以上的进程中运行你的网站要知道,在某个阶段,你将可能有2个进程(或更多)坐着等待文件系统观察。当FSW检测到更改时,它会通知您的两个过程;以不可预知的顺序,但可能会快速连续,这反过来会导致两个独立的线程开始读取文件。您可以在此阶段遇到问题时,两个线程请求Jet提供在同一时间打开相同的文件(S)。确保你有足够的异常捕获逻辑来帮助。

如果您遇到这种情况,您甚至可能需要考虑使用mutexes,以便一次允许一个进程处理结果,但我很少鼓励这些进程。

关于线程异常的说明,请看看this article,我相信在IIS7.5/.Net中仍然适用。4.对于工作线程要非常小心,如果没有捕获,异常可能会使网站失效。

+0

感谢您的持续支持。我希望你至少得到一些精神上的满足:)无论如何,关于IIS设置,我没有启用应用程序使用两个进程(它被称为我想的网络花园)。通过文件访问的初始问题(以及“另一个进程已经锁定文件”的信息)进行教导,如果我只启用运行应用程序的多个进程,则同样的事情可能会发生,这对我来说是合乎逻辑的。我准备了一个2.0版本的建议,并会在今晚进行测试。我会让你知道它是如何解决的... – pzelenovic 2011-04-22 14:23:19

+0

除此之外,有趣的是,在另一个操作中,我确实使用了oledbdataadapter,但不是基本的一个......当然,这部分应用程序从来没有造成我任何问题:)因此我的昵称,我猜... – pzelenovic 2011-04-22 14:24:53

+0

哈哈,至少你已经有了使用适配器的所有模板代码。纠正Web花园笔记,如果您需要这种方法,我会建议将FSW代码删除并放入WCF服务中,以允许单个OOP进程管理这些文件。和以前一样,祝你好运。 – Smudge202 2011-04-22 14:38:00