线程不是在服务器上的ASP.Net中启动的,但在本地工作正常

线程不是在服务器上的ASP.Net中启动的,但在本地工作正常,asp.net,vb.net,multithreading,iis,iis-7.5,Asp.net,Vb.net,Multithreading,Iis,Iis 7.5,我第一次在ASP.Net应用程序中使用线程时遇到了一个问题 当我在本地运行代码时,代码运行良好,但一旦我上传到我们的开发服务器,它就不会运行,但也不会出错 我做了一些研究,发现我应该让线程模拟WindowsIdentity,我已经这样做了,但线程仍然不起作用,我还尝试增加IIS中的最大线程数,但仍然没有结果 我假设问题出在IIS上,因为这是我的本地机器和服务器之间唯一不同的地方,但我没有IIS方面的经验,因此我完全被困在这方面,因此任何帮助都将不胜感激 我正在Windows 2008 R2上运行

我第一次在ASP.Net应用程序中使用线程时遇到了一个问题

当我在本地运行代码时,代码运行良好,但一旦我上传到我们的开发服务器,它就不会运行,但也不会出错

我做了一些研究,发现我应该让线程模拟WindowsIdentity,我已经这样做了,但线程仍然不起作用,我还尝试增加IIS中的最大线程数,但仍然没有结果

我假设问题出在IIS上,因为这是我的本地机器和服务器之间唯一不同的地方,但我没有IIS方面的经验,因此我完全被困在这方面,因此任何帮助都将不胜感激

我正在Windows 2008 R2上运行IIS 7.5

在新线程上执行的方法位于App_Code文件夹中的类中,如下所示:

Public Class RosterEmailer
      Inherits System.Web.UI.Page

      Dim thisID As String
      Dim thisName As String
      Dim strDutyStartDate As date
      Dim thisWorkEmail As String
      Dim thisHomeEmail As String
      Dim mailbody As string
   Dim Sec As Object 

   Public sub Ini(ByVal _thisID As String, 
                       ByVal _thisName As String, 
                       ByVal _strDutyStartDate As date,
                       ByVal _thisWorkEmail As String,
                       ByVal _thisHomeEmail As String,
                       ByVal _mailbody As string,
                       ByVal _security As Object)

      thisID = _thisID 
      thisName = _thisName 
      strDutyStartDate = _strDutyStartDate 
      thisWorkEmail = _thisWorkEmail 
      thisHomeEmail = _thisHomeEmail 
      mailbody = _mailbody 
      Sec = _security 

   End Sub

   Public Sub SendMail()

    Dim id as  System.Security.Principal.WindowsIdentity  = CType(Sec,System.Security.Principal.WindowsIdentity)
      id.Impersonate()
               'Dim response As System.Web.HttpResponse = System.Web.HttpContext.Current.Response

               'Declare the SMTP server we are going to use 
               Dim smtp As New SmtpClient("192.168.20.11")
               Dim cred As NetworkCredential = New NetworkCredential("domain\\username","mypassword")
               smtp.DeliveryMethod = SmtpDeliveryMethod.Network
               smtp.Credentials = cred

               Dim mail As New MailMessage()

               ' create email
               mail.From = New MailAddress("rostering@ourdomain.com")
               mail.To.Add(thisWorkEmail)
               mail.CC.Add(thisHomeEmail)

               mail.Subject = thisName + " Roster from our company for " + strDutyStartDate.Month.ToString() + "_" + strDutyStartDate.Year.ToString()

               mail.IsBodyHtml = True

               mail.Priority = MailPriority.High

               mail.Body = mailbody

               Dim strURL As String = "http://blueprintdev/Opsproject/Ops/rosteroutput.aspx?InstructorID=" & thisID.ToString() & "&Instructor=" & thisName.ToString() & "&Start=" & strDutyStartDate

               Dim holder As String = String.Empty 

               Dim uu As New Uri(strURL,UriKind.Absolute)
               Dim rq As HttpWebRequest = WebRequest.Create(uu)
               Dim res As HttpWebResponse = rq.GetResponse() 
               Dim stream1 As Stream = res.GetResponseStream()

               Using r1 As StreamReader = New StreamReader(stream1,Encoding.UTF8)
                  holder = r1.ReadToEnd()
               End Using

               Dim pdfConverter As PdfConverter = New PdfConverter
               pdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4
               pdfConverter.PdfDocumentOptions.PdfPageOrientation = PDFPageOrientation.Landscape
               pdfConverter.PdfDocumentOptions.PdfCompressionLevel = PdfCompressionLevel.Normal
               pdfConverter.PdfDocumentOptions.ShowHeader = True
               pdfConverter.PdfDocumentOptions.ShowFooter = True
               pdfConverter.PdfDocumentOptions.LeftMargin = 5
               pdfConverter.PdfDocumentOptions.RightMargin = 5
               pdfConverter.PdfDocumentOptions.TopMargin = 5
               pdfConverter.PdfDocumentOptions.BottomMargin = 5
               pdfConverter.PdfDocumentOptions.GenerateSelectablePdf = True

               pdfConverter.PdfDocumentOptions.ShowHeader = False
               pdfConverter.PdfFooterOptions.FooterText = ("Printed on " & Now())
               pdfConverter.PdfFooterOptions.FooterTextColor = Color.DarkBlue
               pdfConverter.PdfFooterOptions.FooterTextFontSize = "10"

               pdfConverter.PdfFooterOptions.FooterTextFontType = PdfFontType.Helvetica
               pdfConverter.PdfFooterOptions.DrawFooterLine = True
               pdfConverter.PdfFooterOptions.PageNumberText = "Page"
               pdfConverter.PdfFooterOptions.PageNumberTextFontType = PdfFontType.Helvetica
               pdfConverter.PdfFooterOptions.PageNumberTextFontSize = "10"
               pdfConverter.PdfFooterOptions.ShowPageNumber = True
               pdfConverter.LicenseKey = "theKeyGoesHere"

               Dim downloadBytes() As Byte = pdfConverter.GetPdfBytesFromHtmlString("<font face='verdana' size='1'>" & holder)

               Dim stream As Stream = New MemoryStream(downloadBytes)

               Dim filename As String = thisName + "_Roster_" + strDutyStartDate.Month.ToString() + "_" + strDutyStartDate.Year.ToString() + ".pdf"

               ' add pdf to email
               Dim att As Attachment = New Attachment(stream, filename, MediaTypeNames.Application.Pdf.ToString())

               mail.Attachments.Add(att)
               ' send email
               smtp.Send(mail)
   End Sub
