مطالب
کاربرد Action ها در Github - خودکار سازی فرآیند کامپایل و آپلود فایل در Release گیت‌هاب
نکته: این آموزش مبتنی بر دات نت نسخه 5 می‌باشد (قابل استفاده در نسخه 3.0 و 3.1 نیز می‌باشد اما تست نشده است). در این آموزش فرض شده‌است که شما توانایی کار کردن با git و گیت‌هاب را دارید. همچنین دقت کنید که گزینه‌های زیر در فایل csproj شما موجود باشد، در غیر این صورت ممکن است با خطا مواجه شوید:
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>

چند وقتی می‌شود که گیت‌هاب اکشن‌ها را معرفی کرده که با استفاده از این اکشن‌ها میتوان برخی فعالیت‌های تکراری را، خودکار سازی کرد و در وقت و انرژی صرفه جویی کرد. ما چه کارهایی را میتوانیم با کمک اکشن‌ها انجام بدهیم؟ تقریبا میشود گفت هرکاری را میتوان با اکشن‌ها انجام داد. کامپایل کردن پروژه، تست کردن، پابلیش کردن و...
من معمولا فایل‌های خروجی که برای پروژه‌هایم میگیرم، بدلیل استفاده از ویژگی SelfContained و ایمیج‌های ReadyToRun برای اجرای سریعتر، معمولا حجمی حدود 140 مگ دارند. حالا وقتی آنها را فشرده میکنم، به حدود 50 مگ کاهش پیدا میکنند که اگر من بخواهم هر دفعه که از برنامه خروجی میگیرم، فایل خروجی را فشرده کنم و آن را در گیت‌هاب آپلود کنم، هم فرآیندی زمانبر هست و هم اینکه تکراری و خسته کننده؛ در نتیجه تصمیم گرفتم که از اکشن گیت‌هاب برای خودکارسازی این فرآیند استفاده کنم. 
در این نوشته میخواهیم یک اکشن بنویسیم که بر اساس سورس کد موجود بر روی گیت‌هاب، برنامه را کامپایل کند، فایل اجرایی را بصورت فایل فشرده Zip ایجاد کرده و در نهایت این فایل فشرده را در قسمت Release گیت‌هاب منتشر کند.
برای شروع کار اول باید در مخزن پروژه، در سایت گیت‌هاب، به قسمت Action برویم:

حالا روی قسمت New workflow کلیک میکنیم
 
شما میتونید از قالب‌های پیش‌فرض موجود، هر کدام را که خواستید انتخاب کنید. من ترجیح میدهم با یک قالب خالی شروع کنم. پس بر روی set up a workflow yourself کلیک میکنیم:
 
کدهای پیش‌فرضی که وجود دارند را پاک کنید، تا مثل تصویر زیر، یک فایل کاملا تمیز و خالی را داشته باشیم. نکته‌ای که باید دقت کنید، اسم و مسیر فایل می‌باشد. مسیر فایل را اصلا نباید تغییر داد، ولی اسم فایل را میتوانید اصلاح کنید؛ ولی توجه کنید که پسوند فایل باید yml باشد.
حالا نوبت نوشتن کدهای اکشن رسیده:
اول از همه کد زیر را مینویسیم:
name: "Publish"

این خط، اسم اکشن مارا مشخص میکند که قرار است در لیست workflow‌ها نمایش داده شود:
در کد بعدی که باید بنویسیم (در خط بعدی) باید مشخص بکنیم که این اکشن چه زمانی اجرا بشود. گزینه‌های زیر استفاده بیشتری دارند:
  • push = هر زمان که کامیتی روی گیتهاب پوش شود، اکشن اجرا میشود.
  • pull_request = هر زمانی که یک پول ریکوئست مرج شود، اکشن اجرا میشود.
  • workflow_dispatch = برنامه نویس خودش میتواند با کلیک بر روی دکمه‌ی مشخصی در قسمت اکشن‌ها، اکشن موردنظر را اجرا کند.
لیست کامل تریگر‌ها را میتوانید اینجا مطالعه کنید.
ما از push استفاده میکنیم؛ البته مقداری آن را تغییر میدهیم تا زمانیکه شامل تگ بود، اکشن اجرا شود.
on:
  push:
    tags:
      - "v*"
