بایگانی دسته‌ی: کدنویسی

استفاده از QueueBackgroundWorkItem برای به تاخیر انداختن کارها در اپلیکیشن های asp.net 4.5.2

ارسال شده در: ASP.NET . کدنویسی

با انتشار نسخه‌ی ۴.۵.۲ از .Net حالا ASP.NET در فضای نام System.Web.Hosting از HostingEnvironment.QueueBackgroundWorkItem پشتیبانی می‌کند. در این نوشته سعی می‌کنم از آن در ASP.NET MVC استفاده کنم.

hosting_environment_queue_background_work_item

پیش از آن، می‌توانید از وبلاگ متخصصان مایکروسافت و یا MSDN دیگر امکاناتی که در .NET 4.5.2 قرار گرفته است را ببینید.

Announcing the .NET Framework 4.5.2 What’s New in the .NET Framework 4.5, 4.5.1, and 4.5.2

وظیفه‌ی QueueBackgroundWorkItem چیست؟

در توضیحات انتشار (release note) در مورد QueueBackgroundWorkItem آمده:

The HostingEnvironment.QueueBackgroundWorkItem method lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed.

این توضیح مخصوصا جایی که bold کردم، دلیل خوبی برای استفاده از QueueBackgroundWorkItem خواهد بود. دیگر نیازی نیست نگران متوقف شدن IIS هنگام کارهای پس‌زمینه باشیم!

لازم به ذکر است که QueueBackgroundWorkItem فقط در ASP.NET managed کار می‌کند. Using Application Domains را مطالعه کنید.

استفاده ساده از متد QueueBackgroundWorkItem

QueueBackgroundWorkItem دو تا overload داره. که هر کدام یک ورودی دارند. می‌توان هر کدام از delegateهای زیر را به آن پاس داد:

  • Action
  • Func

تکه کد زیر چگونگی صدا زدن اولین overload با استفاده از عبارت lambda را نشان می‌دهد:

HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
    // Some long-running job
});

عبارت lambda حتی می‌تواند از async استفاده کند. که با آن می‌توان از تمام مزایای await هم بهره برد:

HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
{
    var result = await LongRunningMethodAsync();

    // Do something with result
    // ...
});

می‌توان یک متد را به وسیله‌ی عبارت Func به QueueBackgroundWorkItem ارسال کرد.

private void QueueWorkItem()
{
    Func<CancellationToken, Task> workItem = LongRunningMethodAsync;
    HostingEnvironment.QueueBackgroundWorkItem(workItem);
}

private async Task LongRunningMethodAsync(CancellationToken cancellationToken)
{
    // Some long-running job
}

از آنجایی که کامپایلرهای C# متدهایی که پاس می‌دهیم را تبدیل (conversion) می‌کنند نمی‌توان مستقیمن LongRunningMethodAsync را به QueueBackgroundWorkItem پاس داد. مشکل این‌جاست که وقتی متد را به QueueBackgroundWorkItem مستقیمن پاس بدهیم کامپایلر با استفاده از overload resolution آن را تبدیل می‌کند، که overload resolution کاری به مقدار بازگشتی متد ندارد. از آن‌جایی که هر دو overload در QueueBackgroundWorkItem یک پارامتر ورودی CancellationToken دارند، کامپایلر نمی‌داند باید کدام را صدا بزند و خطا رخ می‌دهد. برای درک بهتر به این پاسخ در StackOverflow نگاهی بیاندازید.

فراخوانی POST یک API در یک ASP.NET MVC Controller

(نوشتن پست‌های اینچنینی به فارسی کاری بسیار نا به هنجار است!)

در اینجا یک مثال کاملتر از اینکه QueueBackgroundWorkItem چگونه استفاده می‌شود می‌آورم. فرض کنیم که یک مدل به نام Foo ساخته‌ایم. و در controller می‌خواهیم یک API را که عملیات آن زمان‌بر است را صدا بزنیم.

public class FooController : Controller
{
    [HttpPost]
    public ActionResult Create(FooInputModel input)
    {
        // Process the input somehow
        // ...

        Action<CancellationToken> workItem = PostToRemoteService;
        HostingEnvironment.QueueBackgroundWorkItem(workItem);

        return View();
    }

    private async void PostToRemoteService(CancellationToken cancellationToken)
    {
        using (var client = new HttpClient())
        {
            var response = await client.PostAsync("http://example.com/endpoint",
                new StringContent("..."), cancellationToken);

            // Do something with response
            // ...
        }
   }

    // More action methods
    // ...
}

به این ترتیب، Action می‌تواند مقدار بازگشتی را پس از انجام عملیات روی ورودی ها (inputها) پس بفرستد (View) و نیازی نیست که منتظر تمام شدن صدا زدن API بماند.

پر واضح است که می‌توان از QueueBackgroundWorkItem در دیگر انواع پروژه ها و نه فقط ASP.NET MVC هم استفاده کرد.

خلاصه

