8 قدم تا بارگذاری با تاخیر تصاویر در ASP.NET

در مورد تکنیک پس بارگذاری تصاویر یا بارگذاری با تاخیر تصاویر توضحیات کاملی را میتوانیداینجا مشاهده بفرمایید. در اینجا قصد داریم تا یک نمونه عملیاتی از این تکنیک را در ASP.NET با هم بررسی کنیم. برای انجام اینکار از پلاگین Lazy Load مربوط به jquery استفاده میکنیم. این پلاگین همراه پروژه نمونه وجود دارد ولی برای دریافت فایل و مشاهده توضیحات بیشتر میتوانید به سایت پلاگین مراجعه کنید.
آماده سازی محیط:
1- یک برنامه ASP.NETایجاد کنید و پوشه هایی با نام های Images و Scripts در آن ایجاد کنید.
2- فایل jquery و پلاگین مربوطه را درون پوشه Scripts قرار دهید.
3- تصاویر پیش فرض را ویندوز را به درون Images کپی کنید.
4- یک پوشه App_Themes به برنامه اضافه کنید و یک Theme به نام Default درون آن ایجاد کنید و تنظیمات زیر را به وب کانفیگ اضافه کنید تا برنامه از این Theme استفاده کند.
<pages styleSheetTheme="Default"></pages>

تا اینجا مراحل اولیه جهت آماده سازی محیط کار را انجام دادیم. از این پس مراحل زیر را طی میکنیم تا امکان بارگذاری با تاخیر تصاویر به وجود آید.
5- یک صفحه ASP.NET ایجاد کنید و ارجاعاتی به فایل های jquery و پلاگین به شکل زیر ایجاد کنید.

<script src="Scripts/jquery.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.lazyload.js" type="text/javascript"></script>

6- جهت فعال سازی پلاگین برای تصاویری که کلاس lazy  دارند، کد زیر را بعد از ارجاعات خود اضافه کنید. میتوانیم این پلاگین را به همه تصاویر اعمال کنیم. اما برای اینکه دست ما در انتخاب اینکه کدام تصاویر از این تکنیک استفاده کنند باز باشد، تصاویری که میخاهیم این قابلیت را داشته باشند، با کلاس lazy شناسایی میکنیم.
<script type="text/javascript">
    $(function () {
        $("img.lazy").lazyload();
    });
</script>
7- درون صفحه ASP.NET خود یک Repeaterبا مشخصات زیر قرار دهید.

<asp:Repeater ID="RepeaterImages" runat="server">
<HeaderTemplate><div id="albume-container"></HeaderTemplate>
    <ItemTemplate>
 
            <asp:Image CssClass="lazy" ID="Image" runat="server" ImageUrl="~/grey.gif" data-original='<%# Container.DataItem %>'
                Width="1024" Height="768" />
 
    </ItemTemplate>
    <FooterTemplate></div></FooterTemplate>
</asp:Repeater>

نکته ای که در تعریف بالا باید به آن دقت کنید اضافه کرد خاصیت data-original به تصویر است. به صورت پیشفرض بجای تصویر اصلی یک تصویر با انداز 1 در 1 پیکسل بسیار سبک در تصاویر انتخابی نمایش داده میشود و در هنگامی که نیاز به بارگذاری تصویر بود، آدرسی که در data-original قرار دارد دورن تصویر بارگذاری میشود.
8- قطعه کد زیر را برای بارگذاری لیستی از تصاویر و الصاق آن به Repeater درون کد برنامه خود قرار دهید.
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        LoadData();
    }
}
 