نکته‌ای که وجود دارد، ما در آخر این دستور، از *v استفاده کردیم که اشاره میکند اگر تگی بصورت v1.0.0 بود، اجرا بشود. * میتواند هر عددی باشد.
3 متغیر ایجاد میکنیم تا محل فایل پروژه، اجرایی و فشرده را نگه دارد، تا فایل اکشن زیاد شلوغ نباشد. 
env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
حالا باید دستورات خودکار سازی را بنویسیم. همه دستورات باید در قسمت jobs نوشته شوند:
 jobs:
  deploy:
    runs-on: windows-latest
به قسمت runs-on توجه کنید. این گزینه مشخص میکند که اکشن ما بر روی سرور ویندوزی و آخرین نسخه‌ی از آن اجرا بشود؛ در صورت نیاز میتوانید از linux نیز استفاده کنید.
در خط بعدی باید قدم به قدم دستورات را بنویسیم. ما برای هر قدم، از name استفاده میکنیم که هنگام اجرای اکشن، بصورت مرتب و خوانا بتوانیم بفهمیم که در چه مرحله‌ای از اجرا هستیم.
قدم اول باید اکشن را آماده کنیم. اکثر دستورات مهم در این اکشن موجود است:
 steps:
      - name: Initialize Actions
        uses: actions/checkout@v2
قدم بعدی باید sdk دات نت را بر روی سرور، دانلود و نصب کنیم:
     - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
قبل از بیلد پروژه، باید کتابخانه‌ها و بسته‌های نیوگت را restore کنیم، تا بیلد، خطا نداشته باشد:
  - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}
حالا میتوانیم دستور خروجی گرفتن را بنویسیم (حتما باید در فایل csproj پروژه خود، runtimeidentifier  پروژه مشخص باشد که اینجا ما از win-x86 استفاده کردیم؛ در غیر اینصورت خطا میگیرید)  چون در مرحله قبل پروژه را restore کردیم، هنگام خروجی گرفتن، دستور no-restore را مینویسیم تا دوباره بسته‌های نیوگت ری‌استور نشود.
 - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore
حالا که فایل اجرایی را ایجاد کردیم، باید آن را بصورت فشرده و zip در بیاوریم. برای اینکار از یک اکشن دیگر کمک میگیریم. اول آن را به اصطلاح using میکنیم؛ سپس از آن استفاده میکنیم. این اکشن 2 ورودی دارد: files و dest که به ترتیب باید آدرس فایل‌ها و محل ذخیره زیپ را به آن بدهیم که ما از متغیرهایی که قبلا ایجاد کرده‌ایم، استفاده میکنیم. 
 - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
در مرحله بعدی باید از یک اکشن دیگر برای ساخت Release در قسمت گیت‌هاب کمک بگیریم. دقت کنید که برای آپلود کردن فایل زیپ داخل این Release، ما باید توکن و id این ریلیز را ذخیره کنیم که در اینجا در متغیر GITHUB_TOKEN و id ذخیره میکنیم. توکن را میتوانیم از قسمت secrets خود گیت‌هاب دریافت کنیم. همچنین ما اسم تگ را از طریق github.ref دریافت میکنیم (که مقدار v1.0.0 را به عنوان مثال برای ما برگشت خواهد داد (شماره نسخه همان تگی است که پوش کرده‌ایم) 
 - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
حالا نوبت این است که فایل زیپ را آپلود کنیم. دوباره باید از اکشن دیگری برای این امر کمک بگیریم. توکنی را که قبلا ذخیره کردیم، همراه با فایل زیپ، به این اکشن میدهیم و در پایان به کمک id که قبلا ذخیره کردیم، لینک فایل آپلود شده را از آن دریافت میکنیم.  
 - name: Create Release 
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}
کد کامل را اینجا ببینید: 
name: "Publish"

on:
  push:
    tags:
      - "v*"

env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
  

jobs:
  deploy:
    runs-on: windows-latest
    steps:
      - name: Initialize Actions
        uses: actions/checkout@v2

      - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
      
      - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}

      - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore

      - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
          
      - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
      
      - name: Create Release    
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}

در آخر بر روی دکمه سبز رنگ بالا سمت راست start commit کلیک کنید تا تغییرات ثبت شوند.
به پروژه خود برگردید و ترمینال را باز کنید و یک تگ جدید را ایجاد کنید. 
git tag v1.0.0
سپس تگ ایجاد شده را به مخزن گیت‌هاب پوش کنید:
git push origin tag v1.0.0

 به مخزن گیت‌هاب مراجعه کنید تا ببینید که اکشن شما بصورت خودکار اجرا شده و در پایان، یک ریلیز برای شما ایجاد میکند.
 در قسمت ریلیز میتوانید ببینید که ریلیز توسط ربات گیت‌هاب ایجاد شده‌است:
