نظرات مطالب
‫نکات نصب برنامه‌های ASP.NET 4.0 بر روی IIS 6
خیر. «باید» به ازای هر برنامه یک application pool مجزا درست کنید. برای مطالعه بیشتر:
- برای مدیریت نگارش‌های مختلف دات نت مورد استفاده (مطلب جاری)
- جهت مدیریت بهتر میزان مصرف حافظه یک برنامه: مروری بر تاریخچه محدودیت حافظه مصرفی برنامه‌های ASP.NET در IIS
- برای جلوگیری از ری‌استارت شدن بی‌جهت سایر برنامه‌ها: چه زمان‌هایی یک برنامه‌ی ASP.NET ری استارت می‌شود؟    
- جهت کنترل میزان مصرف CPU یک برنامه: بررسی علت CPU Usage بالای برنامه در حال اجرا   
مطالب
فراخوانی سرویس های WCF به صورت Async
هنگام تولید و توسعه سیستم‌های مبتنی بر WCF حتما نیاز به سرویس هایی داریم که متد‌ها را به صورت Async اجرا کنند. در دات نت 4.5 از Async&Await استفاده می‌کنیم(^). ولی در پروژه هایی که تحت دات نت 4 هستند این امکان وجود ندارد(البته می‌تونید Async&Await CTP رو برای دات نت 4 هم نصب کنید(^ )). فرض کنید پروژه ای داریم تحت دات نت 3.5 یا 4 و قصد داریم یکی از متد‌های سرویس WCF آن را به صورت Async پیاده سازی کنیم. ساده‌ترین روش این است که هنگام Add Service Reference از پنجره Advanced  به صورت زیر عمل کنیم:


مهم‌ترین عیب این روش این است که در این حالت تمام متد‌های این سرویس رو هم به صورت Sync و هم به صورت Async تولید می‌کنه در حالی که ما فقط نیاز به یک متد Async داریم.

 در این پست قصد دارم پیاده سازی این متد رو بدون استفاده از Async&Await و Code Generation توکار دات نت شرح بدم که با دات نت 3.5 هم سازگار است.

