نظرات مطالب
نکاتی در مورد ELMAH
در همان مطلب معرفی عنوان شده، داریم:
 <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
در اینجا مقدار path را بجای elmah.axd تغییر بدید به هر نام دیگری که علاقمند بودید.
مطالب
ELMAH و حملات XSS
ASP.NET جهت مقابله با حملات XSS بطور پیش‌فرض از ورود تگ‌های HTML جلوگیری می‌کند و در صورتی که ورودی کاربر شامل این تگ‌ها باشد، HttpRequestValidationException صادر می‌گردد. لاگ کردن و بررسی این خطاها جهت آگاهی از وجود حمله بی اهمیت نیست. اما متأسفانه ELMAH که به عنوان معمول‌ترین ابزار ثبت خطاها کاربرد دارد این نوع Exceptionها را ثبت نمی‌کند. دلیل آن هم این است که ELMAH در رویه‌های درونی خود اقدام به خواندن ورودی‌های کاربر می‌کند و در این هنگام اگر ورودی کاربر نامعتبر باشد، Exception مذکور صادر می‌شود و فرصتی برای ادامه روند و ثبت خطا باقی نمی‌ماند. به هر حال ضروری است که این نقیصه را خودمان جبران کنیم. راه حل افزودن یک فیلتر سفارشی برای ثبت خطاها به شکل زیر است (ASP.NET MVC):
public class ElmahRequestValidationErrorFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        if (context.Exception is HttpRequestValidationException)
           ErrorLog.GetDefault(HttpContext.Current).Log(new Error(context.Exception));
    }
}
فیلتر فوق باید در Global.asax معرفی شود:
public static void RegisterGlobalFilters (GlobalFilterCollection filters)
{
    filters.Add(new ElmahRequestValidationErrorFilter());
    filters.Add(new HandleErrorAttribute());
}
به این ترتیب HttpRequestValidationException هم بعد از این در سیستم ELMAH ثبت خواهد شد.
نظرات مطالب
LocalDB چیست؟
در کد زیر اگر کانکشن استرینگ را کامنت کنم بانک ساخته می‌شود و مشکلی ندارد در غیر این صورت پیغام خطای زیر را می‌دهد:
A file activation error occurred. The physical file name 'tax.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation.

CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
فایل app.config :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
  
  <connectionStrings>
    <clear/>
    <add name="Context"
         connectionString="Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True; AttachDBFilename=tax.mdf"
         providerName="System.Data.SqlClient"
           />
  </connectionStrings>



  <entityFramework>
   
     <defaultConnectionFactory  type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters >
        <parameter value="v11.0"/>
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
  
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup></configuration>

نظرات مطالب
UrlRewriter توسط Intelligencia.UrlRewriter
با تشکر از شما،
مشکل را پیدا کردم. فکر کنم برای IIS‌های از 6 به بالا باید به سبک زیر تنظیم بشه .
  
<configuration>
<configSections>
    <section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
  </configSections>
  
 <system.webServer>
    <modules>
      <add type="Intelligencia.UrlRewriter.RewriterHttpModule,Intelligencia.UrlRewriter" name="UrlRewriter" />
    </modules>
  </system.webServer>

  <rewriter>
    <rewrite url="^.*-T([0-9]+)/?$*" to="~/ShowTerol.aspx?ID=$1" processing="stop" />
  </rewriter>
</configuration>


مطالب
مدیریت استثناءها در Blazor Server - قسمت دوم
در قسمت اول دیدیم که توسط Error boundary می‌توان استثناءها را در Blazor مدیریت کرد؛ اما اگر بخواهیم قدری سفارشی‌تر عمل کرده و علاوه بر نمایش پیغام خطای مناسب به صورت جاوا اسکریپتی، استثنای رخ داده را لاگ کنیم چطور؟
خبر خوب اینکه این مهم نیز به راحتی امکان پذیر است؛ با استفاده از مفهوم CascadingValueها.
یک کامپوننت Error.razor به شکل زیر ایجاد می‌کنیم:
@using Microsoft.Extensions.Logging
@inject ILogger<Error> Logger
@inject IJSRuntime jsRuntime