نظرات مطالب
PersianDatePicker یک DatePicker شمسی به زبان JavaScript که از تاریخ سرور استفاده می‌کند

این پروژه یک فایل اسکریپت بیشتر نیست. بنابراین برای کار کردن نیاز به الحاق آن به صفحه هست (مثل تمام پروژه‌های جاوا اسکریپتی). ضمنا این مطلب رو برای سؤال پرسیدن باید رعایت کنی: آناتومی یک گزارش خطای خوب . کسی نمی‌دونه این ارور می‌ده یعنی چی؟ چه خطایی می‌ده؟ کسی مونیتورت رو نمی‌تونه از راه دور ببینه. باید توضیح بدی. تشریحش کنی با کمک این ابزار: نحوه استفاده از افزونه Firebug برای دیباگ برنامه‌های ASP.NET مبتنی بر jQuery        

نظرات مطالب
افزودن و اعتبارسنجی خودکار Anti-Forgery Tokens در برنامه‌های Angular مبتنی بر ASP.NET Core
سلام
من از ASP. Net Web API 2  برای سرویس هام استفاده می‌کنم، برای سمت Front از Angular 6
چطور میتونم Anti-Forgery Token رو توش پیاده سازی کنم، متاسفانه مطلب مفیدی پیدا نکردم که کمک کنه. (نمونه همین مورد رو با AngularJS پیاده کردم، ولی ظاهرا اینجا یه کم متفاوت هست)
ممنون میشم راهنمایی کنید
نظرات مطالب
مدیریت Instance در WCF
سلام
یه سوالی برام پیش اومده ممنون میشم راهنمایی فرمایید:
من یک سرویس WCF  ایجاد کردم  و اونو به شکل زیر تنظیم کردم :
 [ServiceContract(SessionMode=SessionMode.Reqquired)]
 و همچنین برای کلاس پیاده سازی کننده اینترفیس :
 [ServiceBehavior( InstanceContextMode = InstanceContextMode.PerSession)]
من داخل این کلاس یه متغیر از یک کلاس به صورت سراسری تعریف کردم که میخوام ازش توی متدهای متفاوت استفاده کنم اما ظاهرا با هر بار فراخوانی باز هم این متغیر داده‌های خودشو ازدست میده البته static نیست و به دلیل ساختار اون نمیتونم استاتیکش کنم
ممنون میشم راهنمایی نمایید
مطالب
MongoDb در سی شارپ (بخش چهارم)
در این بخش قصد داریم در مورد Chunk شدن فایل‌ها بدانیم. ولی قبل از هر چیز، نیاز است که ابتدا با اصول اولیه مونگو و حتی بانک‌های nosql آشنا شویم.

رپلیکیشن: اگر در زمینه بانک‌های اطلاعاتی، چه رابطه‌ای و چه nosql فعالیت کرده باشید، میدانید که رپلیکیشن به معنی انتقال و جابجایی داده‌ها، بین سرورهای مختلف در مکانهای مختلف میباشد و این عمل باید ضمانت یکپارپگی و یکسان سازی دیتا را در همه سرورها تضمین کند. اینگونه، بار بین سرورها کاهش پیدا کرده و کاربران راه دور نیازی نیست فاصله زیادی با سرور داشته باشند و میشود از نزدیک‌ترین سرور، داده‌ها را درخواست کنند و از آنجا که بانک‌های nosql در مبحث توزیع پذیری همانند یک قهرمان رفتار می‌کنند، پس اولین اصطلاحی که باید با آن آشنایی داشته باشید، همین عملیات رپلیکیشن می‌باشد.

Sharding : یک خوشه شاردینگ(Sharded Cluster) در واقع مجموعه‌ای از همین سرورهای ریپلیکیشن میباشد که ماموریتشان توزیع یکسان بار، بر روی سرورهاست که به ما امکان مدیریت داده‌های حجیم و توسعه و به روزرسانی افقی سرورها (Horizontally Scale) را میدهد.
از این پس میدانیم که ریپلیکیشن‌ها شامل داده‌های یکسانی بوده و شاردینگ‌ها، تقسیم بندی دیتا را صورت میدهند و هر شارد میتواند شامل رپلیکشن‌های متفاوتی باشد.

