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

时间:2012-03-15 10:16:52

标签: asp.net vb.net multithreading iis iis-7.5

我一直在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

然后我从代码隐藏中的方法调用它,如:

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()

2 个答案:

答案 0 :(得分:1)

我普遍同意这里的建议。更具体地说,我会设置这些电子邮件的队列(及其组成部分),这些电子邮件需要在Web应用程序端发送出去。这使它可以快速写入数据库并完成。

第二部分是使用机制检查队列(上述数据库中的表)并处理出站电子邮件。简单的选项包括一个无窗口的控制台式应用程序,它在Windows中的任务计划执行时执行此操作,每隔几分钟唤醒一次以检查队列等的Windows服务,等等。

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

答案 1 :(得分:-1)

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

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

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