<CascadingValue Value="this">
    @ChildContent
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public void ProcessError(Exception ex)
    {
        Logger.LogError("Error:ProcessError - Type: {Type} Message: {Message}", 
            ex.GetType(), ex.Message);
        jsRuntime.ToastrError("متاسفانه خطایی رخ داد");
        //StateHasChanged();
    }
}
همانطور که مشخص است این کامپوننت سفارشی توسط متد ProcessError می‌تواند خطاها را با استفاده از logger توکار Blazor لاگ نموده و پیغام خطای جاوااسکریپتی نمایش دهد. بدیهی است که می‌توان از لاگ کننده‌های دیگری نظیر Serilog، Elmah و حتی لاگ کننده‌های سفارشی دیگر نیز برای لاگ کردن در این متد بهره جست.
از StateHasChanged زمانی استفاده خواهد شد که متد پردازش خطا می‌خواهد به صورت مستقیم در رندر شدن رابط کاربری کامپوننتی که در آن استثنایی رخ داده‌است، دخالت کند. برای مثال زمانیکه می‌خواهیم تغییری در عناصر رندر شده صفحه، بعد از خطا ایجاد کنیم (رنگ دکمه ای عوض شود یا رنگ فونت برچسب یا تکست باکس یا ...).
حال کامپوننت App.razor را به شکل زیر ویرایش می‌نماییم:
<Error>
    <Router ...>
        ...
    </Router>
</Error>
در حقیقت کامپوننت Router را توسط کامپوننت سفارشی خودمان (Error) محصور می‌کنیم تا کامپوننت Error به صورت آبشاری به هر کامپوننت برنامه که Error را به صورت [ CascadingParameter ]  درنظر بگیرد منتقل شود.
حال فقط کافی است برای پردازش خطاها به شکل زیر در کامپوننت‌های دیگر عمل نمود:
@code {
    [CascadingParameter]
    public Error? Error { get; set; }

    private void CreatePost()
    {
        try
        {           
           throw new InvalidOperationException("پست ساخته نشد!");            
        }
        catch (Exception ex)
        {
            Error?.ProcessError(ex);
        }
    }
}
همینطور که ملاحظه می‌نمایید کامپوننت Error به عنوان یک CascadingParameter تعریف شده‌است و در یک بلاک try catch متد ProcessError کامپوننت Error صدا زده شده و استثنای صادر شده به آن ارسال شده‌است. در مثال من کامپوننت Error فقط یک متد پردازش خطا دارد. بدیهی است که این کامپوننت می‌تواند چندین متد پردازش خطای سفارشی دیگر نیز برای مقاصد مختلف داشته باشد.
پاسخ به بازخورد‌های پروژه‌ها
عدم استفاده از try catch
خطاهای احتمالی توسط Elmah لاگ می‌شوند و یک پیعام خطای عمومی به کاربر نمایش داده می‌شود.
مطالب
ثبت جزئیات استثناهای Entity framework توسط ELMAH
در حین بروز استثناهای Entity framework، می‌توان توسط ابزارهای Logging متنوعی مانند ELMAH، جزئیات متداول آن‌ها را برای بررسی‌های آتی ذخیره کرد. اما این جزئیات فاقد SQL نهایی تولیدی و همچنین پارامترهای ورودی توسط کاربر یا تنظیم شده توسط برنامه هستند. برای اینکه بتوان این جزئیات را نیز ثبت کرد، می‌توان یک IDbCommandInterceptor جدید را طراحی کرد.


کلاس EfExceptionsInterceptor

در اینجا نمونه‌ای از یک پیاده سازی اینترفیس IDbCommandInterceptor را مشاهده می‌کنید. همچنین طراحی یک متد عمومی که می‌تواند به جزئیات SQL نهایی و پارامترهای آن دسترسی داشته باشد، در اینترفیس IEfExceptionsLogger ذکر شده‌است.
public interface IEfExceptionsLogger
{
    void LogException<TResult>(DbCommand command,
        DbCommandInterceptionContext<TResult> interceptionContext);
}

using System.Data.Common;
using System.Data.Entity.Infrastructure.Interception;
 
namespace ElmahEFLogger
{
    public class EfExceptionsInterceptor : IDbCommandInterceptor
    {
        private readonly IEfExceptionsLogger _efExceptionsLogger;
 
        public EfExceptionsInterceptor(IEfExceptionsLogger efExceptionsLogger)
        {
            _efExceptionsLogger = efExceptionsLogger;
        }
 
        public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
 
        public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
 
        public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
 
        public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
 
        public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
 
        public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            _efExceptionsLogger.LogException(command, interceptionContext);
        }
    }
}


تهیه یک پیاده سازی سفارشی از IEfExceptionsLogger توسط ELMAH