End Class

问题在于传递到线程函数的WindowsIndentity。在ASP.NET的web应用程序中,安全上下文在请求线程完成后释放。实际上,这意味着在后台/长时间运行的线程中传递的WindowsIdentity将不可操作(例如,访问Name属性将导致错误)

如果电子邮件发送者线程要求它在请求用户的安全范围内运行(出于委派等目的),则必须将代码包装到使用WCF发布的服务中。WCF IIS主机属于分叉线程上的安全上下文。(根据我的经验,Visual Studio Web开发服务器也是如此)


另一方面,如果您只是想使用WindowsIdentity的属性,而不是简单地在请求线程中收集它们,并将此集合传递给后台线程。

我大体上同意这里的建议。更具体地说,我将设置一个需要在web应用程序端发送的电子邮件队列(及其组成部分)。这允许它对数据库执行快速写入,并且可以完成

第二部分是使用一种机制来检查队列(前面提到的DB中的表)并处理出站电子邮件。简单的选项包括一个无窗口控制台风格的应用程序,在Windows中由任务计划执行时执行此操作,一个每隔几分钟醒来检查队列的Windows服务,等等


由于Windows服务对您正在做的事情感觉有点沉重,并且由于控制台应用程序原型的速度,我建议您选择控制台应用程序方向。这还允许您非常轻松地在开发、测试和生产环境中测试运行时和性能,同时减少环境迁移规划的开销。

ASP.NET web应用程序不是熟悉线程的好地方,尤其是因为您永远不应该真正需要这样做,否则,但不仅限于,这是一个“错误”的环境。请看我在这里使用线程,因为我需要发送大约150封电子邮件,每封邮件都有一个生成并添加的PDF,然后发送电子邮件,不使用线程,这需要大约5分钟,浏览器超时,使用线程大约需要28秒。这只是不将项目分解为适当部分的借口。使用线程,只是不要在这里。如果这里不使用线程,你会建议我如何完成这个任务?你读了我发布的链接了吗?
Dim sec As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()

       Dim emailer As RosterEmailer = New RosterEmailer()
       emailer.Ini(thisID,thisName,strDutyStartDate,thisWorkEmail,thisHomeEmail,body,sec) 

       Dim Thr As System.Threading.Thread = New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf emailer.SendMail))

       Thr.Start()