نظرات اشتراک‌ها
پیشنهاد رسمی اضافه شدن type unions به زبان #C

این متد را درنظر بگیرید:

public Receipt PlaceOrder(Order order)
{
        var product = _products.SingleOrDefault(p => p.ProductId == order.ProductId);
        
        if (product is null)
        {
            throw new Exception("Product doesn't exist");
        }

        if (product.Cost > order.Payment)
        {
            throw new Exception("Insufficient funds");
        }

        var receipt = new Receipt(++_receiptId, order.Payment);
        _receipts.Add(receipt);
        return receipt;
}

برای استفاده کننده دقیقا مشخص نیست که این متد ممکن است چندین استثناء را هم صادر کند. با وجود type unions، می‌توان مقصود واضح‌تری را ارائه داد:

public (Receipt or PlaceOrderError) PlaceOrder(Order order)

هرچند در این لحظه، شبیه به این‌کار را با استفاده‌ از کتابخانه‌ی OneOf هم انجام می‌دهند و ... TypeScript هم که در اساس توسط قسمت مهمی از تیم #C طراحی شده، مدت‌هاست که به همراه چنین قابلیتی هست.

نظرات اشتراک‌ها
اعتبارسنجی Domain Model‎
با توجه به مطلب «طراحی و پیاده سازی زیرساختی برای مدیریت خطاهای حاصل از Business Rule Validationها در ServiceLayer» می‌توان طراحی زیر را انجام داد:
public class Customer
{
    public string Email { get; private set; }
    public string Name { get; private set; }

    private Customer(email, name)
    {
        Email = email;
        Name = name;
    }

    public static Result<Customer> New(string email, string name, INewCustomerPolicy policy)
    {
        var isUnique = policy.IsUnique(email);
        if (!isUnique)
        {
            return Result.Fail<Customer>("Customer with this email already exists.");
        }

        var customer = new Customer(email, name);

        //customer.AddDomainEvent(new CustomerRegistered(customer));

        return Result.Ok(customer);
    }
}
کلاس Result در زیرساخت DNTFrameworkCore قابل دسترس می‌باشد.
مطالب
ایجاد Helper سفارشی جهت نمایش ویدئو در ASP.NET MVC
معرفی HTML Helpers
در صورتی که در مورد Helper‌ها در ASP.NET MVC اطلاعات بیشتری نیاز دارید پیشنهاد می‌کنم ابتدا این مطلب + را مطالعه کنید.
 
ایجاد یک HTML Helper سفارشی برای نمایش ویدئو‌های سایت آپارات
قبل از ایجاد هر Helper ی باید با خروجی نهایی آن آشنا بود. پس از بررسی خروجی نهایی کافیست بخش هایی از آن را Optional کنیم تا در زمان استفاده از آن، نسبت به مقادیر این دسته از پارامترها تصمیم گیری کنیم.
سایت آپارات نمونه‌ی فارسی سایت YouTube است و امکان اشتراک گذاری فایل‌های ویدئویی را برای کاربران مهیا کرده است. در این سایت در صفحه نمایش هر ویدئو، بخشی با عنوان "دریافت کد ویدئو" وجود دارد. با کمی بررسی در کدهای نهایی ایجاد شده توسط دستورات ذکر شده در این بخش، کد نهایی برای نمایش یک ویدئو به صورت زیر خواهد بود:

<embed height="400" width="500" 
flashvars="config=http://www.aparat.com//video/video/config/videohash/BA9Md/watchtype/embed" 
allowfullscreen="true" 
quality="high" name="aparattv_BA9Md" id="aparattv_BA9Md" 
src="http://host10.aparat.com/public/player/aparattv" type="application/x-shockwave-flash">
برای تولید پویای این کد Helper زیر می‌تواند مفید باشد:
using System.Web.Mvc;