private void LoadData()
{
    string[] filesindirectory = Directory.GetFiles(Server.MapPath("~/Images"));
    List<String> images = new List<string>(filesindirectory.Count());
 
    foreach (string item in filesindirectory)
    {
        images.Add(Page.ResolveUrl( String.Format("~/Images/{0}", System.IO.Path.GetFileName(item))));
    }
 
    RepeaterImages.DataSource = images;
    RepeaterImages.DataBind();
 
}
کار تمام است. هم اکنون تصاویر شما تنها در صورتی که نیاز به مشاهده آنها باشد در صفحه دیده میشوند. این پلاگین قابلیت های جالب زیادی دارد مثلا اگر بخواهید کمی زود از رسیدن به تصویر، بارگذاری آن آغاز شود میتوانید از قطعه کد زیر استفاده کنید.
عدد 200 به این معنی است که اگه موقعیت صفحه به 200 پیکسلی تصویر رسید اقدام به بارگذاری تصویر نماید.
$("img.lazy").lazyload({ threshold: 200 });
برای دریافت اطلاعات بیشتر درباره این پلاگین به صفحه این پلاگین در اینجا مراجعه کنید.
برای دریافت برنامه نمونه به اینجا مراجعه کنید.
 به منظور سبک شدن فایل نمونه برنامه، تصاویر پیش فرض را از پوشه تصاویر حذف کردم. قبل از تست برنامه تصاویر دلخواه خود را درون این پوشه قرار دهید.
» ادامه مطلب

پیشگیری از دسترسی آی پی های غیر مجاز به سایت توسط HTTP Module

در قسمت قبل دیدیم که یکی از کاربرد های HTTP Moduleها بررسی های امنیتی است. فرض کنید سایتی دارید که میخواهید تنها آی پی های تعریف شده بتوانند به آن دسترسی پیدا کنند و آدرس های تعریف نشده امکان دسترسی به آن را نداشته باشند حتی اگر نام کاربری نیز داشته باشند فقط در شرایطی که در محل خاصی بودند بتوانند از امکانات سایت استفاده کنند.
در زیر ماژول مخصوص این کار را مشاهده میکنید.
public class AllowedIP : IHttpModule
{


    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        //به دست آوردن لیست آی پی های مجاز
        List<string> allowedIpList = GetIpList();
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;
        string userIp = context.Request.UserHostAddress;
        //بررسی وجود آی پی درخواست درهنده در لیست آی پی های مجاز
        if (!allowedIpList.Contains(userIp))
        {
            throw new HttpException(401, "AccessDenied");
        }

    }
    private List<string> GetIpList()
    {
        // در اینجا میتوانید لیست آی پی های مجاز را از هر منبعی به دست آورید.
        List<string> lst = new List<string>();
        lst.Add("192.168.0.1");
        lst.Add("192.168.0.2");
        lst.Add("192.168.0.3");
        lst.Add("192.168.0.4");
        lst.Add("192.168.0.5");
        return lst;
    }

    public void Dispose()
    {
        
    }
}
 
در این ماژول لیست آیپی های مجاز از منبع دلخواه به دست میآید و سپس با آیپی کاربر تطبیق داده میشود. در صورت غیر مجاز بود یک خطای عدم دسترسی صادر میشود.
میتوانید به کمک یک ماژول که خطاهای برنامه را لاگ میکند، این خطا را به همراه آی پی کاربری که به سایت شما دسترسی داشه لاگ کنید.
» ادامه مطلب

پیشگیری از اجرای مجدد رخ دادها هنگام رفرش کردن صفحه


مسئله: یک صفحه داریم که روی اون یک دکمه وجود دارد که وقتی روی دکمه کلیک میشه صفحه PostBack میشه و بعضی کارها انجام میشه. اما اگر یک بار این دکمه را فشار دهیم و بعد از اینکه کارهای ما درون صفحه انجام شد، صفحه رو رفرش کنیم، مجددا رویدادگردان مربوط به دکمه اجرا میشه و اطلاعات ما باز هم ثبت میشه. یعنی با اینکه ما صفحه را رفرش میکنیم ولی باز هم صفحه PostBack میشود و تمامی کار های مربوط به آخرین روالی که صفحه راPostBack کرده مجددا اجرا میشود. این اتفاق در زمانی که اطلاعات حساسی در صفحه ثبت میشود بسیار دردسرساز است.
راه حل: باید به وسیله کدی که سمت کلاینت و سرور وجود دارد و چک کردن این کد، رویداد گردانی را فعال یا غیر فعال کرد. قطعه کد این راه حل را مشاهده میکنید.
public string ClientCode
    {
        get
        {
            return ViewState["ClientCode"] != null ? ViewState["ClientCode"].
                   ToString(): string.Empty;            
        }
        set
        {
            ViewState["ClientCode"] = value;
        }
    }
    public string ServerCode
    {
        get
        {
            return Session["ServerCode"] != null ?  Session["ServerCode"].
                   ToString() : string.Empty;
        }
        set
        {
            Session["ServerCode"] = value;
        }
    }
    protected void Page_Load(object sender, EventArgs e)
    {

        PreventUnexpectedRePost();
    }

    private void PreventUnexpectedRePost()
    {                       
        if (!IsPostBack || ClientCode.Equals(ServerCode))
        {
            string code = Guid.NewGuid().ToString();
            ClientCode = code;
            ServerCode = code;
        }
        else
        {           
            Response.Redirect(Request.Url.ToString());
        }
    }