اصلی‌ترین هدف این خوشه شاردینگ‌ها عبارتند از:
1-  مقیاس پذیری: توزیع بار پردازشی بر روی سرور‌های مختلف.
2- موازنه سازی لود دیتا: دیتا به طور خودکار در بین شاردهای مختلف توزیع می‌شود. موازنه‌گر تصمیم میگیرد که چگونه دیتا انتقال داده شده و به چه سروری منتقل شود و از طریق یک کلید به نام Partition Key رنج بندی دیتا را انجام میدهد تا بداند هر شاردی، چه رنج دیتایی را شامل میشود.

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


عملیات Chunk یا قطعه سازی فایل‌ها، بر اساس همین تعداد شاردینگ‌های مختلف می‌باشد که به صورت انتزاعی یا مفهومی ایجاد شده‌است و شامل دیتای اصلی نمیشود؛ بلکه شامل اطلاعاتی برای هر قطعه از دیتاها میشود که شامل یک کلید به نام SharedKey میباشد و دو مقدار Min و Max را برای هر رنج دیتا شامل میشود.

بعد از اینکه Chunk‌های یک فایل مشخص شد، مونگو برای حفظ موازنه و بالانس شاردینگ‌ها، شروع به تقسیم این چانک‌ها میکند. به عنوان مثال تعدادی چانک، بین این شاردینگ و تعدادی دیگر برای شاردینگ‌های دیگر. جدول زیر نحوه توزیع 4 چانک را نشان میدهد:


 شارد نهایت مقدار  Max
حداقل مقدار Min
 شناسه یا Id چانک
 “shard” : “shard0001”   “max” : { “x” : 8000 }   “min” : { “x” : 7000 }   “_id” : “testdb.presplit-x_7000.0” 
 “shard” : “shard0001”   “max” : { “x” : 9000 }   “min” : { “x” : 8000 }   “_id” : “testdb.presplit-x_8000.0” 
  “shard” : “shard0002” 
 “max” : { “x” : 10000 }   “min” : { “x” : 9000 }   “_id” : “testdb.presplit-x_9000.0” 
 “shard” : “shard0002”   “max” : { “x” : 11000 }   “min” : { “x” : 10000 }   “_id” : “testdb.presplit-x_10000.0” 

  این تقسیم چانک‌ها باید طوری باشد که سرور‌ها همیشه در حالت موازنه باشند و بالانس خود را حفظ کنند. جدول زیر به شما کمک میکند که بدانید سرور بالانس است یا خیر.
 تعداد چانک ها
 میزان تفاوت
 کمتر از 20 عدد
 2
 20 تا 79
 4
 از 79 عدد بیشتر
 8

برای درک این مسئله، فرض کنید ما 2 عدد شارد داریم و 31 عدد چانک. اگر 17 عدد از چانک‌ها به شارد 1 برسد و 14 تای باقی مانده به شارد شماره 2 برسد، اختلاف این تعداد شاردها سه میباشد که طبق جدول تا 4 عدد جا دارد. پس بالانسی بین شاردها بر قرار است. موقعی که فایلی به مقدار مشخص شده‌ی برای چانک برسد که به طور پیش فرض 64 مگابایت می‌شود، شروع به چانک گذاری کرده و برای حفظ بالانس و موازنه سازی، این چانک‌ها را بین شاردهای مختلف توزیع میکند و چانک را از سروری که شامل چانک‌های زیاد است، به سروری که شامل چانک‌های کمتر است منتقل میکند.

مطالب
استفاده از Lambda Expression در پروژه های مبتنی بر WCF
نکته : آشنایی با مفاهیم پایه WCF برای فهم بهتر مفاهیم توصیه می‌شود.