namespace MvcApplication1
{
    public static class AparatPlayerHelper
    {
        public static MvcHtmlString AparatPlayer(this HtmlHelper helper, string mediafile, int height, int width)
        {
            var player = @"<embed height=""{0}"" width=""{1}"" flashvars=""config=http://www.aparat.com//video/video/config/videohash/{2}/watchtype/embed"" 
                                allowfullscreen=""true"" 
                                quality=""high"" 
                                name=""aparattv_{2}"" id=""aparattv_{2}"""" src=""http://host10.aparat.com/public/player/aparattv"" 
                                type=""application/x-shockwave-flash"">";

            player = string.Format(player, height, width, mediafile);
            return new MvcHtmlString(player);
        }
    }
}
نحوه استفاده از این Helper:
@Html.AparatPlayer("BA9Md", 400, 500)
اگر به آدرس صفحات در سایت آپارات دقت کنید URL جاری به یک عبارت چند حرقی ختم می‌شود که از این عبارت به عنوان مقدار پارامتر mediafile و شناسه منحصر بفرد فایل ویدئو استفاده شده است.
ایجاد Helper سفارشی جهت نمایش ویدئو‌های YouTube:
با توجه به توضیحات فوق یک Helper سفارشی برای نمایش ویدئو‌های YouTube بصورت زیر است:
using System;
using System.Drawing;
using System.Web.Mvc;

namespace MvcApplication1
{

    public static class YouTubePlayerHelper
    {
        public static MvcHtmlString YouTubePlayer(this HtmlHelper helper, string playerId, string mediaFile, YouTubePlayerOption youtubePlayerOption)
        {

            const string baseURL = "http://www.youtube.com/v/";

            // YouTube Embedded Code
            var player = @"<div id=""YouTubePlayer_{7}""width:{1}px; height:{2}px;"">
                                 <object width=""{1}"" height=""{2}"">
                                 <param name=""movie"" value=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}""></param>
                                 <param name=""allowFullScreen"" value=""true""></param>
                                 <embed src=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}""
                                 type = ""application/x-shockwave-flash""
                                 width=""{1}"" height=""{2}"" allowfullscreen=""true""></embed>
                                 </object>
                             </div>";

            // Replace All The Value
            player = String.Format(player, mediaFile, youtubePlayerOption.Width, youtubePlayerOption.Height, (youtubePlayerOption.Border ? "1" : "0"), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.PrimaryColor), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.SecondaryColor), baseURL, playerId);

            //Retrun Embedded Code
            return new MvcHtmlString(player);
        }
    }

    public class YouTubePlayerOption
    {
        int _width = 425;
        int _height = 355;
        Color _color1 = Color.Black;
        Color _color2 = Color.Aqua;

        public YouTubePlayerOption()
        {
            Border = false;
        }

        public int Width { get { return _width; } set { _width = value; } }
        public int Height { get { return _height; } set { _height = value; } }
        public Color PrimaryColor { get { return _color1; } set { _color1 = value; } }
        public Color SecondaryColor { get { return _color2; } set { _color2 = value; } }
        public bool Border { get; set; }
    }

    public class ConvertColorToHexa
    {
        private static readonly char[] HexDigits =
            {
                '0', '1', '2', '3', '4', '5', '6', '7',
                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
            };

        public static string ConvertColorToHexaString(Color color)
        {
            var bytes = new byte[3];
            bytes[0] = color.R;
            bytes[1] = color.G;
            bytes[2] = color.B;
            var chars = new char[bytes.Length * 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                int b = bytes[i];
                chars[i * 2] = HexDigits[b >> 4];
                chars[i * 2 + 1] = HexDigits[b & 0xF];
            }
            return new string(chars);
        }


    }        

}
نحوه استفاده:
@Html.YouTubePlayer("Casablanca", "iLdqKUkkM6w", new YouTubePlayerOption()
                                {
                                    Border = true
                                })
در اینجا جهت مقداردهی پارمتر‌های پخش کننده ویدئو، از کلاس YouTubePlayerOption استفاده شده است.
مطالب
نمایش ای‌جکسی یک partial view در popover بوت استرپ 3
فرض کنید بخواهیم نمایش رای دهنده‌های یک مطلب را با popover بوت استرپ 3 نمایش دهیم:

Popover بوت استرپ برای کار با منابع remote طراحی نشده‌است و نیاز است توابع API آن‌را به همراه jQuery Ajax ترکیب کرد تا به تصویر فوق رسید.


مرحله‌ی اول: اکشن متدی که یک partial view را باز می‌گرداند

فرض کنید اکشن متدی که لیست کاربران رای داده‌ی به یک مطلب را باز می‌گرداند، چنین شکلی را دارد:
        public ActionResult RenderResults(string param1)
        {
            var users = new[]
            {
                new User{ Id = 1, Name = "Test 1", Rating = 3},
                new User{ Id = 2, Name = "Test 2", Rating = 4},
                new User{ Id = 3, Name = "Test 3", Rating = 5}
            };
            return PartialView("_RenderResults", model: users);
        }
در اینجا لیستی دریافت و سپس به partial view ارسال می‌شود. در ادامه این Partial view نیز به صورت ذیل اطلاعات را رندر می‌کند:
@using RemotePopOver.Models
@model IList<User>

<ul id="ratings1" data-title="Ratings" class="list-unstyled">
    @foreach (var user in Model)
    {
        <li>
            @user.Name
            <span class="badge pull-right">@user.Rating</span>
        </li>
    }
</ul>
در اینجا از یک ویژگی سفارشی data-* به نام data-title نیز استفاده کرده‌ایم. متنی که در آن قرار می‌گیرد، به صورت عنوان popover ظاهر خواهد شد.


مرحله‌ی دوم: دریافت اطلاعات partial view با استفاده از jQuery Ajax و سپس درج آن در یک popover

می‌خواهیم با حرکت ماوس بر روی دکمه‌ی سفارشی ذیل، یک popover ظاهر شده و محتوای خودش را از اکشن متد فوق تامین کند.
<span id="remotePopover1"
      aria-hidden="true"
      data-param1="test"
      data-popover-content-url="@Url.Action("RenderResults", "Home")"
      class="glyphicon glyphicon-info-sign btn btn-info"></span>
در این مثال، چند ویژگی سفارشی data-* دیگر را نیز تعریف کرده‌ایم تا نیازی به تعریف سراسری متغیرهای جاوا اسکریپتی نباشد. برای مثال data-param1 یک پارامتر دلخواه است و data-popover-content-url به آدرس اکشن متدی اشاره می‌کند که قرار است partial view مدنظر را رندر کند.
در ادامه نحوه‌ی استفاده‌ی از این ویژگی‌ها را در jQuery Ajax مشاهده می‌کنید:
@section Scripts
{
    <script type="text/javascript">
        $(document).ready(function () {
            $('body').on('mouseenter', 'span[data-popover-content-url]', function () {
                var el = $(this);
                $.ajax({
                    type: "POST",
                    url: $(this).data("popover-content-url"),
                    data: JSON.stringify({ param1: $(this).data("param1") }),
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    // controller is returning a simple text, not json
                    complete: function (xhr, status) {
                        var data = xhr.responseText;
                        if (status === 'error' || !data) {
                            el.popover({
                                content: 'Error connecting server!',
                                trigger: 'focus',
                                html: true,
                                container: 'body',
                                placement: 'auto',
                                title: 'Error!'
                            }).popover('show');
                        }
                        else {
                            el.popover({
                                content: data,
                                trigger: 'focus',
                                html: true,
                                container: 'body',
                                placement: 'auto',
                                title: $('<html />').html(data).find('#ratings1:first').data('title')
                            }).popover('show');
                        }
                    }
                });
            }).on('mouseleave', 'span[data-popover-content-url]', function () {
                $(this).popover('hide');
            });
        });
    </script>
}
در این مثال تمام المان‌هایی که دارای data-popover-content-url هستند، تحت نظر قرار می‌گیرند. سپس اگر ماوس به محدوده‌ی آن‌ها وارد شد، مقدار ("this).data("popover-content-url)$ مساوی آدرسی است که قرار است اطلاعات را از سرور دریافت کند. به همین جهت از آن برای استفاده‌ی در متد ajax کمک گرفته شده‌است.
خروجی partial view به صورت json نیست. بنابراین باید اطلاعات نهایی آن‌را در callback ویژه‌ی complete دریافت کرد. مقدار data دریافتی، معادل اطلاعات رندر شده‌ی partial view است. به همین جهت آن‌را به خاصیت content متد popver ارسال می‌کنیم. همچنین چون خروجی patrtial view به همراه html است، نیاز است خاصیت html متد popover نیز به true تنظیم شود. در خاصیت title، نحوه‌ی دسترسی به مقدار data-title تنظیم شده‌ی در partial view را مشاهده می‌کنید.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
RemotePopOver.zip
نظرات مطالب
صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid
با سلام و خدا قوت

آقای نصیری، model ای که باید در قسمت schema تعریف بشه چطوری میشه اونو دینامیک تولید کرد.
من یک چنین حالتی رو ایجاد کردم ولی نمی‌دونم چطوری باید اسم ستونو براش مشخص کنم.
public class Field
    {
        public string Type { get; set; }
    }

public class Fields : System.Collections.ObjectModel.Collection<Field>
    {
        public System.Collections.IEnumerable ToList()
        {
            return System.Linq.Enumerable.ToList( System.Linq.Enumerable.Select( this ,
                                                                                 field => new { field.Type } ) );
        }
    }
این قسمت اطلاعاتی است که برای ایجاد گرید باز گردانده می‌شود.
return new InitializeInfo
                   {
                           ...
                           Model = GetModel()
                   };

private Model GetModel ()
        {
            return new Model{ Fields = GetFields().ToList() };
        }
متد GetColumns شامل 3 ستون می‌باشد که نوع، عنوان و سایر مشخصات رو توش تعریف کردم
private Fields GetFields()
        {
            var fields = new Fields();
            foreach ( var column in GetColumns() )
            {
                fields.Add( new Field { Type = column.DataType } );
            }
            return fields;
        }
الان خروجی که تولید میشه اینجوریه
"model": {

    "fields": [
        {
            "type": "string"
        },
        {
            "type": "string"
        },
        {
            "type": "datetime"
        }
    ]
}

ممنون میشم یه راهنمایی کنید.
نظرات مطالب
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت ششم - تکمیل مستندات محافظت از API
برای JWT این تغییر را نیاز دارد (توکن دریافتی را پس از لاگین/تولید باید دستی وارد کنید):

services.AddSwaggerGen(c =>
{
    // ... 
    var security = new Dictionary<string, IEnumerable<string>>
    {
        {"Bearer", new string[] { }},
    }; 
    c.AddSecurityDefinition("Bearer", new ApiKeyScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = "header",
        Type = "apiKey"
    });
    c.AddSecurityRequirement(security);
});
پاسخ به بازخورد‌های پروژه‌ها
تراز یک ستون بر اساس مقدار ستون دیگر
باید از نکته مطلب «ایجاد قالب‌های سفارشی ستون‌ها و فرمت شرطی اطلاعات در PdfReport » استفاده کنید. مثلا:
column.ColumnItemsTemplate(template =>
                     {
                         template.TextBlock();
                         template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", Math.Abs((long)obj)));
                         template.ConditionalFormatFormula(list =>
                         {
                             var currentRowCredit = (long)list.GetValueOf<Payment>(x => x.Credit);
                             if (currentRowCredit > 0)
                             {
                                 return new CellBasicProperties
                                 {
                                     FontColor = new BaseColor(System.Drawing.Color.Brown.ToArgb()),
                                     HorizontalAlignment = HorizontalAlignment.Right
                                 };
                             }
                             return new CellBasicProperties { PdfFontStyle = DocumentFontStyle.Normal };
                         });
                     });
بازخوردهای پروژه‌ها
ارسال به JsonResult
با سلام
به چه صورت میشه فایل pdf از طریق Jsonresult فلش کرد؟
public JsonResult PdfReport(ReportViewModel model)
        {
            if (model == null)
                return Json(new
                {
                    success = false
                },
                    JsonRequestBehavior.AllowGet);
            var report = new GeneratePdfReport();
            report.CreatePdfReport(AutoMapperHelper.Map<ReportViewModel, Report>(model));
            return Json(new
            {
                success = true
            }, JsonRequestBehavior.AllowGet);
        }
 و برای flash کردن:
fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8);
                    data.FlushInBrowser(fileName, FlushType.Inline);
اما فایل پی دی اف attach نمیشه
نظرات مطالب
سفارشی کردن ASP.NET Identity در MVC 5
با سلام و احترام 
من دستور زیر رو تو asp.net mvc Identity sample 2 تو اکشن Login  اضافه کردم 
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));         
    var user = UserManager.FindById(User.Identity.GetUserId());
اما user و null میده !
اکشن login
 public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            // This doen't count login failures towards lockout only two factor authentication
            // To enable password failures to trigger lockout, change to shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {

                case SignInStatus.Success:
                    {
                        UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
                        var user = UserManager.FindById(User.Identity.GetUserId());
                        return RedirectToLocal(returnUrl);
                    }
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }
        }

مطالب دوره‌ها
متدهای الحاقی و ترکیب کننده‌های اعمال غیرهمزمان
تعدادی متد جدید در دات نت 4.5 جهت ترکیب و کار با Taskها اضافه شده‌اند. نمونه‌ای از آن‌را در قسمت‌های قبل با معرفی متد WhenAll مشاهده کردید. در ادامه قصد داریم این متدها را  بیشتر بررسی کنیم.


متد WhenAll
کار آن ترکیب تعدادی Task است و اجرای آن‌ها. تنها زمانی خاتمه می‌یابد که کلیه‌ی Taskهای معرفی شده به آن خاتمه یافته باشند. هدف از آن اجرای همزمان و مستقل چندین Task است. برای مثال دریافت چندین فایل به صورت همزمان از اینترنت.
همچنین باید دقت داشت که در اینجا، هر Task کاری به نتایج Taskهای دیگر ندارد و کاملا مستقل اجرا می‌شود. اگر نیاز است Taskها مستقل اجرا شوند، از همان روش سریالی اجرای Taskها، توسط معرفی هر کدام به کمک await استفاده کنید.
به علاوه اگر در این بین استثنایی وجود داشته باشد، تنها پس از پایان عملیات تمام Taskها بازگشت داده می‌شود. این استثناء نیز از نوع Aggregate Exception است.
using System.Linq;
using System.Threading.Tasks;

namespace Async07
{
    public class EggBoiler
    {
        private const int BoilingTimeMs = 200;

        private static Task boilEgg()
        {
            var bolingTask = Task.Run(() =>
            {
                Task.Delay(BoilingTimeMs);
            });
            return bolingTask;
        }

        public async Task BoilEggsSequentialAsync(int count)
        {
            for (var i = 0; i < count; i++)
            {
                await boilEgg();
            }
        }

        public async Task BoilEggsSimultaneousAsync(int count)
        {
            var tasksList = from egg in new[] { 1, 2, 3, 4, 5 }
                            select boilEgg();
            await Task.WhenAll(tasksList);
            // ...
        }
    }
}
در این مثال عمل پختن تخم مرغ را در یک مدت زمان مشخصی ملاحظه می‌کنید. در متد BoilEggsSequentialAsync، پختن تخم مرغ‌ها، ترتیبی است. ابتدا مورد اول انجام می‌شود و پس از پایان آن، مورد دوم و الی آخر. در اینجا اگر نیاز باشد، می‌توان از نتیجه‌ی عملیات قبلی، در عملیات بعدی استفاده کرد.
 اما در متد BoilEggsSimultaneousAsync به علت بکارگیری Task.WhenAll پختن تمام تخم مرغ‌های مدنظر همزمان آغاز می‌شود و تا پایان عملیات (پخته شدن تمام تخم مرغ‌ها) صبر خواهد شد.


متد WhenAny

در حالت استفاده از متد WhenAny، هر کدام از Taskهای در حال پردازش که خاتمه یابند، کل عملیات خاتمه خواهد یافت. فرض کنید نیاز دارید تا دمای کنونی هوای منطقه‌ی خاصی را از چند وب سرویس مختلف دریافت کنید. می‌توان در این حالت تمام این‌ها را توسط WhenAny ترکیب کرد و هر کدام که زودتر خاتمه یابد، عملیات را پایان خواهد داد.
    public class Downloader
    {
        private Task<string> downloadTask(string url)
        {
            return new WebClient().DownloadStringTaskAsync(url);
        }

        public async Task<int> GetTemperature()
        {
            var sites = new[]
            {
                "http://www.site1.com/svc",
                "http://www.site2.com/svc",
                "http://www.site3.com/svc",
            };
            var tasksList = from site in sites
                            select downloadTask(site);
            try
            {
                var finishedTask = await Task.WhenAny(tasksList);
                var result = await finishedTask;

            }
            catch (Exception ex)
            {

            }

            // todo: process result, get temperature
            return 10; // for example.
        }
    }
در اینجا نحوه‌ی استفاده از WhenAny را مشاهده می‌کنید. نکته‌ی مهم این مثال، استفاده از await دوم بر روی Task بازگشت داده شده‌است. این مساله از این لحاظ مهم است که Task بازگشت داده شده الزامی ندارد که حتما با موفقیت پایان یافته باشد. فراخوانی await بر روی نتیجه‌ی آن سبب خواهد شد تا اگر استثنایی در این بین رخ داده باشد، قابل دریافت و پردازش شود.
در این حالت اگر نیاز بود وضعیت سایر Taskها، مثلا در صورت شکست آن‌ها، بررسی شوند، می‌توان از یکی از دو قطعه کد زیر استفاده کرد:
            foreach (var task in tasksList)
            {
                var ignored = task.ContinueWith(
                    t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
            }

            // or
            foreach (var task in tasksList)
            {
                var ignored = task.ContinueWith(
                    t =>
                    {
                        if (t.IsFaulted)
                            Console.WriteLine(t.Exception);
                    });
            }

کاربرد دیگر WhenAny زمانی است که برای مثال می‌خواهید تعداد زیادی Url را پردازش کنید، اما نمی‌خواهید برای نمایش اطلاعات، تا پایان عملیات تمامی آن‌ها مانند WhenAll صبر کنید. می‌خواهید به محض پایان کار یکی از Taskها، عملیات نمایش نتیجه‌ی آن‌را انجام دهید:
        public async Task ShowTemperatures()
        {
            var sites = new[]
            {
                "http://www.site1.com/svc",
                "http://www.site2.com/svc",
                "http://www.site3.com/svc",
            };
            var tasksList = sites.Select(site => downloadTask(site)).ToList();

            while (tasksList.Any())
            {
                try
                {
                    var tempTask = await Task.WhenAny(tasksList);
                    tasksList.Remove(tempTask);

                    var result = await tempTask;
                    //todo: show result
                }
                catch(Exception ex) { }
            }
        }
در اینجا در یک حلقه، هر Taskایی که زودتر پایان یابد، نمایش داده شده و سپس از لیست وظایف حذف می‌شود. در ادامه مجددا یک await روی آن انجام خواهد شد تا استثنای احتمالی آن بروز کند. سپس اگر مشکلی نبود، می‌توان نتیجه را نمایش داد.

کاربرد سوم WhenAny کنترل تعداد وظایف همزمان است. برای مثال اگر قرار است هزاران تصویر از اینترنت دریافت شوند، نباید تمام وظایف را یکجا راه اندازی کرد. شاید نیاز باشد هربار فقط 15 وظیفه‌ی همزمان عمل کنند و نه بیشتر. در این حالت، مثال قبلی دارای یک حلقه‌ی کنترل کننده tasksList ارائه شده خواهد شد. هر بار تعداد معینی وظیفه به tasksList اضافه و پردازش می‌شوند و این روند تا پایان کار تعداد Urlها ادامه خواهد یافت (یک Take و Skip است؛ مانند صفحه بندی اطلاعات).


متدهای Run و FromResult

متد Task.Run اضافه شده در دات نت 4.5 به این معنا است که می‌خواهید Task ایجاد شده بر روی Thread pool اجرا شود. پارامتر آن می‌تواند یک delegate یا عبارت lambda و یا حتی یک Task باشد. خروجی آن نیز یک Task است و به همین جهت با async و await سی شارپ 5 سازگاری بهتری دارد.
استفاده از Task.Run نسبت به عملیات Threading متداول کارآیی بهتری دارد، زیرا ایجاد Threadهای جدید زمانبر بوده و زمانیکه به صورت خودکار از Thread pool استفاده می‌شود، تا حد امکان، استفاده‌ی مجدد از تردهای بیکار در حال حاضر، مدنظر است.

متد Task.FromResult کار بازگشت یک Task را از نتایج متدهای مختلف فراهم می‌کند. فرض کنید یک متد async تعریف کرده‌اید که خروجی آن Task of T است. در اینجا اگر داخل متد، از یک متد معمولی که یک عدد int را ارائه می‌دهد استفاده کنیم، با استفاده از Task.FromResult بلافاصله می‌توان یک Task of int را بازگشت داد.


متد Delay

پیشتر برای به خواب فرو بردن یک ترد از متد Thread.Sleep استفاده می‌شد. کار Thread.Sleep بلاک کردن ترد جاری است. در دات نت 4.5، بجای آن باید از Task.Delay استفاده شود که یک مکانیزم غیر قفل کننده را جهت صبر کردن به همراه بازگشت یک Task، ارائه می‌دهد.
یکی از کاربردهای Delay منهای صبر کردن تا مدت زمانی مشخص، ایجاد مکانیزم timeout است. برای مثال حالت Task.WhenAny را درنظر بگیرید. اگر در اینجا timeout مدنظر ما 3 ثانیه باشد، می‌توان یکی از Taskها را Task.Delay با آرگومان مساوی 3000 معرفی کرد. اگر هر کدام از taskهای تعریف شده زودتر از 3 ثانیه پایان یافتند که بسیار خوب؛ در غیر اینصورت Task.Delay معرفی شده کار را تمام می‌کند.


متد Yield
متد Task.Yield بسیار شبیه به متد قدیمی DoEvents است که از آن برای اجازه دادن به سایر اعمال جهت اجرا، در بین یک عمل طولانی، استفاده می‌شد.


متد ConfigureAwait

به صورت پیش فرض ادامه یک عملیات همزمان، بر روی ترد ایجاد کننده‌ی آن اجرا می‌شود. برای نمونه اگر یک عملیات async در ترد UI آغاز شود، نتیجه‌ی آن نیز در همان ترد UI بازگشت داده می‌شود. به این ترتیب دیگر نیازی نخواهد بود تا نگرانی در مورد نحوه‌ی دسترسی به مقدار آن توسط عناصر UI داشته باشیم.
اگر به این مساله اهمیت نمی‌دهید، برای مثال اگر اعمال در حال انجام، کاری به عناصر UI ندارند، از متد ConfigureAwait با پارامتر false بر روی یک task پیش از فراخوانی await بر روی آن، استفاده کنید.
 byte [] buffer = new byte[0x1000];
int numRead;
while((numRead = await source.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{
  await source.WriteAsync(buffer, 0, numRead).ConfigureAwait(false);
}
این مثال در طی یک حلقه، هر بار مقدار کوچکی از منبع ارائه شده به آن را می‌خواند. در اینجا تعداد await cycles قابل توجهی وجود دارند. در هر سیکل نیز از دو فراخوانی async استفاده می‌شود؛ یکی برای انجام عملیات و دیگری برای بازگشت نتیجه به Synchronization Context آغاز کننده آن. با استفاده از ConfigureAwait false زمان اجرای این حلقه به شدت بهبود خواهد یافت و کوتاه‌تر خواهد شد؛ زیرا فاز هماهنگی آن با Synchronization Context حذف می‌شود.



به صورت خلاصه در سی شارپ 5

- بجای task.Wait قدیمی، از await task برای صبر کردن تا پایان یک task استفاده کنید.
- بجای task.Result جهت دریافت یک نتیجه‌ی یک task از await task کمک بگیرید.
- بجای Task.WaitAll از await Task.WhenAll و بجای Task.WaitAny از await Task.WhenAny استفاده نمائید.
- همچنین Thread.Sleep در اعمال async با await Task.Delay جایگزین شده‌است.
- در اعمال غیرهمزمان همیشه متد ConfigureAwait false را بکار بگیرید، مگر اینکه به Context نهایی آن واقعا نیاز داشته باشید.
و برای ایجاد یک Task جدید از Task.Run یا TaskFactory.StartNew استفاده نمائید.