FeedBack-страничка
Я долго колебался, выкладывать ли эту страничку, ибо я не люблю раскрывать всякие критические технологии, связанные с криптографией и прочими подобными фишками, но потом все-таки решился. Ведь этот сайт рассчитан не на дураков, а умные люди и так знают множество способов решения поставленной задачи.
Я расскажу на этой страничке, один из простейших способов организации FeedBack-странички в ASP2:
Для начала, нам потребуется вот такой контрольчик:
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Image.aspx.vb" Inherits="Control_Image" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml" > 00006: <head runat="server"> 00007: <title>Untitled Page</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: эта страничка - просто способ записать в поток браузера в формате IMAGE/BMP</div> 00013: </form> 00014: </body> 00015: </html>
00001: Partial Class Control_Image 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: Dim X As Drawing.Bitmap 00006: Try 00007: X = Session("Image") 00008: Response.ContentType = "image/bmp" 00009: X.Save(Response.OutputStream, Drawing.Imaging.ImageFormat.Gif) 00010: Catch ex As Exception 00011: ' 00012: End Try 00013: End Sub 00014: End Class
Фактически, это просто вывод графики в поток браузера. Второй контрол тоже несложный - фон на цифры тут наложен простейшим образом.
00001: <%@ Control Language="VB" AutoEventWireup="false" CodeFile="Sender.ascx.vb" Inherits="Control_Sender" %> 00002: <asp:Label ID="L1" runat="server" Font-Names="sans-serif" Font-Size="X-Small" Text="Для отправки сообщения введите это число: "></asp:Label> 00003: <asp:Image ID="I1" runat="server" ImageUrl="~/Control/Image.aspx" /> 00004: <asp:Label ID="L2" runat="server" Font-Names="sans-serif" Font-Size="X-Small" Text="и подтвердите ввод: "></asp:Label> 00005: <asp:TextBox ID="T1" runat="server" MaxLength="4" Width="64px"></asp:TextBox> 00006: <asp:Button ID="B1" runat="server" Text="Я не робот." /> 00007: <asp:RegularExpressionValidator ID="REV1" runat="server" ControlToValidate="T1" ErrorMessage="Четыре символа, плиз." 00008: Font-Names="sans-serif" Font-Size="X-Small" ValidationExpression="\S\S\S\S"></asp:RegularExpressionValidator>
00001: 'контрол генерации четырех цифр верменного пароля и проверки корректности их ввода 00002: Partial Class Control_Sender 00003: Inherits System.Web.UI.UserControl 00004: 00005: Public Event Send() 00006: 00007: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00008: If Not IsPostBack Then 00009: Call NewPass() 00010: End If 00011: End Sub 00012: 00013: Protected Sub B1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles B1.Click 00014: If T1.Text.ToUpper = Session("Password") Then 00015: RaiseEvent Send() 00016: Else 00017: SH.Common.ErrorMessage(Me.Page, "Подбор пароля", T1.Text) 00018: Call NewPass() 00019: End If 00020: End Sub 00021: 00022: Private Sub NewPass() 00023: Dim GU As Guid = Guid.NewGuid 00024: Dim GS As String = GU.ToString 00025: Dim G4 As String = GS.Substring(0, 4).ToUpper 00026: Dim X As New Drawing.Bitmap(60, 20) 00027: Dim G As Drawing.Graphics = Drawing.Graphics.FromImage(X) 00028: G.Clear(Drawing.Color.White) 00029: G.DrawLine(Drawing.Pens.SkyBlue, 0, 0, 60, 20) 00030: G.DrawLine(Drawing.Pens.Red, 0, 10, 30, 20) 00031: G.DrawLine(Drawing.Pens.Red, 30, 0, 60, 10) 00032: G.DrawLine(Drawing.Pens.SkyBlue, 0, 20, 60, 0) 00033: G.DrawLine(Drawing.Pens.Red, 0, 10, 30, 0) 00034: G.DrawLine(Drawing.Pens.Red, 30, 20, 60, 10) 00035: G.DrawString(G4, New Drawing.Font("", 20, Drawing.FontStyle.Italic, Drawing.GraphicsUnit.Pixel), Drawing.Brushes.DarkBlue, 0, -2) 00036: Session("Image") = X 00037: Session("Password") = G4 00038: End Sub 00039: End Class
Ну и наконец, страничка с критической технологией. Обратите внимание на обязательное использование здесь многопоточности.
00001: Partial Class Page5 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub Sender1_Send() Handles Sender1.Send 00005: SenderStat = Request.Params("ALL_RAW") & vbCrLf & vbCrLf & vbCrLf 00006: Dim X As New System.Threading.Thread(AddressOf SendMail) 00007: X.Start() 00008: Response.Redirect("~/Page51.aspx") 00009: End Sub 00010: 00011: Dim SenderStat As String = "" 00012: 00013: Private Sub SendMail() 00014: Dim Email As New System.Net.Mail.MailMessage("XXXXXXXXX@list.ru", "YYYYYYYYYY@mail.ru", "Soft-help.Ru", SenderStat & T1.Text) 00015: 'Email.IsBodyHtml=True 'для форматированной почты 00016: 'Email.Attachments.Add(New system.Net.Mail.Attachment(...)) 00017: Dim MailClient As New System.Net.Mail.SmtpClient() 00018: Dim basicAuthenticationInfo As New System.Net.NetworkCredential("UUUUUUUUU", "VVVVVVVVVV") 00019: MailClient.Host = "smtp.list.ru" 00020: MailClient.UseDefaultCredentials = False 00021: MailClient.Credentials = basicAuthenticationInfo 00022: Try 00023: MailClient.Send(Email) 00024: Catch ex As Exception 00025: SH.Common.ErrorMessage("SendMail", ex.Message) 00026: End Try 00027: End Sub 00028: End Class
Как видите, все просто и без изысков, но аутентификацию проходим на ура:
Эту идею тоже можно обернуть примерно в такой стандартный библиотечный модуль:
00001: Public Class Mail 00002: Public Shared Function Send(ByVal myMessage As String) As String 00003: Return Send(myMessage, "NoReply@sal.ch", "Error auf www.sal.ch", System.Configuration.ConfigurationManager.AppSettings("AdminEmail").ToString, False) 00004: End Function 00005: 00006: Public Shared Function Send(ByVal myMessage As String, ByVal Recipient As String) As String 00007: Return Send(myMessage, Recipient, "Error auf www.sal.ch", System.Configuration.ConfigurationManager.AppSettings("AdminEmail").ToString, False) 00008: End Function 00009: 00010: Public Shared Function Send(ByVal myMessage As String, ByVal Recipient As String, ByVal Subject As String) As String 00011: Return Send(myMessage, Recipient, Subject, System.Configuration.ConfigurationManager.AppSettings("AdminEmail").ToString, False) 00012: End Function 00013: 00014: Public Shared Function Send(ByVal myMessage As String, ByVal Recipient As String, ByVal Subject As String, ByVal ByFrom As String) As String 00015: Return Send(myMessage, Recipient, Subject, ByFrom, False) 00016: End Function 00017: 00018: Public Shared Function Send(ByVal myMessage As String, ByVal Recipient As String, ByVal Subject As String, ByVal ByFrom As String, ByVal TextOnly As Boolean) As String 00019: Dim EMail As New System.Net.Mail.MailMessage(Recipient, ByFrom) 00020: If TextOnly Then 00021: EMail.Body = myMessage 00022: EMail.IsBodyHtml = False 00023: Else 00024: EMail.Body = "<html><head><title></title></head> <body><font face=""Arial"">" & myMessage & " </font></body></html>" 00025: EMail.IsBodyHtml = True 00026: End If 00027: EMail.Subject = Subject 00028: Dim MailClient As New System.Net.Mail.SmtpClient() 00029: MailClient.UseDefaultCredentials = False 00030: Dim basicAuthenticationInfo As New System.Net.NetworkCredential _ 00031: (System.Configuration.ConfigurationManager.AppSettings("SMTP_Login"), _ 00032: System.Configuration.ConfigurationManager.AppSettings("SMTP_Pass")) 00033: MailClient.Host = System.Configuration.ConfigurationManager.AppSettings("SMTP_Sever") 00034: MailClient.Credentials = basicAuthenticationInfo 00035: Try 00036: MailClient.Send(EMail) 00037: Return "OK" 00038: Catch ex As Exception 00039: 'для WEB на HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog требует FULL Control для учетной записи ASP.NET и NETWORK SERVICE 00040: Dim LogMSG As New System.Text.StringBuilder("Error in MAIL Service <" & MailClient.Host & ">" & vbCrLf & ex.Message & vbCrLf) 00041: If Not (ex.InnerException Is Nothing) Then 00042: LogMSG.AppendLine(ex.InnerException.ToString) 00043: LogMSG.AppendLine() 00044: End If 00045: If Not (ex.StackTrace Is Nothing) Then 00046: LogMSG.AppendLine(ex.StackTrace) 00047: End If 00048: LogMSG.AppendLine() 00049: If Not (MailClient.Host Is Nothing) Then 00050: LogMSG.AppendLine("MailClient.Host:" & MailClient.Host & vbCrLf) 00051: End If 00052: If Not (MailClient Is Nothing) Then 00053: LogMSG.AppendLine("MailClient.Port:" & MailClient.Port & vbCrLf) 00054: End If 00055: LogMSG.AppendLine() 00056: If Not (EMail.From.Address Is Nothing) Then 00057: LogMSG.AppendLine("EMail.From.Address:" & EMail.From.Address & vbCrLf) 00058: End If 00059: If Not (EMail.To(0).Address Is Nothing) Then 00060: LogMSG.AppendLine("EMail.To(0).Address:" & EMail.To(0).Address & vbCrLf) 00061: End If 00062: If Not (EMail.Subject Is Nothing) Then 00063: LogMSG.AppendLine("EMail.Subject:" & EMail.Subject & vbCrLf) 00064: End If 00065: If Not (EMail.Body Is Nothing) Then 00066: LogMSG.AppendLine("EMail.Body:" & EMail.Body & vbCrLf) 00067: End If 00068: Dim Encoder As New Text.ASCIIEncoding 00069: If System.Web.HttpContext.Current Is Nothing Then 00070: System.Diagnostics.EventLog.WriteEntry("MailService", LogMSG.ToString, Diagnostics.EventLogEntryType.Error, 500, 1) 00071: Else 00072: System.Diagnostics.EventLog.WriteEntry("MailService", LogMSG.ToString, Diagnostics.EventLogEntryType.Error, 500, 1, Encoder.GetBytes(System.Web.HttpContext.Current.Request.Url.PathAndQuery)) 00073: End If 00074: Throw New Exception("Error in MAIL Service <" & MailClient.Host & ">" & vbCrLf & ex.Message & vbCrLf, ex) 00075: End Try 00076: End Function 00077: End Class
В таком случае мы получим чтение всех параметров из конфигурации и полную обработку ошибок. В форме странички с ошибкой, выданной юзеру и записи в журнал. Только обратите внимание на указанные выше необходимые разрешения для доступа к журналу системы.
Кстати то, что на заднем фоне - это самый первый мой Custom-контрол, написанный еще в 2004 году. Это вообще говоря, один из самых несовершенных примеров моего кода, лежащих на этом сайте. Я заранее говорю об этом. Он, вероятно, не потянет работу при МАССОВЫХ ошибках. Но он работает исключительно надежно и удобно в режиме отладки и не раз помогал мне. Я использовал его много раз - например тут при выкладывании сайта на хостинг он сразу же зафиксировал ошибку кошмара DLL, когда на хостинге присутсвовал NET.Framework 2, но сборка Бейсика имела совершенно ИНОЕ имя, чем обычно. Между тем стандартное сообщение в этом случае заключалось в том, что страничка просто отсутствовала. Хотя внешне страничка вполне присутствовала - она не могла ЛИШЬ быть ЗАПУЩЕНА, ибо не могли быть разрешены ССЫЛКИ на библиотеку поддержки бейсика с совершенно иным строгим именем.
Когда я столкнулся впервые с ситуацией кошмара DLL в NET.Framework 2.0 - я чуть с ума не сошел, пытаясь понять, почему же на хостинге сайт не работает. Однако этот контрол дает полный просмотр стека, и в последующих случаях с кошмаром DLL я уже сразу понимал, что дело не в остсутcтвии странички как таковой, и именно в невозможности ее запуска по причине ИНОГО строгого имени у того же самого компонента NET.FRAMEWORK в другой виндузне.
Для использования этот контрол обычно размещается на страничке обработки ошибок - ведь он еще и выводит все Сессион, чем гораздо удобнее стандартного сообщения об ошибке. Сгрузить этот контрол в готовом виде отсюда. Контрол надо добавить на панель ТулБоксов VS2005 и потом просто перетащить на форму обработки ошибок сайта и, главное, обеспечить его вызов из GLOBAL.ASaX
Далее приводится его текст в полном виде, однако не забудьте, чтоб он все показал, надо еще и указать это в Web-config (естественно при работе сайта в боевом режиме - делать это совсем не обязательно):
00001: Imports System 00002: Imports System.Collections.Generic 00003: Imports System.ComponentModel 00004: Imports System.Text 00005: Imports System.Web 00006: Imports System.Web.UI 00007: Imports System.Web.UI.WebControls 00008: 00009: 00010: <DefaultProperty("ErrorMessage")> _ 00011: <System.Drawing.ToolboxBitmap(GetType(AspErrorInfo), "i280.ico")> _ 00012: Public Class AspErrorInfo 00013: Inherits WebControl 00014: 00015: ''' <summary> 00016: ''' Этот метод должен быть вызван в Global.ASAX - Application_Error 00017: ''' </summary> 00018: Public Shared Sub ErrorRedirections() 00019: Dim ExceptionS As New System.Collections.Generic.SortedList(Of String, System.Exception()) 00020: ExceptionS.Add(System.Web.HttpContext.Current.Request.Url.PathAndQuery, System.Web.HttpContext.Current.AllErrors) 00021: Try 00022: System.Web.HttpContext.Current.Application("ErrorPages") = ExceptionS 00023: System.Web.HttpContext.Current.Response.Redirect("~/Error1.aspx") 00024: Catch ex As System.Exception 00025: System.Web.HttpContext.Current.Response.Write("Error page is missing") 00026: End Try 00027: System.Web.HttpContext.Current.Response.End() 00028: End Sub 00029: 00030: Dim _ErrorMessage As String 00031: <Bindable(False), Category("Misc"), DefaultValue("При выполнении вашего запроса возникла следующая ошибка:"), Localizable(True)> _ 00032: Public Property ErrorMessage() As String 00033: Get 00034: ErrorMessage = _ErrorMessage 00035: End Get 00036: Set(ByVal value As String) 00037: _ErrorMessage = value 00038: End Set 00039: End Property 00040: 00041: Dim _ErrorTitleDiv As String 00042: <Bindable(False), Category("Misc"), DefaultValue("<span style='font-size: normal; color: darkred'>"), Localizable(True)> _ 00043: Public Property ErrorTitleDiv() As String 00044: Get 00045: ErrorTitleDiv = _ErrorTitleDiv 00046: End Get 00047: Set(ByVal value As String) 00048: _ErrorTitleDiv = value 00049: End Set 00050: End Property 00051: 00052: Dim _ErrorMessageDiv As String 00053: <Bindable(False), Category("Misc"), DefaultValue("<span style='font-size: x-small; color: darkred'>"), Localizable(True)> _ 00054: Public Property ErrorMessageDiv() As String 00055: Get 00056: ErrorMessageDiv = _ErrorMessageDiv 00057: End Get 00058: Set(ByVal value As String) 00059: _ErrorMessageDiv = value 00060: End Set 00061: End Property 00062: 00063: Dim _ErrorPageDiv As String 00064: <Bindable(False), Category("Misc"), DefaultValue("<span style='font-size: large; color: black'>"), Localizable(True)> _ 00065: Public Property ErrorPageDiv() As String 00066: Get 00067: ErrorPageDiv = _ErrorPageDiv 00068: End Get 00069: Set(ByVal value As String) 00070: _ErrorPageDiv = value 00071: End Set 00072: End Property 00073: 00074: Dim _ErrorCountDiv As String 00075: <Bindable(False), Category("Misc"), DefaultValue("<span style='font-size: xx-small; color: black'>"), Localizable(True)> _ 00076: Public Property ErrorCountDiv() As String 00077: Get 00078: ErrorCountDiv = _ErrorCountDiv 00079: End Get 00080: Set(ByVal value As String) 00081: _ErrorCountDiv = value 00082: End Set 00083: End Property 00084: 00085: Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) 00086: Dim HtmlOut As New System.Text.StringBuilder 00087: Dim PageName As String 'страничка с ошибкой 00088: ' 00089: HtmlOut.Append(_ErrorTitleDiv & _ErrorMessage & "</span><br />") 00090: Dim ExceptionS As New Collections.Generic.SortedList(Of String, System.Exception()) 00091: If System.Web.HttpContext.Current.Application("ErrorPages") IsNot Nothing Then 00092: ExceptionS = System.Web.HttpContext.Current.Application("ErrorPages") 00093: If ExceptionS.Count >= 1 Then 00094: PageName = ExceptionS.Keys(0) 00095: HtmlOut.Append(_ErrorPageDiv & PageName.ToString & "</span><br>") 00096: HtmlOut.Append(_ErrorCountDiv ) 00097: 'в месте до слеша выводится общий список необработанных ошибок приложения в данный момент времени (в запросах всех юзеров) 00098: If ExceptionS.Count > 1 Then HtmlOut.Append("(" & ExceptionS.Count.ToString) 00099: ' 00100: If System.Configuration.ConfigurationManager.AppSettings("FullErrorMesssage") IsNot Nothing Then 00101: If System.Configuration.ConfigurationManager.AppSettings("FullErrorMesssage") Then 00102: If ExceptionS.Item(PageName) IsNot Nothing Then 00103: 'выводится только ОДНА из общего списка ошибок, возникших от выполнения запроса 00104: 'однако в метке после слеша выводится общее количество ошибок запроса 00105: If ExceptionS.Count > 1 Then 00106: HtmlOut.Append(" / " & ExceptionS.Item(PageName).Length & " ) </span") 00107: Else 00108: HtmlOut.Append("</span>") 00109: End If 00110: HtmlOut.Append(_ErrorMessageDiv) 00111: HtmlOut.Append(ExceptionS.Item(PageName)(0).Message) 00112: If Not (ExceptionS.Item(PageName)(0).Source Is Nothing) Then 00113: HtmlOut.AppendLine() 00114: HtmlOut.AppendLine(ExceptionS.Item(PageName)(0).Source) 00115: End If 00116: If Not (ExceptionS.Item(PageName)(0).InnerException Is Nothing) Then 00117: HtmlOut.AppendLine() 00118: HtmlOut.AppendLine(ExceptionS.Item(PageName)(0).InnerException.ToString) 00119: End If 00120: If Not (ExceptionS.Item(PageName)(0).StackTrace Is Nothing) Then 00121: HtmlOut.AppendLine() 00122: HtmlOut.AppendLine(ExceptionS.Item(PageName)(0).StackTrace) 00123: End If 00124: HtmlOut.Replace(vbCrLf, "<br />") 00125: HtmlOut.Append("</span>") 00126: End If 00127: 'далее выведем все сесиионные переменные при возникновении ошибки 00128: If System.Web.HttpContext.Current.Session.Count > 0 Then 00129: HtmlOut.Append("<table border=1>") 00130: For Each Key As String In System.Web.HttpContext.Current.Session.Keys 00131: If System.Web.HttpContext.Current.Session.Item(Key) Is Nothing Then 00132: HtmlOut.Append("<tr><td>" & Key & "</td><td>Nothing</td></tr>") 00133: Else 00134: HtmlOut.Append("<tr><td>" & Key & "</td><td>" & System.Web.HttpContext.Current.Session.Item(Key).ToString & "</td></tr>") 00135: End If 00136: Next 00137: HtmlOut.Append("</table>") 00138: End If 00139: Else 00140: If ExceptionS.Item(PageName) IsNot Nothing Then HtmlOut.Append(_ErrorMessageDiv & System.Web.HttpContext.Current.Server.HtmlEncode(ExceptionS.Item(PageName)(0).Message).ToString & "</span>") 00141: End If 00142: Else 00143: If ExceptionS.Item(PageName) IsNot Nothing Then HtmlOut.Append(_ErrorMessageDiv & System.Web.HttpContext.Current.Server.HtmlEncode(ExceptionS.Item(PageName)(0).Message).ToString & "</span>") 00144: End If 00145: 'выведенное сообщение об ошибке удалили из списка ошибок приложения 00146: ExceptionS.Remove(PageName) 00147: System.Web.HttpContext.Current.Application("ErrorPages") = ExceptionS 00148: output.Write(HtmlOut.ToString) 00149: End If 00150: End If 00151: 00152: End Sub 00153: End Class
Параметры контролу можно задать так:
00001: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00002: AspErrorInfo1.ErrorCountDiv = "<span style='font-size: xx-small; color: black'>" 00003: AspErrorInfo1.ErrorMessage = "При выполнении вашего запроса возникла ошибка:" 00004: AspErrorInfo1.ErrorMessageDiv = "<span style='font-size: x-small; color: darkred'>" 00005: AspErrorInfo1.ErrorPageDiv = "<span style='font-size: large; color: black'>" 00006: AspErrorInfo1.ErrorTitleDiv = "<span style='font-size: normal; color: darkred'>" 00007: End Sub
|