نظرات مطالب
پَرباد - راهنمای اتصال و پیاده‌سازی درگاه‌های پرداخت اینترنتی (شبکه شتاب)
با تشکر از مطالب مفید شما
فقط یک سوال اینجا پیش میاد اطلاعات شماره درگاه و نام کاربری و کلمه عبور عملا در این روش کاربردی نداره ؟
احراز اطلاعات پذیرنده به چه صورتیه ؟
امنیت استفاده از این پکیج را هم ممنون میشم توضیح بفرمائید
مطالب
مدیریت سشن‌ها در برنامه‌های وب به کمک تزریق وابستگی‌ها
سشن‌ها در برنامه‌های وب، یکی از وابستگی‌های استاتیکی هستند که می‌توان آن‌ها را از طریق تزریق وابستگی‌ها، جهت بالا بردن قابلیت آزمون پذیری برنامه، تامین کرد. همچنین اگر از سشن‌ها برای نمونه در برنامه‌های ASP.NET MVC استفاده کنید، مقدار آن‌ها در سازنده‌ی کنترلرها نال خواهند بود؛ از این جهت که در زمان نمونه سازی یک کنترلر توسط IoC Container، کار مدیریت سشن‌ها صورت نمی‌گیرد و اگر در این بین سرویسی نیاز به سشن داشته باشد، دیگر وهله سازی نخواهد شد؛ به این دلیل که صرفنظر از مقدار دهی متغیر سشن در صفحه‌ای دیگر، این مقدار در سازنده‌ی کلاس، نال است. در ادامه این مشکل را از طریق غنی سازی تزریق وابستگی‌ها با اطلاعات سشن جاری، برطرف خواهیم کرد.


طراحی یک تامین کننده‌ی عمومی سشن

public interface ISessionProvider
{
    object Get(string key);
    T Get<T>(string key) where T : class;
    void Remove(string key);
    void RemoveAll();
    void Store(string key, object value);
}
در اینجا یک اینترفیس عمومی را مشاهده می‌کنید که کار آن کپسوله سازی اعمال متداول کار با سشن‌ها است؛ برای مثال دریافت اطلاعات یک سشن، بر اساس کلیدی مشخص و یا ذخیره سازی اطلاعات اشیاء در سشن‌ها.
یک نمونه پیاده سازی عمومی آن نیز برای کار با سشن‌ها در برنامه‌های وب ASP.NET وب فرم و MVC، می‌تواند به صورت زیر باشد:
public class DefaultWebSessionProvider : ISessionProvider
{
    private readonly HttpSessionStateBase _session;
 
    public DefaultWebSessionProvider(HttpSessionStateBase session)
    {
        _session = session;
    }
 
    public object Get(string key)
    {
        return _session[key];
    }
 
    public T Get<T>(string key) where T : class
    {
        return _session[key] as T;
    }
 
    public void Remove(string key)
    {
        _session.Remove(key);
    }
 
    public void RemoveAll()
    {
        _session.RemoveAll();
    }
 
    public void Store(string key, object value)
    {
        _session[key] = value;
    }
}
در کلاس DefaultWebSessionProvider مستقیما از HttpContext.Current.Session برای دسترسی به سشن جاری استفاده نشده‌است. این مقدار را از سازنده‌ی خود که توسط کلاس پایه HttpSessionStateBase تامین می‌شود، دریافت خواهد کرد. این سازنده را توسط تنظیمات ابتدایی IoC Container خود وهله سازی و مقدار دهی می‌کنیم؛ زیرا HttpContext.Current.Session برای مقدار دهی، نیاز به راه اندازی یک وب سرور دارد و عملا استفاده و شبیه سازی از آن در بسیاری از آزمون‌های واحد، بسیار مشکل خواهد بود.
private static Container defaultContainer()
{
    return new Container(ioc =>
    {
        // session manager setup
        ioc.For<ISessionProvider>().Use<DefaultWebSessionProvider>();
        ioc.For<HttpSessionStateBase>()
           .Use(ctx => new HttpSessionStateWrapper(HttpContext.Current.Session)); 
 
        ioc.Policies.SetAllProperties(properties =>
        {
            properties.OfType<ISessionProvider>();
        });
    });
}
در مثال فوق یک نمونه از تنظیمات ابتدایی StructureMap را برای استفاده از مقدار HttpContext.Current.Session، جهت وهله سازی سازنده‌ی کلاس DefaultWebSessionProvider مشاهده می‌کنید.