همان‌طور که مشاهده کردید استفاده از QueueBackgroundWorkItem بسیار ساده‌ست. حالا دیگر ASP.NET می‌تواند از متوقف شدن IIS برای انجام کارهای به تاخیر افتاده و طولانی جلوگیری کند. به نظر می‌رسد که استفاده از QueueBackgroundWorkItem برای انجام scheduling کارهای کوچک بسیار مفید باشد.

JavaScript-logo-700x388

فراخوانی توابع به صورت ناهمزمان در JavaScript

ارسال شده در: جاوا اسکریپت . کدنویسی

برای شروع از یک موضوع ساده استفاده می‌کنم تا دوباره به روزهای خوب نوشتن برگردم. فراخوانی توابع به صورت ناهمزمان در JavaScript به روش های مختلف انجام میشه.

برای کاربران حرفه‌ای تر استفاده از تکنولوژی‌ها و Frameworkهای زیر رو پیشنهاد می‌کنم: + Backbone + TypeScript + AngularJS البته الزاما در این libraryها از روش‌های مشابه استفاده نشده. مثلا در backbone از event استفاده میشه.

اما در اینجا می‌خوام از یک راه خیلی ساده و بدون هیچ Libraryای استفاده کنم. این روش برای پروژه‌های کوچک و یا پروژه‌هایی که وقت سازمان دادن پروژه رو ندارین و میخواین خیلی زود و با اضافه کردن یک فایل JS به پروژه کار رو تمام کنین به درد می‌خوره.

Callback

احتمالا در jQuery از Eventهای Click و یا Change استفاده کردین. مثلا:

$(".a-link").click(callback);

در واقع ما در اینجا برای پارامتر callback یک تابع ارسال می‌کنیم که زمانی که Event کلیک لینک (a-link.) اتفاق افتاد function ما فراخونده میشه. این Pureترین و ساده‌ترین راه برای به تأخیر انداختن اجرای یک function هست.

حالا ما می‌خوایم از این روش در پروژه‌ی خودمون استفاده کنیم. پروژه‌ی ساده‌ای تعریف خواهیم کرد که در آن وقتی روی یک دکمه کلیک کنیم صفحه تغییر رنگ دهد. یک پروژه با ساختار زیر ایجاد می‌کنیم:

-- Index.html
-- js
-- -- jquery.js
-- -- scripts.js

در فایل scripts.js یک function می‌سازیم:

var changeColor = function() {
    // Body background will be `pink` hear
    $("body").css({ "background-color": "pink" });
};

حالا محتوای فایل index.html به شکل زیر خواهد بود.

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Blogwave: Color Changer;</title>
</head>
<body>
    <button id="color-changer"></button>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="js/scripts.js"></script>
</body>
</html>

حالا به scripts.js کد زیر رو اضافه می‌کنیم:

$(document).ready(function() {
    $("#color-changer").click(changeColor);
});

تا اینجا وقتی کاربر روی دکمه کلیک کرد رنگ زمینه‌ی Body صورتی میشه. اما فرض می‌کنیم که کاربر قبلا به ما گفته بوده که از رنگ زرد خوشش میاد و این اطلاعات در سرور ذخیره شده. پس یک function می‌نویسیم که از سرور اطلاعات رنگ مورد علاقه‌ی کاربر رو واسمون پیدا کنه.

var getFavoriteColor = function() {
    $.ajax({
        type: "POST",
        url: "/api/GetFavoriteColor",
        contentType: "application/json"
    }).done(function (color) {
        return color;
    })
};

می‌دونیم که کد بالا هیچ وقت هیچ رنگی رو بر نمی‌گردونه. چون زمانی تابع done اجرا میشه که فراخوانی تابع getFavoriteColor به پایان رسیده. پس ما اینجا یک پارامتر ورودی به نام callback خواهیم گرفت:

var getFavoriteColor = function(callback) {
    $.ajax({
        type: "POST",
        url: "/api/GetFavoriteColor",
        contentType: "application/json"
    }).done(function (color) {
        if (callback) {
            callback(color);
        }
    })
};

در اینجا ما چک کردیم که اگه callback تعریف شده باشه ما پارامتر color رو واسش ارسال می‌کنیم و اون رو فراخوانی می‌کنیم. حالا کد قبل رو اینطور ویرایش می‌کنیم:

var changeColor = function() {
    // Body background will be `pink` hear
    $("body").css({ "background-color": "pink" });

    // ‌Body background will be user defined color hear
    getFavoriteColor(function(color) {
        $("body").css({ "background-color": color });
    });
};

ما یک تابع به عنوان پارامتر به تابع getFavoriteColor ارسال کردیم که خودش یک پارامتر به نام color میگیره. حالا هر چقدر هم که ajax کارش طول بکشه برای ما مهم نیست، بلافاصله بعد از دریافت رنگ جدید getFavoriteColor رنگ رو پاس میده به تابعی که ما ساختیم و اون هم رنگ پس‌زمینه رو تغییر میده.

:)