ابتدا یک پروژه از نوع WCF Service Application ایجاد کنید.
یک ClassLibrary جدید به نام Model بسازید و کلاس زیر را به عنوان مدل در آن قرار دهید.(این اسمبلی باید هم به پروژه‌های کلاینت و هم به پروژه‌های سرور رفرنس داده شود)
    [DataContract]
    public class Book
    {
        [DataMember]
        public int Code { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Author { get; set; }
    }
حال  پیاده سازی سرویس و Contract مربوطه را شروع می‌کنیم.
#Class Library به نام Contract بسازید. قصد داریم از این لایه به عنوان قرارداد‌های سمت کلاینت و سرور استفاده کنیم. اینترفیس زیر را به عنوان BookContract در آن بسازید.
   [ServiceContract]
    public interface IBookService
    {
        [OperationContract( AsyncPattern = true )]
        IAsyncResult BeginGetAllBook( AsyncCallback callback, object state );

        IEnumerable<Book> EndGetAllBook( IAsyncResult asyncResult ); 
    }
برای پیاده سازی متد‌های Async به این روش باید دو متد داشته باشیم. یکی به عنوان شروع عملیات و دیگری اتمام. دقت کنید نام گذاری به صورت Begin و End کاملا اختیاری است و برای خوانایی بهتر از این روش نام گذاری استفاده می‌کنم. متدی که به عنوان شروع عملیات استفاده می‌شود باید حتما OperationContractAttribute رو داشته باشد و مقدار خاصیت AsyncPattern اون هم true باشد. همان طور که می‌بیند این متد دارای 2 آرگومان وروردی است. یکی از نوع AsyncCallback و دیگری از نوع object. تمام متد‌های Async به این روش باید این دو آرگومان ورودی را حتما داشته باشند. خروجی این متد حتما باید از نوع IAsyncResult باشد. متد دوم که به عنوان اتمام عملیات استفاده می‌شود نباید OperationContractAttribute را داشته باشد. ورودی اون هم فقط یک آرگومان از نوع IAsyncResult است. خروجی اون هم هر نوعی که سمت کلاینت احتیاج دارید می‌تونه باشه . در صورت عدم رعایت نکات فوق، هنگام ساخت  ChannelFactory یا خطا روبرو خواهید شد. اگر نیاز به پارامتر دیگری هم داشتید باید آن‌ها را قبل از این دو پارامتر قرار دهید. برای مثال:
[OperationContract]
IEnumerable<Book> GetAllBook(int code , AsyncCallback callback, object state );
قبل از پیاده سازی سرویس باید ابتدا یک AsyncResult سفارشی بسازیم. ساخت AsyncResult سفارشی بسیار ساده است. کافی است کلاسی بسازیم که اینترفیس IAsyncResult را به ارث ببرد.
 public class CompletedAsyncResult<TEntity> : IAsyncResult where TEntity : class , new()
    {
        public IList<TEntity> Result
        {
            get
            {
                return _result;
            }
            set
            {
                _result = value;
            }
        }
        private IList<TEntity> _result;

        public CompletedAsyncResult( IList<TEntity> data )
        {
            this.Result = data;
        }

        public object AsyncState
        {
            get
            {
                return ( IList<TEntity> )Result;
            }
        }

        public WaitHandle AsyncWaitHandle
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool CompletedSynchronously
        {
            get
            {
                return true;
            }
        }

        public bool IsCompleted
        {
            get
            {
                return true;
            }
        }
    }
در کلاس بالا یک خاصیت به نام Result درنظر گرفتم که لیستی از نوع TEntity است.(TEntityبه صورت generic تعریف شده و نوع ورودی آن هر نوع کلاس غیر abstract می‌تواند باشد). این کلاس برای تمام سرویس‌های Async یک پروژه مورد استفاده قرار خواهد گرفت برای همین ورودی آن به صورت generic در نظر گرفته شده است.
#پیاده سازی سرویس
 public class BookService : IBookService
    {
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

        public List<Book> ListOfBook
        {
            get;
            private set;
        }

        private List<Book> CreateListOfBook()
        {
            Parallel.For( 0, 10000, ( int counter ) =>
            {
                ListOfBook.Add( new Book()
                {
                    Code = counter,
                    Title = String.Format( "Book {0}", counter ),
                    Author = "Masoud Pakdel"
                } );
            } );

            return ListOfBook;
        }

        public IAsyncResult BeginGetAllBook( AsyncCallback callback, object state )
        {
            var result = CreateListOfBook();
            return new CompletedAsyncResult<Book>( result );
        }

        public IEnumerable<Book> EndGetAllBook( IAsyncResult asyncResult )
        {
            return ( ( CompletedAsyncResult<Book> )asyncResult ).Result;
        }
    }
*در متد BeginGetAllBook ابتدا به تعداد 10,000 کتاب در یک لیست ساخته می‌شوند و بعد این لیست در کلاس CompletedAsyncResult که ساختیم به عنوان ورودی سازنده پاس داده می‌شوند. چون CompletedAsyncResult از IAsyncResult ارث برده است پس return آن به عنوان خروجی مانعی ندارد. با فراخوانی متد EndGetAllBook سمت کلاینت  مقدار asyncResult به عنوان خروجی برگشت داده می‌شود. به عملیات casting برای دستیابی به مقدار Result در CompletedAsyncResult دقت کنید.
#کد‌های سمت کلاینت:
اکثر برنامه نویسان با استفاده از روش AddServiceReference یک سرویس کلاینت در اختیار خواهند داشت که با وهله سازی از این کلاس یک ChannelFactory ایجاد می‌شود. در این پست به جای استفاده از Code Generation توکار دات نت برای ساخت ChannelFactory از روش دیگری استفاده خواهیم کرد. به عنوان برنامه نویس باید بدانیم که در پشت پرده عملیات ساخت ChannelFactory چگونه است.
 روش AddServiceReference
بعد از اضافه شدن سرویس سمت کلاینت کد‌های زیر برای سرویس Book به صورت زیر تولید می‌شود.
[System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class BookServiceClient : System.ServiceModel.ClientBase<UI.BookService.IBookService>, UI.BookService.IBookService {
        
        public BookServiceClient() {
        }
        
        public BookServiceClient(string endpointConfigurationName) : 
                base(endpointConfigurationName) {
        }
        
        public BookServiceClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }
        
        public BookServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }
        
        public BookServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress) {
        }
        
        public UI.BookService.Book[] BeginGetAllBook() {
            return base.Channel.BeginGetAllBook();
        }
    }