اکنون که ساختار کلی IDbCommandInterceptor سفارشی برنامه مشخص شد، می‌توان پیاده سازی خاصی از آن‌را جهت استفاده از ELMAH به نحو ذیل ارائه داد:
using System;
using System.Data.Common;
using System.Data.Entity.Infrastructure.Interception;
using Elmah;
 
namespace ElmahEFLogger.CustomElmahLogger
{
    public class ElmahEfExceptionsLogger : IEfExceptionsLogger
    {
        /// <summary>
        /// Manually log errors using ELMAH
        /// </summary>
        public void LogException<TResult>(DbCommand command,
            DbCommandInterceptionContext<TResult> interceptionContext)
        {
            var ex = interceptionContext.OriginalException;
            if (ex == null)
                return;
 
            var sqlData = CommandDumper.LogSqlAndParameters(command, interceptionContext);
            var contextualMessage = string.Format("{0}{1}OriginalException:{1}{2} {1}", sqlData, Environment.NewLine, ex);
 
 
            if (!string.IsNullOrWhiteSpace(contextualMessage))
            {
                ex = new Exception(contextualMessage, new ElmahEfInterceptorException(ex.Message));
            }
 
            try
            {
                ErrorSignal.FromCurrentContext().Raise(ex);
            }
            catch
            {
                ErrorLog.GetDefault(null).Log(new Error(ex));
            }
        }
    }
}
در اینجا شیء Command به همراه SQL نهایی تولید و پارامترهای مرتبط است. همچنین interceptionContext.OriginalException جزئیات عمومی استثنای رخ داده را به همراه دارد. می‌توان این اطلاعات را پس از اندکی نظم بخشیدن، به متد Raise مربوط به ELMAH ارسال کرد تا جزئیات بیشتری از استثنای رخ داده شده، در لاگ‌های آن ظاهر شوند.


استفاده از ElmahEfExceptionsLogger جهت طراحی یک Interceptor عمومی

   public class ElmahEfInterceptor : EfExceptionsInterceptor
    {
        public ElmahEfInterceptor()
            : base(new ElmahEfExceptionsLogger())
        { }
    }
برای استفاده از ElmahEfExceptionsLogger و تهیه یک Interceptor عمومی، می‌توان با ارث بری از کلاس Interceptor ابتدای بحث شروع کرد و وهله‌ای از ElmahEfExceptionsLogger را به سازنده‌ی آن تزریق نمود (یکی از چندین روش ممکن). سپس برای استفاده از آن کافی است به ابتدای متد Application_Start فایل Global.asax.cs مراجعه و در ادامه سطر ذیل را اضافه نمود:
 DbInterception.Add(new ElmahEfInterceptor());

پس از آن جزئیات کلیه استثناهای EF در لاگ‌های نهایی ELMAH به نحو ذیل ظاهر خواهند شد:




کدهای کامل این پروژه را از اینجا می‌توانید دریافت کنید:
ElmahEFLogger
نظرات مطالب
فشرده سازی خروجی فایلهای استاتیک سایت
- خیر.
- من دسترسی به سرور و کدهای شما برای دیباگ ندارم. از ELMAH استفاده کنید. شاید خطایی در کار باشد که با ELMAH لاگ می‌شود. شاید اصلا این روال فراخوانی نمی‌شود که بهتر است این نوع کدها را به یک http module منتقل کرد و نه اینکه مستقیما داخل global.asax.cs نوشت.
نظرات مطالب
عبارت using و نحوه استفاده صحیح از آن
مطلب جاری بیشتر به شبیه سازی try/finally معادل using که توسط کامپایلر به صورت خودکار تولید می‌شود مرتبط است نه try/catch کلی. بحث dispose خودکار اشیاء disposable و اینکه استفاده از using به دلیلی که عنوان شد مناسب نیست. بنابراین بجای using از SafeUsingBlock استفاده کنید (شبیه سازی بهتر کاری است که کامپایلر در پشت صحنه جهت معادل سازی یا پیاده سازی using انجام می‌دهد؛ اما بدون از دست رفتن استثناهای رخ داده). مابقی را هم ELMAH انجام می‌دهد.
اگر از using استفاده کنید و ELMAH، فقط خطاهای مرتبط با مثلا iTextSharp رو در لاگ‌ها خواهید یافت؛ مثلا شیء document آن dispose شده، اما خطا و مشکل اصلی که به کدهای ما مرتبط بوده و نه iTextSharp، این میان گم خواهد شد. اما با استفاده از SafeUsingBlock ، دلیل اصلی نیز لاگ می‌شود.