امروزه استفاده از WCF در پروژه‌های SOA بسیار فراگیر شده است. کمتر کسی است که در مورد قدرت تکنولوژی WCF نشنیده باشد یا از این تکنولوژی در پروژه‌های خود استفاده نکرده باشد. WCF مدل برنامه نویسی یکپارچه مایکروسافت برای ساخت نرم‌افزارهای سرویس گرا است و برای توسعه دهندگان امکانی را فراهم می‌کند که راهکارهایی امن، و مبتنی بر تراکنش را تولید نمایند که قابلیت استفاده در بین پلتفرم‌های مختلف را دارند. قبل از WCF توسعه دهندگان پروژه‌های نرم افزاری برای تولید پروژه‌های توزیع شده باید شرایط موجود برای تولید و توسعه را در نظر می‌گرفتند. برای مثال اگر استفاده کننده از سرویس در داخل سازمان و بر پایه دات نت تهیه شده بود از .net remoting استفاده می‌کردند و اگر استفاده کننده سرویس از خارج سازمان یا مثلا بر پایه تکنولوژی J2EE بود از Web Service‌ها استفاده می‌شد. با ظهور WCF این تکنولوژی با هم تجمیع شدند(بهتر بگم تبدیل به یک تکنولوژی واحد شدند) و دیگر خبری از net remoting یا web service‌ها نیست.
  WCF با تمام قدرت و امکاناتی که داراست دارای نقاط ضعفی هم می‌باشد که البته این معایب (یا محدودیت) بیشتر جهت سازگار سازی سرویس‌های نوشته شده با سیستم‌ها و پروتکل‌های مختلف است.
برای انتقال داده‌ها از طریق WCF بین سیستم‌های مختلف باید داده‌های مورد نظر حتما سریالایز شوند که مثال هایی از این دست رو در همین سایت می‌تونید مطالعه کنید:
(^ )  و (^ ) و (^ )

با توجه به این که داده‌ها سریالایز می‌شوند، در نتیجه امکان انقال داده هایی که از نوع object  هستند در WCF وجود ندارد. بلکه نوع داده باید صراحتا ذکر شود و این نوع باید قابیلت سریالایز شدن را دارا باشد.برای مثال شما نمی‌تونید متدی داشته باشید که پارامتر ورودی آن از نوع delegate باشد یا کلاسی باشد که صفت [Serializable] در بالای اون قرار نداشته باشد یا کلاسی باشد که صفت DataContract برای خود کلاس و صفت DataMember برای خاصیت‌های اون تعریف نشده باشد. حالا سوال مهم این است اگر متدی داشته باشیم که پارامتر ورودی آن حتما باید از نوع delegate باشد چه باید کرد؟

برای تشریح بهتر مسئله یک مثال می‌زنم؟

سرویسی داریم برای اطلاعات کتاب ها. قصد داریم متدی بنوسیم که پارامتر ورودی آن از نوع Lambda Expression است تا Query مورد نظر کاربر از سمت کلاینت به سمت سرور دریافت کند و خروجی مورد نظر را با توجه به Query ورودی به کلاینت برگشت دهد.( متدی متداول در اکثر پروژه ها). به صورت زیر عمل می‌کنیم.

*ابتدا یک Blank Solution ایجاد کنید.

*یک ClassLibrary به نام Model ایجاد کنید و کلاسی به نام Book در آن بسازید .(همانطور که میبینید کلاس مورد نظر سریالایز شده است):

   [DataContract]
    public class Book
    {
        [DataMember]
        public int Code { get; set; }

        [DataMember]
        public string Title { get; set; }
    }
* یک WCF Service Application ایجاد کنید
یک Contract برای ارتباط بین سرور و کلاینت می‌سازیم:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.ServiceModel;

namespace WcfLambdaExpression
{
    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression );
    }
}
متد GetByExpression دارای پارامتر ورودی expression است که نوع آن نیز Lambda Expression  می‌باشد. حال یک سرویس ایجاد می‌کنیم:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace WcfLambdaExpression
{    
    public class BookService : IBookService
    {        
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

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

        public IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression )
        {
            ListOfBook.AddRange( new Book[] 
            {
                new Book(){Code = 1 , Title = "Book1"},
                new Book(){Code = 2 , Title = "Book2"},
                new Book(){Code = 3 , Title = "Book3"},
                new Book(){Code = 4 , Title = "Book4"},
                new Book(){Code = 5 , Title = "Book5"},
            } );

            return ListOfBook.AsQueryable().Where( expression );
        }       
    }
}
بعد از Build پروژه همه چیز سمت سرور آماده است. یک پروژه دیگر از نوع Console ایجاد کنید و از روش AddServiceReference سعی کنید که سرویس مورد نظر را به پروژه اضافه کنید. در هنگام Add Service Reference برای اینکه سرویس سمت سرور و کلاینت هر دو با یک مدل کار کنند باید از یک Reference assembly استفاده کنند و کافی است از قسمت Advanced گزینه Reuse types in referenced assemblies را تیک بزنید و assembly‌های مورد نظر را انتخاب کنید.( در این پروژه باید Model و System.Xml.Linq را انتخاب کنید)