همانطور که می‌بینید سرویس بالا از کلاس ClientBase ارث برده است. ClientBase دارای خاصیتی به نام ChannelFactory است که فقط خواندنی می‌باشد. با استفاده از مقادیر EndPointConfiguration یک وهله از کلاس ChannelFactory با توجه به مقدار generic کلاس clientBase ایجاد خواهد شد. در کد زیر مقدار TChannel برابر IBookService است:
System.ServiceModel.ClientBase<UI.BookService.IBookService>
وهله سازی از ChannelFactory به صورت دستی
یک پروژه ConsoleApplication سمت کلاینت ایجاد کنید. برای فراخوانی متد‌های سرویس سمت سرور باید ابتدا تنظیمات EndPoint رو به درستی انجام دهید. سپس با استفاده از EndPoint به راحتی می‌توانیم Channel مربوطه را بسازیم.
کلاسی به نام ServiceMapper ایجاد می‌کنیم که وظیفه آن ساخت ChannelFactory به ازای درخواست‌ها است.
public class ServiceMapper<TChannel>
    {
        public static TChannel CreateChannel()
        {
            TChannel proxy;

            var endPointAddress = new EndpointAddress( "http://localhost:7000/" + typeof( TChannel ).Name.Remove( 0, 1 ) + ".svc" );

            var httpBinding = new BasicHttpBinding();
            
            ChannelFactory<TChannel> factory = new ChannelFactory<TChannel>( httpBinding, endPointAddress );

            proxy = factory.CreateChannel();

            return proxy;
        }
    }
در متد CreateChannel یک وهله از کلاس EndPointAddress ایجاد شده است. پارامتر ورودی آن آدرس سرویس هاست شده می‌باشد برای مثال:

"http://localhost:7000/" +  "BookService.svc"
دستور Remove برای حذف I از ابتدای نام سرویس است. پارامتر‌های ورودی برای سازنده کلاس ChannelFactory ابتدا یک نمونه از کلاس BasicHttpBinding می‌باشد. می‌توان از WSHttpBinding یا NetTCPBinding یا WSDLHttpBinding هم استفاده کرد. البته هر کدام از انواع Binding‌ها تنظیمات خاص خود را می‌طلبد که در مقاله ای جداگانه بررسی خواهم کرد. پارامتر دوم هم EndPoint ساخته شده می‌باشد. در نهایت با دستور CreateChannel عملیات ساخت Channel به پایان می‌رسد.

بعد از اعمال تغییرات زیر در فایل Program پروژه Console و اجرای آن، خروجی به صورت زیر می‌باشد.
  var channel = ServiceMapper<Contract.IBookService>.CreateChannel();
            channel.BeginGetAllBook( new AsyncCallback( ( asyncResult ) => 
            {
                channel.EndGetAllBook( asyncResult ).ToList().ForEach( _record => 
                {
                    Console.WriteLine( _record.Title );
                } );
            } ) , null );
            Console.WriteLine( "Loading..." );
            Console.ReadLine();
همان طور که می‌بینید ورودی متد BeginGtAllBook یک AsyncCallback است که در داخل آن متد EndGetAllBook صدا زده شده است. مقدار برگشتی متد EndGetAllBook خروجی مورد نظر ماست.
خروجی : 


