我一直在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()
答案 0 :(得分:1)
我普遍同意这里的建议。更具体地说,我会设置这些电子邮件的队列(及其组成部分),这些电子邮件需要在Web应用程序端发送出去。这使它可以快速写入数据库并完成。
第二部分是使用机制检查队列(上述数据库中的表)并处理出站电子邮件。简单的选项包括一个无窗口的控制台式应用程序,它在Windows中的任务计划执行时执行此操作,每隔几分钟唤醒一次以检查队列等的Windows服务,等等。
由于Windows服务对您正在做的事情感觉有点沉重,并且由于控制台应用程序的速度原型,我建议您转向控制台应用程序方向。这使您可以非常轻松地在开发,测试和生产环境中测试运行时间和性能,同时减少环境迁移规划的开销。
答案 1 :(得分:-1)
问题在于你传递给线程函数的WindowsIndentity。在Web应用程序中的ASP.NET上,在请求线程完成后释放安全上下文。这在实践中意味着在后台/长时间运行的线程中传递的WindowsIdentity变得不可操作(例如,访问Name属性会导致错误)。
如果电子邮件发件人线程要求它在请求用户的安全范围内运行(出于委派等目的),则必须将代码包装在使用WCF发布的服务中。 WCF IIS主机与分叉线程上的安全上下文相关。 (根据我的经验,Visual Studio Web Dev服务器也是如此)
另一方面,如果您只是使用WindowsIndentity的属性而不是简单地在请求线程中收集它们,而是将此集合传递给后台线程。