به طور حتم با خطا روبرو خواهید شد. دلیل آن هم این است که امکان سریالایز کردن برای پارامتر ورودی expression میسر نیست.
خطای مربوطه به شکل زیر خواهد بود:
Type 'System.Linq.Expressions.Expression`1[System.Func`2[WcfLambdaExpression.Book,System.Boolean]]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  
If the type is a collection, consider marking it with the CollectionDataContractAttribute.  
See the Microsoft .NET Framework documentation for other supported types
حال چه باید کرد؟
روش‌های زیادی برای بر طرف کردن این محدودیت وجود دارد. اما در این پست روشی رو که خودم از اون استفاده می‌کنم رو براتون شرح می‌دهم.
در این روش باید از XElement استفاده شود که در فضای نام System.Linq.Xml قرار دارد. یعنی آرگومان ورودی سمت کلاینت باید به فرمت Xml سریالایز شود و سمت سرور دوباره دی سریالایز شده و تبدیل به یک Lambda Expression شود. اما سریالایز کردن Lambda Expression واقعا کاری سخت و طاقت فرساست . با توجه به این که در اکثر پروژه‌ها این متد‌ها به صورت Generic نوشته می‌شوند. برای حل این مسئله بعد از مدتی جستجو، کلاسی رو پیدا کردم که این کار رو برام انجام می‌داد. بعد از مطالعه دقیق و مشاهده روش کار کلاس، تغییرات مورد نظرم رو اعمال کردم و الان در اکثر پروژه هام دارم از این کلاس استفاده می‌کنم.
یک مثال از روش استفاده :
برای اینکه از این کلاس در هر دو پروژه (سرور و کلاینت) استفاده می‌کنیم باید یک Class Library جدید به نام Common بسازید و یک ارجاع از اون رو به هر دو پروژه سمت سرور و کلاینت بدید.
سرویس و Contract بالا رو به صورت زیر باز نویسی کنید.
[ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        IEnumerable<Book> GetByExpression( XElement expression );
    }
و سرویس :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Xml.Linq;

namespace WcfLambdaExpression
{
    public class BookService : IBookService
    {
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

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