استفاده از تامین کننده‌ی سفارشی سشن در برنامه

پس از طراحی تامین کننده‌ی سفارشی سشن و همچنین معرفی آن به IoC Container خود، اکنون استفاده‌ی از آن به سادگی ذیل است:
public class HomeController : Controller
{
    private readonly ISessionProvider _sessionProvider;
    public HomeController(ISessionProvider sessionProvider)
    {
        _sessionProvider = sessionProvider;
    }
بنابراین اگر در کلاسی، کنترلری و یا سرویسی نیاز به سشن وجود داشت، بهتر است از ISessionProvider بجای مقدار دهی و یا دسترسی مستقیم به شیء استاتیک Session استفاده کرد.
مطالب
SignalR - قسمت سوم
در قسمت قبل درباره روشهای برقراری ارتباط با سرور در کتابخونه SignalR کمی بحث شد. برای ادامه بهتره که به برنامه چت ساده ای که تو این مدت کمی تکمیلش کردم یه نگاهی بندازین:
لطف کنین این برنامه رو دانلود و اجرا کنین تا کمی با جزئیات این کتابخونه بیشتر آشنا بشین. این برنامه قدم به قدم نوشته شده و حاوی نسخه‌های مختلفی از برنامه چت هست که هر کدوم تو یه فایل html استفاده شده. نسخه آخر شامل عملیات لاگین، چت گروهی، چت خصوصی و امکان تغییر گروه است. درضمن این برنامه کمی با عجله نوشته شده پس اگه باگ یا موردی مشاهده کردین و یا پیشنهادی دارین اشاره کنین تا بقیه هم استفاده کنن.
حالا به یه نکته در مورد آغاز برقراری ارتباط کلاینت با سرور اشاره میکنم. قبل از برقراری این ارتباط (که در قسمت قبل توضیحاتی در این مورد داده شده) برنامه کلاینت یک درخواست به سمت سرور ارسال میکنه. به تصویر زیر دقت کنین:

به این درخواست اولیه در کتابخونه SignalR همونطور که مشاهده میشه مذاکره (negotiate) گفته میشه. برقراری ارتباط این درخواست اولیه هم توسط XHR انجام میشه. نتیجه این مذاکره در تب Response Body قابل مشاهده است:

می‌بینین که علاوه بر آی دی ارتباط که یک guid است (تلفظ مرسومش «گوئِد» هستش) امکان برقراری ارتباط از طریق روش WebSocket رو هم از طرف سرور مشخص میکنه که با توجه به استفاده من از ویندوز 7 امکانش وجود نداره. یعنی اگر مثلا شما از ویندوز 8 و IIS 8 استفاده کنین مقدار TryWebSocket برابر true بوده و همچنین پارامتر WebSocketServerUrl نال نخواهد بود. البته این پارامتر تنها مربوط به سروره و برنامه کلاینت مورد استفاده (در اینجا یک مرورگر) هم باید توانایی استفاده از این روش رو داشته باشه. پس از اتمام این مذاکره ارتباط اصلی برقرار میشه.

یکی از قابلیتهای خوب این کتابخونه ارسال خطاهای رخ داده در سمت سرور به کلاینت هست. در تصویر زیر بدنه یک نمونه از پاسخهای سرور که نمایش دهنده خطای رخ داده در سمت سرور هست رو نشون داده شده:

برای راحتی دوستان در استفاده از راهنماهای این کتابخونه، یه مقدار کار روشون انجام دادم و با خلاصه کردن محتوای اونا (و کاهش حجم 95 درصدی!) برای استفاده آفلاین آماده کردم:

SignarR github docs.rar 

اگه فرصتی پیش بیاد و دوستان هم علاقه داشته باشن در قسمت بعدی برنامه چت رو بیشتر با هم بررسی میکنیم.

در ادامه قصد دارم تا روی بازدهی و کارایی این کتابخونه تو بار زیاد یه بررسی هایی انجام بدم (البته اگه وقت کنم چون راه اندازی یه محیط تست برا این جور کتابخونه‌ها چندان آسون نیست)  و مطلبی هم در مورد نحوه راه اندازی تست بار ارائه بدم.

مطالب
آشنایی با ساختار IIS قسمت اول
در مقاله قبل در مورد نحوه ذخیره سازی در حافظه نوشتیم و به user mode و kernel mode اشاراتی کردیم که می‌توانید به آن رجوع کنید.
در این سری مقالات قصد داریم به بررسی اجزا و روند کاری موجود در IIS بپردازیم که چگونه IIS کار می‌کند و شامل چه بخش هایی می‌شود. مطمئنا آشنایی با این بخش‌ها در روند شناسایی رفتارهای وب اپلیکیشن‌ها و واکنش‌های سرور، کمک زیادی به ما خواهد کرد. در اینجا نسخه IIS7 را به عنوان مرجع در نظر گرفته‌ایم.
وب سرور IIS در عبارت مخفف Internet information services به معنی سرویس‌های اطلاعاتی اینترنت می‌باشد. IIS شامل کامپوننت‌های زیادی است که هر کدام ازآن‌ها کار خاصی را انجام میدهند؛ برای مثال گوش دادن به درخواست‌های ارسال شده به سرور، مدیریت فرآیندها Process و خواندن فایل‌های پیکربندی Configuration؛ این اجزا شامل protocol listener ،Http.sys و WSA و .. می‌شوند.
Protocol Listeners
این پروتکل‌ها به درخواست‌های رسیده گوش کرده و آن‌ها را مورد پردازش قرار می‌دهند و پاسخی را به درخواست کننده، ارسال می‌کنند. هر listener بر اساس نوع پروتکل متفاوت هست. به عنوان مثال کلاینتی، درخواست صفحه‌ای را می‌کند و http listener که به آن Http.sys می‌گویند به آن پاسخ می‌دهد. به طور پیش فرض http.sys به درخواست‌های http و https گوش فرا می‌دهد، این کامپوننت از IIS6 اضافه شده است ولی در نسخه 7 از SSL نیز پشتیبانی می‌کند.
Http.sys یا Hypertext transfer protocol stack
کار این واحد در سه مرحله دریافت درخواست، ارسال آن به واحد پردازش IIS و ارسال پاسخ به کلاینت است؛ قبل از نسخه 6 از Winsock یا windows socket api  که یک کامپوننت user-mod بود استفاده می‌شد ولی Http.sys یک کامپوننت Kernel-mod هست.

Http.sys مزایای زیر را به همراه دارد:

  • صف درخواست مد کرنل: به خاطر اینکه کرنل مستقیما درخواست‌ها را به پروسه‌های مربوطه میفرستد و اگر پروسه موجود نباشد، درخواست را در صف گذاشته تا بعدا پروسه مورد نظر آن را از صف بیرون بکشد.
  • برای درخواست‌ها یک پیش پردازش و همچنین اعمال فیلترهای امنیتی اعمال می‌گردد. 
  • عملیات کش کردن تماما در محیط کرنل مد صورت می‌گیرد؛ بدون اینکه به حالت یوزرمد سوییچ کند. مد کرنل دسترسی بسیار راحت و مستقیمی را برای استفاده از منابع دارد و لازم نیست مانند مد کاربر به لایه‌های زیرین، درخواست کاری را بدهد؛ چرا که خود مستقیما وارد عمل می‌شود و برداشته شدن واسط در سر راه، موجب افزایش عمل caching می‌شود. همچنین دسترسی به کش باعث می‌شود که مستقیما پاسخ از کش به کاربر برسد و توابع پردازشی در حافظه بارگذاری نشوند. البته این کش کردن محدودیت هایی را هم به همراه دارد:
    1. کش کرنل به صورت پیش فرض بر روی صفحات ایستا فعال شده است؛ نه برای صفحاتی با محتوای پویا که البته این مورد قابل تغییر است که نحوه این تغییر را پایینتر توضیح خواهیم داد.
    2. اگر آدرس درخواستی شامل کوئری باشد صفحه کش نخواهد شد:    http://www.site.info/postarchive.htm?id=25 
    3. برای پاسخ ازمکانیزم‌های فشرده سازی پویا استفاده شده باشد مثل gzip کش نخواهد شد
    4. صفحه درخواست شده صفحه اصلی سایت باشد کش نخواهد شد :   http://www.dotnettip.info ولی اگر درخواست بدین صورت باشه http://www.domain.com/default.htm  کش خواهد کرد.
    5. درخواست به صورت ناشناس anonymous نباشد  و نیاز به authentication داشته باشد کش نخواهد شد (یعنی در هدر شامل گزینه authorization می‌باشد).
    6. درخواست باید از نوع نسخه http1 به بعد باشد.
    7. اگر درخواست شامل Entity-body باشد کش نخواهد کرد.
    8. درخواست شامل If-Range/Range header باشد کش نمی‌شود.
    9. کل حجم response بییشتر از اندازه تعیین شده باشد کش نخواهد گردید، این اندازه در کلید ریجستری UriMaxUriBytes قرار دارد. اطلاعات بیشتر
    10. اندازه هدر بیشتر از اندازه تعیین شده باشد که عموما اندازه تعیین شده یک کیلو بایت است.
    11. کش پر باشد، کش انجام نخواهد گرفت.
    برای فعال سازی کش کرنل راهنمای زیر را دنبال کنید:
    گزینه output cache را در IIS، فعال کنید و سپس گزینه Add را بزنید. کادر add cache rule که باز شود، از شما میخواهد یکی از دو نوع کش مد کاربر و مد کرنل را انتخاب کنید و  مشخص کنید چه نوع فایل‌هایی (مثلا aspx) از این قوانین پیروری کنند و مکانیزم کش کردن به سه روش جلوگیری از کش کردن، کش زمان دار و کش بر اساس آخرین تغییر فایل انجام گردد.


    برای تعیین مقدار سایز کش response که در بالا اشاره کردیم می‌توانید در همان پنجره، گزینه edit feature settings را انتخاب کنید.


    این قسمت از مطلب که به نقل از مقاله  آقای Karol Jarkovsky در این آدرس است یک سری تست هایی با نرم افزار(Web Capacity Analysis Tool (WCAT  گرفته است که به نتایج زیر دست پیدا کرده است:
    Kernel Cache Disabled    4 clients/160 threads/30 sec      257 req/sec
    Kernel Cache Enabled     4 clients/160 threads/30 sec      553 req/sec 
    همانطور که می‌بینید نتیجه فعال سازی کش کرنل پاسخ به بیش از دو برابر درخواست در حالت غیرفعال آن است که یک عدد فوق العاده به حساب میاد.
    برای اینکه خودتان هم تست کرده باشید در این آدرس  برنامه را دانلود کنید و به دنبال فایل request.cfg بگردید و از صحت پارامترهای server و url اطمینان پیدا کنید. در گام بعدی 5 پنجره خط فرمان باز کرده و در یکی از آن‌ها دستور netsh http show cachestate را بنویسید تا تمامی وروردی‌های entry که در کش کرنل ذخیره شده اند لیست شوند. البته در اولین تست کش را غیرفعال کنید و به این ترتیب نباید چیزی نمایش داده شود. در همان پنجره فرمان wcctl –a localhost –c config.cfg –s request.cfg  را زده تا کنترلر برنامه در وضعیت listening قرار بگیرد. در 4 پنجره دیگر فرمان wcclient localhost از شاخه کلاینت را نوشته تا تست آغاز شود. بعد از انجام تست به شاخه نصب کنترلر WCAT رفته و فایل log را بخوانید و اگر دوباره دستور نمایش کش کرنل را بزنید باید خالی باشد. حالا کش را فعال کنید و دوباره عملیات تست را از سر بگیرید و اگر دستور netsh را ارسال کنید باید کش کرنل دارای ورودی باشد.
    برای تغییرات در سطح http.sys می‌توانید از ریجستری کمک بگیرید. در اینجا تعداد زیادی از تنظیمات ذخیره شده در ریجستری برای http.sys لیست شده است.
    مطالب
    آشنایی با Window Function ها در SQL Server بخش سوم
    در این بخش به دو Function از Analytic Function‌ها (توابع تحلیلی)، یعنی Lead Function و  LAG Function می پردازیم.
    قبل از اینکه به توابع ذکرشده بپردازیم، باید عرض کنم، شرح عملکرد اینگونه توابع کمی مشکل می‌باشد، بنابراین با ذکر مثال و توضیح آنها،سعی می‌کنیم،قابلیت هریک را بررسی و درک نماییم. 
    • Lead Function:
           این فانکشن در SQL Server 2012 ارائه شده است، و امکان دسترسی، به Data‌های سطر بعدی نسبت به سطر جاری را در نتیجه یک پرس و جو (Query)، ارائه می‌دهد. بدون آنکه از Self-join استفاده نمایید،   
           Syntax تابع فوق بصورت زیر است:
    LEAD ( scalar_expression [ ,offset ] , [ default ] ) 
        OVER ( [ partition_by_clause ] order_by_clause )
    شرح Syntax:
    1. Scalar_expression: در Scalar_expression، نام یک فیلد یا ستون درج می‌شود، و مقدار برگشتی فیلد مورد نظر، به مقدار تعیین شده offset نیز بستگی دارد. خروجی Scalar_expression فقط یک مقدار است.
    2. offset: منظور از Offset در این Syntax همانند عملکرد Offset در Syntax مربوط به Over می‌باشد. یعنی هر عددی برای offset در نظر گرفته شود، بیانگر نقطه آغازین سطر بعدی یا قبلی نسبت به سطر جاری است. به بیان دیگر، عدد تعیین شده در Offset به Sql server می‌فهماند چه تعداد سطر را در محاسبه در نظر نگیرد.
    3. Default: زمانی که برای Offset مقداری را تعیین می‌نمایید، SQL Server به تعداد تعیین شده در Offset، سطر‌ها را در نظر نمی‌گیرد، بنابراین مقدار خروجی Scalar_expression بطور پیش فرض Null در نظر گرفته می‌شود، چنانچه بخواهید، مقداری غیر از Null درج نمایید، می‌توانید مقدار دلخواه را در قسمت Default وارد کنید.
    4. (OVER ( [ partition_by_clause ] order_by_clause : در بخش اول بطور کامل توضیح داده شده است.
         برای درک بهتر Lead Function چند مثال را بررسی می‌نماییم:
         ابتدا Script زیر را اجرا می‌نماییم، که شامل ایجاد یک جدول و درج 18 رکورد در آن:
    Create Table TestLead_LAG
    (SalesOrderID int not null,
     SalesOrderDetailID int not null ,
     OrderQty smallint not null);
     GO
    Insert Into TestLead_LAG 
           Values (43662,49,1),(43662,50,3),(43662,51,1),
              (43663,52,1),(43664,53,1),(43664,54,1),
      (43667,77,3),(43667,78,1),(43667,79,1),
      (43667,80,1),(43668,81,3),(43669,110,1),
      (43670,111,1),(43670,112,2),(43670,113,2),
      (43670,114,1),(43671,115,1),(43671,116,2)
    مثال:قصد داریم در هر سطر مقدار بعدی فیلد SalesOrderDetailID در فیلد دیگری به نام LeadValue نمایش دهیم، بنابراین Script زیر را ایجاد می‌کنیم:
    SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty,
    LEAD(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID) LeadValue
    FROM TestLead_LAG s
    WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
    ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty
    خروجی بصورت زیر خواهد بود:

         مطابق شکل، براحتی واضح است، که در هر سطر مقدار بعدی فیلد SalesOrderDetailID در فیلد LeadValue درج و نمایش داده می‌شود. فقط در سطر 10، چون مقدار بعدی برای فیلد SalesOrderDetailID وجود ندارد، SQL Server مقدار فیلد LeadValue را، Null در نظر می‌گیرد.
    در این مثال فقط از آرگومان Scalar_expression، استفاده کردیم، و Offset و Default را مقدار دهی ننمودیم، بنابراین SQL Server بطور پیش فرض هیچ سطری را حذف نمی‌کند و مقدار Default را Null در نظر می‌گیرد.
    مثال دوم: قصد داریم در هر سطر مقدار دو سطر بعدی فیلد SalesOrderDetailID را در فیلد LeadValue نمایش دهیم، و در صورت وجود نداشتن مقدار فیلد SalesOrderDetailID، مقدار پیش فرض صفر ،در فیلد LeadValue قرار دهیم،بنابراین Script آن بصورت زیر خواهد شد:
    SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty,
    LEAD(SalesOrderDetailID,2,0) OVER (ORDER BY SalesOrderDetailID) LeadValue
    FROM TestLead_LAG s
    WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
    ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty
    خروجی:

        در صورت مسئله بیان کرده بودیم، در هر سطر،مقدار فیلد SalesOrderDetailID دو سطر بعدی، را نمایش دهیم، بنابراین مقداری که برای Offset در نظر می‌گیریم، برابر دو خواهد بود، سپس گفته بودیم، چنانچه در هر سطر مقدار  فیلد SalesOrderDetailID وجود نداشت،بجای مقدار پیش فرض Null،از مقدار صفر استفاده شود، بنابراین به Default مقدار صفر را نسبت دادیم.
    LEAD(SalesOrderDetailID,2,0)
    در شکل، مطابق صورت مسئله، مقدار فیلد LeadValue سطر اول برابر است با 78،  
    به بیان ساده‌تر برای بدست آوردن مقدار فیلد LaedValue هر سطر، می‌بایست هر سطر را به علاوه 2 (Offset) نماییم، تا سطر بعدی بدست آید، سپس مقدار SalesOrderDetailID را در فیلد LeadValue قرار می‌دهیم.
    به سطر 9 و 10 توجه نمایید، که مقدار فیلد LeadValue آنها برابر با صفر است، واضح است، سطر 10 + 2 برابر است با 12( 10+2=12 )، چنین سطری در خروجی نداریم، بنابراین بطور پیش فرض مقدار LeadVaule توسط Sql Server برابر Null در نظر گرفته می‌شود، اما نمی‌خواستیم، که این مقدار Null باشد، بنابراین به آرگومان Default مقدار صفر را نسبت دادیم، تا SQL Server ، به جای استفاده از Null، مقدار در نظر گرفته شده صفر را استفاده نماید.
    اگر چنین فانکشنی وجود نداشت، برای شبیه سازی آن می‌بایست از Join روی خود جدول استفاده می‌نمودیم، و یکسری محاسابت دیگر، که کار را سخت می‌نمود، مثال دوم را با Script زیر می‌توان شبیه سازی نمود:
    WITH cteLead
    AS
    (
    SELECT SalesOrderID,SalesOrderDetailID,OrderQty,
           ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS sn
    FROM TestLead_LAG
    WHERE
    SalesOrderID IN (43670, 43669, 43667, 43663)
    )
    SELECT m.SalesOrderID, m.SalesOrderDetailID, m.OrderQty,
           case  when sLead.SalesOrderDetailID is null Then 0 Else sLead.SalesOrderDetailID END as leadvalue
    FROM cteLead AS m
    LEFT OUTER JOIN cteLead AS sLead ON sLead.sn = m.sn+2
    ORDER BY m.SalesOrderID, m.SalesOrderDetailID, m.OrderQty
    
           جدول موقتی ایجاد نمودیم، که ROW_Number را در آن اضافه کردیم، سپس جدول ایجاد شده را با خود Join کردیم، و گفتیم، که مقدار فیلدLeadValue  هر سطر برابر است با مقدار فیلد SalesOrderDetailID دو سطر بعد از آن. و با Case نیز مقدار پیش فرض را صفر در نظر گرفتیم.

    • LAG Function:
           این فانکشن نیز در SQL Server 2012 ارائه شده است، و امکان دسترسی، به Data‌های سطر قبلی نسبت به سطر جاری را در نتیجه یک پرس و جو (Query)، ارائه می‌دهد. بدون آنکه از Self-join استفاده نمایید،  
    Syntax آن شبیه به فانکشن Lead میباشد و بصورت زیر است:
    LAG (scalar_expression [,offset] [,default])
        OVER ( [ partition_by_clause ] order_by_clause )
    Syntax مربوط به فانکشن LAG را شرح نمی‌دهم، بدلیل آنکه شبیه به فانکشن Lead می‌باشد، فقط تفاوت آن در Offset است، Offset در فانکشن LAG روی سطرهای ماقبل سطر جاری اعمال می‌گردد.
    مثال دوم را برای حالت LAG Function شبیه سازی می‌نماییم:
    SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty,
    LAG(SalesOrderDetailID,2,0) OVER (ORDER BY SalesOrderDetailID) LAGValue
    FROM TestLead_LAG s
    WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
    ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty
    go
    
    خروجی :

    همانطور که گفتیم، LAG Function عکس LEAD Function میباشد. یعنی مقدار فیلد LAGValue سطر جاری برابر است با مقدار SalesOrderDetailID دو سطر ما قبل خود. 
    مقدار فیلد LAGValue دو سطر اول و دوم نیز برابر صفر است، چون دو سطر ماقبل آنها وجود ندارد، و مقدار صفر نیز بدلیل این است که Default را برابر صفر در نظر گرفته بودیم.
    مثال: در این مثال از Laed Function و LAG Function بطور همزمان استفاده می‌کنیم، با این تفاوت، که از گروه بندی نیز استفاده شده است:
    Script زیر را اجرا نمایید:
    SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty,
           Lead(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) LeadValue,
           LAG(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) LAGValue
    FROM TestLead_LAG s
    WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
    ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty
    go
    
    خروجی:

    با بررسی هایی که در مثالهای قبل نمودیم،خروجی زیر را می‌توان براحتی تشخیص داد، و توضیح بیشتری نمی‌دهم.
    موفق باشید.