در این کد متغیر های ServerCode و ClentCode کدها را نگه داری میکندد و تابع PreventUnexpectedRePost مسئولیت پیشگیری از اجرای مجدد رویداد گردان را دارد.
در صورت نیاز میتوان این کد را در BasePage یا MasterPage قرار داد که در تمامی صفحات سایت اعمال شود.
ممکن است کاربر چندین صفحه از سایت را باز کند که در این صورت سرور کد و کلاینت کد همخوانی خود را از دست خواهد داد. برای رفع این مشکل میتوان به ازای هر صفحه یک مقداد را درون یک Dictionary قرار داد.
پ ن: این خبرنامه هایی که آدم عضو آنها میشه هر از چند گاهی میتونه مشکلات آدم رو حل کنه. :-)
» ادامه مطلب

مروری بر HTTP Modules و HTTP Handlers قسمت اول

طی آخرین پروژه ای اجرا کردم، در ابتدا به خاطر ساختار کاری که داشتم مشکلات فراوانی داشتم که با استفاده از http module ها و http handler ها این کارها رو خیلی راحت تر از اونی که فکرش رو میکردم انجام دادم. اما در طول اجرای این پروژه یه نکته ای توجه منو جلب کرد و اون این بود که خیلی از برنامه نویس های ما از وجود ماژول ها و هندلر ها بی خبر هستن و ازش استفاده نمکنن و یا اگر  مطلع هستن، فقط از اونها در حد سمپل های موجود استفاده کردن و در مورد عملکرد اونها خیلی کم مطلع هستن. برای همین تصمیم گرفتم طی چند مقاله به معرفی این امکانات و استفاده از اون ها بپردازم و امیدوارم که به دردتون بخوره.
در قسمت اول به معرفی کلی HTTP Modules و HTTP Handlers میپردازم. در قسمت های بعد تعدادی از ماژول ها و هندلرهایی که در طول کار خودم بهشون نیاز پیدا کردم رو به صورت عملی با هم بررسی میکنیم.
معرفی HTTP Modules و HTTP Handlers:
هرگاه یک درخواست به یک برنامه ASP.NET ارسال میشود، این درخواست به وسیله HTTP Handlerدریافت میگردد و پردازش لازم صورت میگیرد و پاسخ برای کاربر ارسال میگردد. عمومی ترین HTTP Handler موجود، مربوط به پردازش صفحات aspx میباشد. هنگامی که درخواستی به یک صفحه  ارسال میگردد این درخواست به وسیله HTTP Handler  پردازش میشود. در صورت نیاز میتوانید HTTP Handler شخصی خود را توسعه دهید تا خروجی مورد نیاز خود را ایجاد کنید.
HTTP Module یک اسمبلی است که هرگار درخواستی به سایت شما ارسال شود فراخوانی میگردد. HTTP Module به شما این اجازه را میدهد تا روی ورودی و خروجی ایجاد شده در صورت نیاز تغییرات خود را اعمال کنید.
مثال های عملی:
HTTP Handlers:
rss feed: میتوانید یک HTTP Handler ایجاد کنید که درخواست هایی که پسوند rssدارند را پردازش نماید و در آن HTTP Handler فید مربوط به سایت خود را به کاربر نمایش دهید.
image server: اگر میخاهید تصاویر سایت خود را در سایز های مختلفی به کاربر نمایش، در این صورت میتوانید یک HTTP Handler ایجاد کنید که مسئولیت تغییر سایز و نمایش تصاویر را به عهده داشته باشد.
HTTP Modules:
امنیت: به خاطر اینکه میتوانید قبل از هر کاری به یک درخواست ورودی دسترسی داشته باشید، میتوانید قبل از ورود درخواست به برنامه خود، چک های امنیتی خود را انجام دهید و اعمال مناسب را پیاده سازی کنید.
لاگ کردن: همانطور که قبلا گفتیم در هر درخواستی این ماژول ها اجرا میشوند، پس میتوانید برای اعمالی که روی هر درخواستی باید انجام شود مانند لاگ کردن و بررسی و ثبت وضعیت ها، یک httpmodule بنویسید و این کار را به صورت مرکزی انجام دهید به جای اینکه در تک تک قسمت های برنامه این کارها را پیاده سازی کنید.
قابلیت ها و ویژگی ها:
قابلیت ها و خواص HTTP Modules و HTTP Handlers در زیر آمده است
1- برای توسعه HTTP Modules و HTTP Handlers باید از اینترفیس های IHttpHandler و IHttpModule  استفاده کنیم.
2- برای توسعه یک http handler غیر همزمان از IHttpAsyncHandler  استفاده میکنیم.
3- سور کد ماژول ها و هندلر هایی که توصعه میدهیم میتواند در فولدر App_Code قرار گیرد یا میتوانیم آنها را در یک پروژه دیگر توسعه دهیم و به نرم افزار خود اضافه کنیم.
4- ماژول ها و هندلر های توسعه داده شده برای IIS 6 میتوانند با اندک تغییراتی یا بدون تغییر در iis7 مورد استفاده قرار گیرند.
5- در IIS7 ماژول ها نه تنها میتوانند با درخواست های برنامه مورد استفاده قرار گیرند. بلکه میتوانند با تمامی درخواست های ارسال شده به IIS استفاده شوند.
پیشینه:
HTTP Handlers
یک HTTP Handler پردازشی است که در پاسخ به یک درخواست که برای یک برنامه ASP.NET ارسال میشود اجرا میگردد. عمومی ترین هندلر موجود مربوط به پاسخ به درخواست هایی است که برای یک صفحه aspx ارسال میگردد. هنگامی که کاربر درخواستی برای یک صفحه ارسال میکند این درخواست توسط یک page handler پاسخ داده میشود.
ASP.NET شامل چندین نوع مختلف handler است. هر کدام از این handler ها میتوانند به یک درخواست خواص یا گروهی از درخواست های ورودی پاسخ دهند. در ذیل لیستی از انواع handler های موجود را میبینید.
ASP.NET page handler (*.aspx): یک هندلر عمومی است که مسئولیت پردازش درخواست های مربوط به صفحات را بر عهده دارد.
Web service handler (*.asmx): هندلر عمومی برای پردازش درخواست هایی که به وب سرویس ها ارسال میگردد.
Generic Web handler (*.ashx): یک هندلر عمومی است که تمامی درخواست هایی که هیچ UI ندارند را پردازش میکند.
Trace handler (trace.axd): هندلری است که اطلاعات تریس را نمایش میدهد.
ایجاد یک HTTP Handler:
برای ایجاد یک HTTP Handler کافی است کلاسی ایجاد کنید و یکی از اینتر فیس های IHttpHandler یا IHttpAsyncHandler را پیاده سازی کنید. این اینترفیس ها شامل 2 متد میباشند. IsReusable که اگر مقدار آن برابر با true باشد این هندلر را در Pool قرار میدهد و در دفعات بعدی از آن استفاده میکند و باعث افزایش سرعت میشود و در غیر این صورت با هر درخواست یک شی جدید از این هندلر ایجاد میشود. متد ProcessRequest برای پاسخ به درخواست کاربر استفاده میشود و هنگام ارسال درخواست این متد اجرا میگردد.
در یک http handler به application context دسترسی داریم و میتوانیم از خواص application context استفاده کنیم.
مپ کردن پسوند فایل ها:
هنگامی که یک http hanler ایجاد میکنید، این هندلر میتواند به هر درخواستی با هر پسوندی پاسخ دهد. برای مثال اگر هندلری بسازید که بخواهید تنها به درخواست هایی که پسوند rss دارند پاسخ دهد باید در IIS این پسوند را تنظیم کنید که به برنامه ASP.NET شما ارسال شود و در فایل web.config نیز این پسوند را به handler مخصوص خود ارسال کنید.
در صورتی که یک generic handler با پسوند ashx ایجاد کنید این هندلر به صورت اتوماتیک به وسیله IIS و ASP.NET شناخته خواهد شد.
برای ثبت هندلر های خود در IIS میتوانید از به اینجا و اینجا مراجعه کنید.
http handler های همزمان و غیر همزمان:
هندلرهای همزمان یا Synchronous  آنهایی هستند که وقتی درخواستی به آنها ارسال میگردد تا زمانی که پردازش آن درخواست پایان یابد هیچ بازگشتی نخواهند داشت. اما هندلرهای غیرهمزمان آنهایی هستند که به پاسخ ارسال شده به کاربر وابستگی ندارند. این دسته از هندلرها زمانی مورد استفاده قرارمیگرند که بعد از ارسال یک درخواست که زمان پردازش آن نیز زیاد است، لزومی ندارد کاربر در انتظار پایان پردازش آن درخواست بماند و به سادگی میتواند به کار خود ادامه دهد.
HTTP Moduleها:
HTTP module یک اسمبلی است که با هر درخواستی که به برنامه ارسال میشود، اجرا میگردد. HTTP module به عنوان بخشی از خط لوله درخواست(منظور همون request pipeline هست D:) اجرا میگردد و به تمامی رخداد هایی که در طول عمر درخواست اتفاق می افتد درسترسی دارد. به همین دلیل ماژول ها به شما این امکان را میدهند که درخواست های ورودی را مدیریت کنید و یا قبل از ارسال پاسخ به کاربر تغییراتی در پاسخ ایجاد کنید.
HTTP modules از جهاتی شبیه به ISAPI فیلتر ها هستند چون با هر درخواستی اجرا میشوند با این تفاوت که در یک محیط مدیریت شده پیاده سازی شده اند و با چرخه حیات درخواست های برنامه های ASP.NETکاملا منطبق هستند.
ASP.NET برای اهداف مختلفی از این ماژول ها استفاده میکند مانندforms authentication, caching, session state و client script services. در هر شرایطی در صورتی که یکی از این امکانات فعال شوند، بدون اینکه نیاز باشد در هر صفحه ای این امکانات را فراخوانی کنیم، به صورت اتوماتیک این امکانات برای ما فعال میشود. ماژول ها میتوانند به رخ دادهای برنامه دسترسی داشته باشند و یا میتوانند رخ دادهایی ایجاد کنند و در Global.asax میتوان به این رخ داد ها رسیدگی کرد.
نکته: ماژول ها و handler ها با هم تفاوت های اساسی دارند. یک هندلر برای یک نوع خاص درخواست ایجاد میشود و به آن پاسخ میدهد ولی یک ماژول با هر درخواستی که به سایت میآید اجرا میشود. به طور کلی در مواردی از ماژول ها استفاده میکنیم که بخواهیم یک کار عمومی را در کل برنامه اجرا کنیم.
HTTP Module  ها چگونه کار میکنند:
برای اینکه ماژول ها شروع به کار کنند باید آن ها را تنظیم و فعال کنیم. عمومی ترین روش به کارگیری ماژول ها استفاده از web.config جهت تنظیم آنها است.
هنگامی که یک نسخه از HttpApplication  ایجاد میشود یک نمونه از تمامی ماژول های ثبت شده نیز ایجاد میگردد. هنگامی که یک ماژول ایجاد میشود متد Init آن فراخوانی شده و ماژول خودش را آماده به کار میکند. برای اطلاعات بیشتر به اینجا و اینجا مراجعه کنید. در متد Init شما میتوانید رخ داد های مختلفی را که در برنامه اتفاق می افتد به متدهایی در ماژول خود مقید کنید و با اتفاق افتادن آن رخ دادها، عملی دلخواه انجام دهید مانند چک کردن دسترسی ها یا لاگ کردن موارد دلخواه. یک ماژول به Context درخواست دسترسی دارد و این به شما کمک میکند تا تغییرات دلخواه خود را وارد کنید، مثلا درخواست را به جای دیگری Redirect کنید.
HTTP Module ها در برابر Global.asax
بسیاری از قابلیت هایی را که شما در ماژول ها در اختیار دارید در Global.asax نیز قابل دسترسی است و به شما این قابلیت را میدهد که اعمالی در سطح برنامه اجرا کنید. اما ماژول ها مزایایی در اختیار شما میگذارند که شما را ترغیب میکند به جای استفاده از Global.asax از آنها استفاده کنید.
شما میتواندی یک ماژول را ایجاد کنید و در برنامه های مختلفی استفاده کنید. البته در مقابل Global.asax نیز به شما این قابلیت را میدهد که از رخ دادهایی مانند Session_Start و Session_End باخبر شوید و یا یک شی را ایجاد کنید که در کل برنامه مورد استفاده قرار گیرد.
در شرایطی که نیاز به قابلیتی در سطح برنامه دارید و موارد زیر نیز محقق شده است میتوانید از ماژول ها استفاده کنید:
1- میخاهید از این کد در سایر برنامه ها نیز استفاده کنید.
2-نمیخاهید کدهای پیچیده ای درون فایل Global.asax قرار دهید.
3-این امکانات در تمامی  درخواست های برنامه نیاز میباشد.
اگر شما نیاز به کدی داشتید که میخاهید با رخ دادهای مختلفی برنامه فعال شود و نیاز به استفاده از آن در سایر برنامه ها نیست و یا میخاهید با رخدادی کار کنید که در ماژول ها در دسترسی نیستند میتوانید از Global.asax استفاده کنید.
ایجاد یک HTTP Module:
رویه ایجاد یک Http Module به شرح زیر میباشد.
1- یک کلاس ایجاد کنید که IHttpModule را پیاده سازی کند.
2- متد Init  را ایجاد کنید.
3- متدهایی که برای رخدادهای مختلف ثبت کرده اید را پیاده سازی کنید.
4- در صورت نیاز متد Dispose را پیاده سازی کنید.
5- ماژول را در فایل web.Config ثبت کنید.
منبع HTTP Handlers and HTTP Modules Overview
پایان قسمت اول.
» ادامه مطلب