        public IEnumerable<Book> GetByExpression( XElement expression )
        {
            ListOfBook.AddRange( new Book[] 
            {
                new Book(){Code = 1 , Title = "Book1"},
                new Book(){Code = 2 , Title = "Book2"},
                new Book(){Code = 3 , Title = "Book3"},
                new Book(){Code = 4 , Title = "Book4"},
                new Book(){Code = 5 , Title = "Book5"},
            } );

             Common.ExpressionSerializer serializer = new Common.ExpressionSerializer();

            return ListOfBook.AsQueryable().Where( serializer.Deserialize( expression ) as Expression<Func<Book, bool>> );
        }
    }
بعد از Build پروژه از روش Add Service Reference استفاده کنید و می‌بینید که بدون هیچ گونه مشکلی سرویس مورد نظر به پروژه Console اضافه شد. برای استفاده سمت کلاینت به صورت زیر عمل کنید.

using System;
using System.Linq.Expressions;
using TestExpression.MyBookService;

namespace TestExpression
{
    class Program
    {
        static void Main( string[] args )
        {
            BookServiceClient bookService = new BookServiceClient();

            Expression<Func<Book, bool>> expression = x => x.Code > 2 && x.Code < 5;

            Common.ExpressionSerializer serializer = new Common.ExpressionSerializer();

            bookService.GetByExpression( serializer.Serialize( expression ) );
        }
    }
}
بعد از اجرای پروژه، در سمت سرور خروجی‌های زیر رو مشاهده می‌کنیم.

خروجی هم به صورت زیر خواهد بود:

دریافت سورس کامل Expression-Serialization
نظرات مطالب
ASP.NET MVC #3
کلاس ProductController در پوشه Controllers اضافه می‌شود. این کلاس هم یک کلاس ساده دات نتی است با این تفاوت که با ارث بری از کلاس استاندارد Controller، مفهوم یک کنترلر را پیدا می‌کند.
مرحله بعد ایجاد View است برای متدهای این کنترلر. در این مورد در قسمت بعد با تصویر توضیح خواهم داد. البته نتیجه آن هم این خواهد بود که فایل‌های View آن در پوشه پیش فرض Views/Product قرار می‌گیرند.
بنابراین نام کنترلر Product است.
نام پوشه Viewهای پیش فرض آن مطابق قرارداد، Views/Product است.
اما این کنترلر باید تحت عنوان کلاسی به نام ProductController به پوشه Controllers اضافه شود.
نظرات مطالب
معرفی DNTProfiler
- لطفا برای طرح سؤالات و ارائه‌ی پیشنهادات خود در زمینه‌ی این پروژه، به قسمت اختصاصی آن در سایت مراجعه نمائید: https://www.dntips.ir/projects/details/21
- استثناءها را با تصویر ارائه ندهید. اصل متنی استثناء، بهتر قابلیت پیگیری دارد.
خطاهای برنامه در فایل متنی به نام ErrorsLog.Log در کنار فایل اجرایی برنامه ثبت می‌شوند.  
- سورس را اجرا کردید یا اصل برنامه‌ی توزیع شده را؟ به نظر سورس را اجرا کرده‌اید. آیا بسته‌های نیوگت آن‌را به درستی بازیابی کرده‌اید؟ آیا از فایل Microsoft.SqlServer.TransactSql.ScriptDom با شماره نگارش صحیحی استفاده می‌کنید که پیام داده‌است متدهای آن یافت نشدند؟
<package id="Microsoft.SqlServer.TransactSql.ScriptDom" version="12.0.1" targetFramework="net40" />
این فایل‌ها به همراه بسته‌ی توزیع شده وجود دارند.
نظرات مطالب
واکشی اطلاعات سرویس Web Api با استفاده از TypeScript و AngularJs
angularJs کتابخانه ای برای mock آبجکت‌ها خود تهیه کرده است.(angular-mock) . از آن جا که در angular مبحث تزریق وابستگی بسیار زیبا پیاده سازی شده است با استفاده از این کتابخانه می‌توانید آبجکت‌های متناظر را mock کنید. برای مثال:
describe('myApp', function() {
var scope;

 beforeEach(angular.mock.module('myApp'));
 beforeEach(angular.mock.inject(function($rootScope) {
    scope = $rootScope.$new();
});
it('...')
});
هم چنین برای تست سرویس http$  و شبیه سازی عملیات request و response در انگولار سرویس httpBackend$ تعبیه شده است که یک پیاده سازی Fake از http$ است که در تست‌ها می‌توان از آن استفاده کرد. برای مثال:
describe('Remote tests', function() {
    var $httpBackend, $rootScope, myService;
       beforeEach(inject(
function(_$httpBackend_, _$rootScope_, _myService_) {
      $httpBackend = _$httpBackend_;
      $rootScope = _$rootScope_;
      myService = _myService_;
}));
it('should make a request to the backend', function() {
   $httpBackend.expect('GET', '/v1/api/current_user')
     .respond(200, {userId: 123}); 
     myService.getCurrentUser();

     $httpBackend.flush();
});
});
دستور httpBackend$.expect برای ایجاد درخواست مورد نظر استفاده می‌شود که نوع verb را به عنوان آرگومان اول دریافت می‌کند. respond نیز مقدار بازگشتی مورد انتظار از سرویس مورد نظر را بر میگرداند. می‌توانید از دستورات زیر برای سایر حالات استفاده کنید:

»httpBackend$.expectGet
»httpBackend$.expectPut
»httpBackend$.expectPost
»httpBackend$.expectDelete
»httpBackend$.expectJson
»httpBackend$.expectHead
»httpBackend$.expectPatch 

Flush کردن سرویس httpBackend$ در پایان تست نیز برای همین مبحث async اجرا شدن سرویس‌های http$backend است.
نظرات مطالب
شروع کار با ASP.NET Web API 2
بله. به طور کلی، هر پلتفرمی که دارای کتابخانه ای جهت کار با سرویس‌های Http است می‌تواند از سرویس‌های Asp.Net WebApi استفاده نماید.
 اما در هنگام پیاده سازی پروژه‌های مقیاس بزرگ حتما به طراحی زیر ساخت توجه ویژه ای داشته باشید. اگر کتاب‌های
 Designing Evolvable Web Api With Asp.Net یا
Pro Asp.Net Web Api : Http Web Service In Asp.Net   را مطالعه نکردید بهتون پیشنهاد می‌کنم قبل از شروع به کار حتما نگاهی به آن‌ها بیندازید.

در همین رابطه:
»مقایسه بین امکانات Web Api و WCF