استخدام ELMAH في تطبيق وحدة التحكم
-
20-08-2019 - |
سؤال
لقد بدأت للتو في استخدام ELMAH وأنا من المعجبين به.يدعم فريقي عددًا كبيرًا من تطبيقات الويب، وأنا متحمس بشكل خاص لأن ELMAH يتيح لنا حفظ الاستثناءات من كل تطبيق في نفس جدول قاعدة بيانات MS SQL.
نحن ندعم أيضًا عددًا قليلاً من تطبيقات وحدة التحكم وDLL وسطح المكتب.هل من الممكن استخدام ELMAH DLL لتسجيل الاستثناءات في هذه التطبيقات إلى نفس الموقع؟
المحلول
لدينا بالضبط نفس الوضع هنا. تشغيل ELMAH لجميع التطبيقات على شبكة الإنترنت. وهناك عدد قليل منهم يكون المنظمون على أساس وحدة التحكم.
وبعد القيام ببعض الحفر خلال التعليمات البرمجية المصدر، يبدو أن التعليمات البرمجية التالية إلى العمل:
ErrorLog errorLog = ErrorLog.GetDefault(null);
errorLog.ApplicationName = "/LM/W3SVC/1/ROOT/AppName";
errorLog.Log(new Error(ex));
والمشكلة الحقيقية الوحيدة مع ما ورد أعلاه هو أنك بحاجة للحفاظ على اسم التطبيق في مكان ما في التكوين الخاص لتكون قادرة على مشاهدة الإدخالات على المشاهد ELMAH.axd.
وحتى في منطقتنا عام معالجة رمز خطأ نقوم به:
if (HttpContext.Current != null)
ErrorSignal.FromCurrentContext().Raise(ex);
else
{
ErrorLog errorLog = ErrorLog.GetDefault(null);
errorLog.ApplicationName = ErrorHandling.Application;
errorLog.Log(new Error(ex));
}
نصائح أخرى
ونحن بحاجة إلى القدرة على تسجيل من تطبيق وحدة التحكم وخدمة ويندوز بالإضافة إلى موقع ASP.NET لدينا. لقد استخدمت الجواب (ErrorLog.GetDefault(null);
) التي عملت بشكل جيد حتى أنا في حاجة إلى البريد الإلكتروني أيضا.
وهكذا، وهنا هو بلدي الحل. أنه يتعامل مع سجل والبريد الإلكتروني وتويتر والتصفية (سواء في ملف التكوين وفي التعليمات البرمجية). لقد ملفوفة أيضا الدعوة الرئيسية كامتداد لاستثناء لذلك يمكن أن يسمى مثل: catch(Exception ex) { ex.LogToElmah(); }
لتصفية في التعليمات البرمجية، ربط المقابلة .Filtering الحدث: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);
والرمز:
وusing System;
using System.Web;
using Elmah;
namespace System
{
public static class ElmahExtension
{
public static void LogToElmah(this Exception ex)
{
if (HttpContext.Current != null)
{
ErrorSignal.FromCurrentContext().Raise(ex);
}
else
{
if (httpApplication == null) InitNoContext();
ErrorSignal.Get(httpApplication).Raise(ex);
}
}
private static HttpApplication httpApplication = null;
private static ErrorFilterConsole errorFilter = new ErrorFilterConsole();
public static ErrorMailModule ErrorEmail = new ErrorMailModule();
public static ErrorLogModule ErrorLog = new ErrorLogModule();
public static ErrorTweetModule ErrorTweet = new ErrorTweetModule();
private static void InitNoContext()
{
httpApplication = new HttpApplication();
errorFilter.Init(httpApplication);
(ErrorEmail as IHttpModule).Init(httpApplication);
errorFilter.HookFiltering(ErrorEmail);
(ErrorLog as IHttpModule).Init(httpApplication);
errorFilter.HookFiltering(ErrorLog);
(ErrorTweet as IHttpModule).Init(httpApplication);
errorFilter.HookFiltering(ErrorTweet);
}
private class ErrorFilterConsole : ErrorFilterModule
{
public void HookFiltering(IExceptionFiltering module)
{
module.Filtering += new ExceptionFilterEventHandler(base.OnErrorModuleFiltering);
}
}
}
}
وبالإضافة إلى ذلك، سوف تحتاج إلى إضافة إشارة إلى System.Web.dll
في المشروع لهذا العمل.
تعديل : لوفقا لتعليقات، وإرسال رسائل البريد الإلكتروني هذا الرمز إلا إذا ملف التكوين لديه <errorMail async="false"/>
. الرجوع إلى هذا المقتطف أن كنت تريد أن تبقي <errorMail async="true"/>
في ملف التكوين الخاص بك (ليتم استخدامها عند HttpContext.Current غير متاح ).
إذا كنت ترغب فقط في البريد الإلكتروني سجل دون HTTP يمكنك القيام به مثل هذا:
public class MyElmahMail: ErrorMailModule
{
public MyElmahMail()
{
//this basically just gets config from errorMail (app.config)
base.OnInit(new HttpApplication());
}
public void Log(Error error)
{
//just send the email pls
base.ReportError(error);
}
}
//to call it
var mail = new MyElmahMail();
mail.Log(new Error(new NullReferenceException()));//whatever exception u want to log
ومن حيث app.config
//Under configSections
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
و
<elmah>
<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="C:\Elmah.Error" applicationName="MyAwesomeApp" />
<errorMail from="from@email.com" to="to@email.com" />
</elmah>
وإعدادات بروتوكول نقل البريد من اختيارك.
وكل ذلك. : -)
يحرر:هذا يستطيع يجب القيام به - انظر هذا إجابة.
أنا متأكد من أنك لا تستطيع أن تفعل هذا.سأحاول وحفر المواد ذات الصلة.
إذن مما يمكنني العثور عليه من البحث في مجموعة Google هو أنه ليس من الممكن ...وبما أن ELMAH يعمل خارج HttpHandlers (بنية asp.net)، فهو ASP.NET فقط.
ومع ذلك، هناك طرق يمكنك من خلالها الاستفادة منها في تطبيق وحدة التحكم.يوفر ELMAH طريقة لرفع الأخطاء، بحيث يمكنك تضمين ELMAH في معالجة الاستثناءات ثم الإشارة إلى خطأ عبر:
ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
قد يعني هذا تغليف التطبيق بالكامل في معالج الاستثناء والإشارة.قد يتطلب الأمر بعض التغيير والتبديل للحصول عليه، لكنني أعتقد أنه ممكن تمامًا.
وفي حال كنت بحاجة لذلك، وهذا هو الرابط إلى مستودع رمز ELMAH.
لتلك التي تحتاج إلى إجابة براين فرصة لاستدار إلى VB.NET:
Imports System
Imports System.Web
Imports Elmah
Namespace System
Public NotInheritable Class ElmahExtension
Private Sub New()
End Sub
<System.Runtime.CompilerServices.Extension> _
Public Shared Sub LogToElmah(ex As Exception)
If HttpContext.Current IsNot Nothing Then
ErrorSignal.FromCurrentContext().Raise(ex)
Else
If httpApplication Is Nothing Then
InitNoContext()
End If
ErrorSignal.[Get](httpApplication).Raise(ex)
End If
End Sub
Private Shared httpApplication As HttpApplication = Nothing
Private Shared errorFilter As New ErrorFilterConsole()
Public Shared ErrorEmail As New ErrorMailModule()
Public Shared ErrorLog As New ErrorLogModule()
Public Shared ErrorTweet As New ErrorTweetModule()
Private Shared Sub InitNoContext()
httpApplication = New HttpApplication()
errorFilter.Init(httpApplication)
TryCast(ErrorEmail, IHttpModule).Init(httpApplication)
errorFilter.HookFiltering(ErrorEmail)
TryCast(ErrorLog, IHttpModule).Init(httpApplication)
errorFilter.HookFiltering(ErrorLog)
TryCast(ErrorTweet, IHttpModule).Init(httpApplication)
errorFilter.HookFiltering(ErrorTweet)
End Sub
Private Class ErrorFilterConsole
Inherits Elmah.ErrorFilterModule
Public Sub HookFiltering([module] As Elmah.IExceptionFiltering)
AddHandler [module].Filtering, New Elmah.ExceptionFilterEventHandler(AddressOf MyBase.OnErrorModuleFiltering)
End Sub
End Class
End Class
End Namespace
ولكن، لمجرد تسجيل الأخطاء إلى قاعدة البيانات، وهذا سوف يكون كافيا:
If System.Web.HttpContext.Current Is Nothing Then
Dim req As System.Web.HttpRequest = New System.Web.HttpRequest(String.Empty, "https://www.domain.tld", Nothing)
Dim res As System.Web.HttpResponse = New System.Web.HttpResponse(Nothing)
System.Web.HttpContext.Current = New System.Web.HttpContext(req, res)
'Dim request As System.Web.Hosting.SimpleWorkerRequest = New System.Web.Hosting.SimpleWorkerRequest("/blah", "c:\inetpub\wwwroot\blah", "blah.html", Nothing, New System.IO.StringWriter())
'System.Web.HttpContext.Current = New System.Web.HttpContext(request)
System.Web.HttpContext.Current.ApplicationInstance = New System.Web.HttpApplication()
Dim ErrorLog As New Elmah.ErrorLogModule()
TryCast(ErrorLog, System.Web.IHttpModule).Init(System.Web.HttpContext.Current.ApplicationInstance)
End If
وكما حلا كاملا:
Public parent As Elmah.ServiceProviderQueryHandler = Nothing
' http://stackoverflow.com/questions/5981750/configuring-elmah-with-sql-server-logging-with-encrypted-connection-string
Public Function Elmah_MS_SQL_Callback(objContext As Object) As System.IServiceProvider
Dim container As New System.ComponentModel.Design.ServiceContainer(parent(objContext))
Dim strConnectionString As String = COR.SQL.MS_SQL.GetConnectionString()
Dim log As Elmah.SqlErrorLog = New Elmah.SqlErrorLog(strConnectionString)
'Dim strApplicationName = System.Web.Compilation.BuildManager.GetGlobalAsaxType().BaseType.Assembly().FullName
Dim strApplicationName As String = System.Reflection.Assembly.GetExecutingAssembly().FullName
If Not String.IsNullOrEmpty(strApplicationName) Then
log.ApplicationName = strApplicationName.Substring(0, strApplicationName.IndexOf(","))
End If
container.AddService(GetType(Elmah.ErrorLog), log)
Return container
End Function ' Elmah_MS_SQL_Callback
Public Function Elmah_PG_SQL_Callback(objContext As Object) As System.IServiceProvider
Dim container As New System.ComponentModel.Design.ServiceContainer(parent(objContext))
Dim strConnectionString As String = COR.SQL.MS_SQL.GetConnectionString()
Dim log As Elmah.PgsqlErrorLog = New Elmah.PgsqlErrorLog(strConnectionString)
'Dim strApplicationName = System.Web.Compilation.BuildManager.GetGlobalAsaxType().BaseType.Assembly().FullName
Dim strApplicationName As String = System.Reflection.Assembly.GetExecutingAssembly().FullName
If Not String.IsNullOrEmpty(strApplicationName) Then
log.ApplicationName = strApplicationName.Substring(0, strApplicationName.IndexOf(","))
End If
container.AddService(GetType(Elmah.ErrorLog), log)
Return container
End Function ' Elmah_PG_SQL_Callback
' http://weblogs.asp.net/stevewellens/archive/2009/02/01/debugging-a-deployed-site.aspx
Public Sub Initialize()
If System.Web.HttpContext.Current Is Nothing Then
Dim req As System.Web.HttpRequest = New System.Web.HttpRequest(String.Empty, "https://www.domain.tld", Nothing)
Dim res As System.Web.HttpResponse = New System.Web.HttpResponse(Nothing)
System.Web.HttpContext.Current = New System.Web.HttpContext(req, res)
'Dim request As System.Web.Hosting.SimpleWorkerRequest = New System.Web.Hosting.SimpleWorkerRequest("/blah", "c:\inetpub\wwwroot\blah", "blah.html", Nothing, New System.IO.StringWriter())
'System.Web.HttpContext.Current = New System.Web.HttpContext(request)
System.Web.HttpContext.Current.ApplicationInstance = New System.Web.HttpApplication()
Dim ErrorLog As New Elmah.ErrorLogModule()
TryCast(ErrorLog, System.Web.IHttpModule).Init(System.Web.HttpContext.Current.ApplicationInstance)
End If
parent = Elmah.ServiceCenter.Current
If SQL.IsMsSql Then
Elmah.ServiceCenter.Current = AddressOf Elmah_MS_SQL_Callback
End If
If SQL.IsPostGreSql Then
Elmah.ServiceCenter.Current = AddressOf Elmah_PG_SQL_Callback
End If
End Sub ' InitializeElmah
و
Elmah.ErrorSignal.FromCurrentContext().Raise(New NotImplementedException("Test"))
وستعمل إذا كان يتم استدعاء بعد تهيئة ()
حسنا، لأنني لا أستطيع التعليق أنا ما بعد هذا إلى هنا، وربما شخص ما سوف نرى ذلك.
وبعد اتباع طريقة براين وcommentors وكنت قادرا على الحصول على البريد الإلكتروني يعمل ولكن ما زلت لم رؤية الرسائل SQL يتم تسجيل، حتى ولو كنت قد حددت اسم التطبيق. ما لم أكن أدرك أن كانوا في الواقع يتم تسجيل أنا فقط لم رؤيتهم لأن APPLICATIONNAME يجب أن يكون نفس الملف web.config الخاص بك من أجل أن يكون قادرا على مشاهدته.
وبلدي الملف web.config لم يكن لديهم APPLICATIONNAME محددة، لذلك كان التعثر إلى "/ LM / W3SVC / 2 / ROOT"، الذي هو في الأساس ما علق "asgeo1"، على الرغم من أنني لم أكن أدرك أنه كان لابد من نفسه.
وبما أنني لم يكن لديك حقا أي أخطاء كنت المعنية، وتكوين APPLICATIONNAME في بلدي الملف web.config وبلدي app.config أن تكون هي نفسها، والآن كل شيء يظهر وكأنه بطل.
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" />
وELMAH لتقف على وحدات تسجيل خطأ ومعالجات - اشارة، بطبيعة الحال، إلى IHttpModule
وIHttpHandler
وحدة التحكم لا تستخدم HTTP، لذلك عادة لا تكون قادرة على الاستفادة من ذلك بكثير من وحدات معالجات بنيت لHTTP.