مدیریت تگ span ایجاد شده به صورت پیش فرض در کنترل های ASP.NET

اگر تا به حال اقدام به ساخت کنترل های ASP.NET کرده باشید، مشاهده کرده اید که هر کنترلی که ایجاد میشود یک تگ span به صورت پیش فرض ایجاد میکند. دلیل ایجاد این تگ این است که کنترل های وبی این تگ را به صورت پیش فرض برای خود تعریف کرده اند.

protected internal override void Render(HtmlTextWriter writer)
{
    this.RenderBeginTag(writer);
    this.RenderContents(writer);
    this.RenderEndTag(writer);
}
برای رفع این مشکل کافی است متد Render را override کنید.
protected override void Render(HtmlTextWriter writer)
{
    RenderContents(writer);
}
دلیل این امر این است که کنترل این متد به صورت پیش فرض به شکل زیر پیاده سازی شده است. مشاهده میکنید که این متد ابتدا تابع RenderBeginTag را صدا میزند که پیاده سازی این متد به شکل زیر است:
protected internal override void Render(HtmlTextWriter writer)
{
    this.RenderBeginTag(writer);
    this.RenderContents(writer);
    this.RenderEndTag(writer);
}
این متد ابتدا tagKey را ایجاد میکند. و این کار باعث ایجاد span میشود، اما با override کردن متد Render دیگر این تگ ایجاد نمیشود. حال اگر بخاهیم بجای تگ span تگ دیگری را ایجاد کنیم چه؟ فرض کنید میخاهید کنترل شما یک container داشته باشد اما میخاهید container شما از جنس div باشد. برای این کار کافی است خاصیت زیر را به شکل نمایش داده شده override کنید.
protected override HtmlTextWriterTag TagKey
{

    get{ return HtmlTextWriterTag.Div;}
}
» ادامه مطلب