نکته: برای اینکه مطمئن شوید که سرویس مورد نظر در آدرس "http"//localhost:7000/" هاست شده است(یعنی همان آدرسی که در EndPointAddress از آن استفاه کردیم) کافیست از پنجره Project Properties  برای پروژه سرویس وارد برگه Web شده و از بخش Servers گزینه Use Visual Studio Development Server و Specific Port 7000 رو انتخاب کنید.

 
نظرات مطالب
تبدیل برنامه‌های کنسول ویندوز به سرویس ویندوز ان تی
من برای شرکتی چندسال قبل یک چنین برنامه‌ای رو تهیه کردم:
یک سرویس ویندوز ان تی که روزهای اول به پورت سریال دستگاه کارتخوان متصل می‌شد و بعدها این پورت تبدیل شد به پورت شبکه و ریموت هم می‌شد به آن وصل شد؛ اما باز هم این پورت شبکه تبدیلگری بود برفراز سیستم اصلی RS232 آن دستگاه. کار این سرویس که نیاز به دسترسی بالایی برای اتصال به پورت‌های سیستم داشت و همچنین همیشه در حال اجرا بود و راه اندازی آن نیازی به لاگین شخصی و اجرای دستی برنامه نداشت (مزیت سرویس‌های ویندوز ان تی)، اتصال هر 5 دقیقه یکبار به دستگاه کارتخوان، تخلیه اطلاعات آن و ثبت آن‌ها در بانک اطلاعاتی یک برنامه ASP.NET بود. به این ترتیب کارکنان آن سازمان می‌توانستند از ورود و خروج خودشان با یک برنامه تحت وب (در شبکه داخلی شرکت) گزارشگیری کنند.
نظرات مطالب
SignalR
سلام.
آیا  این امکان وجود داره که SingnalR   رو  با  RestFull سرویس  در سمت سرور  ترکیب کنم   و  از  سرویس در سمت کلاینت ، داخل یک  برنامه  WPF   استفاده کتم؟
بازخوردهای دوره
بررسی Semantic Search و FTS Table-valued functions
- گوگل اگر واژه‌ای را به اشتباه وارد کرده باشید، غلط‌یاب آن این اصلاح را انجام می‌دهد؛ چیزی شبیه به «نحوه اضافه کردن قابلیت غلط گیر املایی شبیه به جستجوی گوگل توسط لوسین» و یا مفهوم Thesaurus در اینجا «8) جستجو برای یافتن متشابهات».  
- مابقی آن همان موارد rank و score‌ایی است که در اینجا مشاهده می‌کنید (مرتب سازی نتیجه‌ی بازگشتی بر اساس این پارامترهای ویژه و تعیین وزن و اهمیت برای آن‌ها).
بازخوردهای دوره
بررسی Semantic Search و FTS Table-valued functions
با سلام ؛ زمانی که شما در گوگل سرچ انجام میدید گوگل جمله شما رو اصلاح کرده و به شما پیشنهاد میدهد سوال من اینکه چطور میتونم این موضوع رو تو سرچ‌های خودم پیاده سازی کنم به طور مثال کاربر من سرچ کرده سینمای آزادی الگوریتم اگه فرض باشه که الگوریتم اینجا کلمه بی ربطی و بخوام سرچمو اصلاح کنم به چه شکل میتونم اینکار رو انجام بدم
نظرات اشتراک‌ها
بحثی در مورد تغییرات اخیر سایت Medium
اگر قصد نصب افزونه‌ای را ندارید، برای مشاهده‌ی یک صفحه در کش گوگل، بر روی نوار ابزار bookmarks مرورگر خود، راست کلیک کرده و یک bookmark جدید را با URL زیر به آن اضافه کنید:
javascript:location.href='https://webcache.googleusercontent.com/search?q=cache:'+encodeURIComponent(location.href)
پس از این اینکار، با کلیک بر روی این دکمه‌ی جدید، صفحه‌ی جاری در حال مرور را در کش گوگل مشاهده خواهید کرد و اگر محتوای صفحه‌ی باز شده قابل مشاهده نبود، حالت Text version آن‌را آزمایش کنید.
اشتراک‌ها
وبینار بررسی روش‌ها و ابزارهای بنچمارکینگ کد

این ایونت «احتمالا» بخش اول سری بنچمارکینگ است، قصد دارم اهمیت و نکات بنچمارکینگ رو مرور کنیم و در بخش اول، روی دات‌نت و اس‌کیوال سرور کار خواهیم کرد و اگر استقبال بشه، در بخش دوم روی روی لایبری‌های گو کار کنیم.

کانال تلگرام

اضافه کردن به تقویم گوگل

لینک گوگل میت

یکشنبه ۱۸ شهریور/ ۸ سپتامبر

ساعت ۶:۳۰ (به وقت تهران)، مدت: ۱ ساعت

وبینار بررسی روش‌ها و ابزارهای بنچمارکینگ کد
نظرات مطالب
بهبود SEO در ASP.NET MVC
یک نکته تکمیلی دیگر:
<a href="/contactus?name=وحید نصیری" rel="nofollow">ارسال پیام خصوصی</a>
اگر در سایت لینک‌هایی دارید که نیاز به اعتبارسنجی و لاگین دارند، این‌ها را با rel=nofollow مشخص کنید تا توسط گوگل ایندکس نشوند و تمام آن‌ها به یک صفحه تکراری (از دیدگاه گوگل) ختم نگردند.
مطالب
فید اشتراک‌های من در گوگل ریدر
مدتی لیست مطالب مورد علاقه را به شکل هفتگی در این سایت ارائه دادم (تازه‌های هفته ...)، سپس تبدیل شد به ارائه‌ی همان‌ها در سایت‌های به اشتراک گذاری لینک و الان هم به نظر من بهترین روش، استفاده از گزینه‌ی Share در گوگل ریدر است. به این صورت یک فید خودکار از موارد به اشتراک گذاشته شده را می‌توان تهیه کرد: