مطالب
Navigation در AJAX - لینک دائمی برای محتوای AJAX
استفاده از AJAX به ما امکان می‌دهد قسمتی از صفحه را بدون رفتن به صفحه‌ی جدید بروز کنیم. 
فرض کنید لیستی از اسامی و قیمت کالاها را در اختیار داریم ، کاربر روی دکمه‌ی جزییات کالا کلیک می‌کند ، جزییات کالا را با یک درخواست AJAX بارگزاری می‌کنیم و در یک Dialog به کاربر نمایش می‌دهیم .
آیا لینک دائمی برای این محتوای لود شده وجود دارد ؟ منظور این است آیا کاربر می‌تواند بدون تکرار مراحل قبلی و با استفاده از یک لینک جزییات آن کالا را مشاهده کند ؟ 
برای فراهم ساختن یک لینک دائمی برای محتوای AJAX راه حل استفاده از windows.location.hash  هست.
در این http://example.com/blah#456 مقدار HashTag ما برابر با 456 می‌باشد. 
مقدار HashTag به سرور ارسال نمی‌شود و فقط سمت کلاینت قابل استفاده هستند.
<span class='button goodDetail' id='123' >جزییات کالا</span>
به Span بالا یک Attribute سفارشی افزوده شده که حاوی کلید اصلی کالا می‌باشد. هنگامی که روی این دکمه کلیک می‌شود با یک درخواست AJAX اطلاعات جزییات این کالا واکشی می‌شود و قسمتی از صفحه بروزسانی می‌شود : 
$('.goodDetail').click(function(){
//add to hash data that you need to make the AJAX request later
$(window).location.hash = $(this).attr('id');
$.ajax({
 type: "POST",
 url: 'some url',
 dataType: "html",
 data:'GoodId='+$(this).attr('id'),
 success: function(html) {
                 //do something
 } })  })
در خط سوم کد بالا Location hash را به کلید اصلی کالایی که روی آن کلیک شده است مقدار داده ایم. بعد از کلیک روی آن دکمه URL ما اینگونه خواهد بود : www.mysite.com/goods.aspx#123
123 همان کلید اصلی کالا است که در Attribute سفارشی در دکمه‌ی جزییات کالا نگهداری می‌شده ، پس انتظار می‌رود اگر کاربر www.mysite.com/goods.aspx#123 را وارد کرد همان درخواست AJAX اجرا شود و جزییات کالای 123 به کاربر نشان داده شود. 
در Document Ready صفحه‌ی جزییات کالا چک می‌کنیم آیا Hash tag وجود دارد یا خیر ، اگر وجود داشت مقدار آن را به دست می‌آوریم ، درخواست AJAX را صادر می‌کنیم و اطلاعات کالای 123 را به کاربر نشان می‌دهیم : 
$(document).ready(function(){
if ($(window).location.hash.length))
{
//we will use $(window).location.hash.replace('#','') in the "data" section of the AJAX request
$.ajax({
 type: "POST",
 url: current_url,
 dataType: "html",
 data:'GoodId='+$(window).location.hash.replace('#',''),
 success: function(html) {
                 //do something
 }  })  
}
});
همانطور که مشاهده می‌کنید برای به دست آوردن مقدار Hashtag از کد پراپرتی hash شیء location استفاده شده ، این پراپرتی علامت # را هم بر می‌گرداند ، پس قبل یا بعد از ارسال مقدار این پراپرتی به سرور باید این علامت را حذف کرد.
این مثال Online را مشاهده کنید. 
نظرات مطالب
فعال سازی و پردازش صفحات پویای افزودن، ویرایش و حذف رکوردهای jqGrid در ASP.NET MVC
ممنون. ولی تو تعریف کدهای شما، ردیف رو به عنوان ایدی به تابع حذف می‌فرسته و با این تابع میشه نوع داده ارسالی رو مشخص کرد
   onClickButton: function (e) {
            var id = $('#grid').jqGrid('getGridParam', 'selrow');
           
            if (id != null) {
                var idHtml = $('#grid').jqGrid('getCell', id, 'ID_Baker');
                //var idHtml = id.ID_Baker;
                //var idHtml = $('#' + id).children().first().html();
                $.ajax({
                    url: '@(Url.Action("DeleteProfile"))' + '?Id=' + idHtml + '&RowId=' + id,
                    success: function (data) {
                        if (data.Success) {

                            $('#grid').jqGrid('delRowData', data.RowId);
                        }
                    }
                });
            }
            else {
            }
        },
نظرات مطالب
بررسی روش آپلود فایل‌ها از طریق یک برنامه‌ی Angular به یک برنامه‌ی ASP.NET Core
یک نکته‌ی تکمیلی: به روز رسانی مثال مطلب جاری جهت گزارش درصد پیشرفت آپلود فایل‌ها توسط HTTP Client جدید Angular

در اینجا می‌خواهیم بدون استفاده از هیچگونه کامپوننت ثالثی، صرفا بر اساس قابلیت‌های جدید ماژول HttpClient ارائه شده‌ی در Angular 4.3، درصد پیشرفت آپلود را نیز نمایش دهیم. تغییرات مورد نیاز برای این منظور به شرح زیر هستند:

1) تغییر سرویس برنامه جهت استفاده از HTTP Client و گزارش درصد پیشرفت

  postTicket(ticket: Ticket, filesList: FileList): Observable<HttpEvent<any>> {

    //… the same as before

    const headers = new HttpHeaders().set("Accept", "application/json");
    return this.http
      .post(`${this.baseUrl}/SaveTicket`, formData, {
        headers: headers,
        reportProgress: true,
        observe: "events"
      })
      .map(response => response || {})
      .catch((error: HttpErrorResponse) => {
        console.error("observable error: ", error);
        return Observable.throw(error.statusText);
      });
  }
در اینجا متد postTicket، به این صورت تغییر کرده‌است:
الف) خروجی متد آن یک Observable از نوع HttpEvent تعیین شده‌است. به این ترتیب مشترکین به آن قادر خواهند شد به رخ‌دادهای HTTP Client گوش فرا دهند:
 postTicket(ticket: Ticket, filesList: FileList): Observable<HttpEvent<any>> {

ب) به قسمت options متد post، گزینه‌ها‌ی "observe: "events و reportProgress: true اضافه شده‌اند:
{
  headers: headers,
  reportProgress: true,
  observe: "events"
}
به این ترتیب، رخ‌دادها به همراه گزارش درصد پیشرفت آپلود و دانلود، به مشترکین این متد ارسال خواهند شد.

2) تغییر متد submitForm کامپوننت جهت گزارش و اعمال تغییرات به قالب برنامه

  queueProgress: number;
  isUploading: boolean;
  uploadTimeRemaining: number;
  uploadTimeElapsed: number;
  uploadSpeed: number;

  submitForm(form: NgForm) {
    const fileInput: HTMLInputElement = this.screenshotInput.nativeElement;
    this.queueProgress = 0;
    this.isUploading = true;
    let startTime = Date.now();

    this.uploadService.postTicket(this.model, fileInput.files).subscribe(
      (event: HttpEvent<any>) => {
        switch (event.type) {
          case HttpEventType.Sent:
            startTime = Date.now();
            console.log("Request sent!");
            break;
          case HttpEventType.DownloadProgress:
          case HttpEventType.UploadProgress:
            if (event.total) {
              this.queueProgress = Math.round(event.loaded / event.total * 100);

              const timeElapsed = Date.now() - startTime;
              const uploadSpeed = event.loaded / (timeElapsed / 1000);
              this.uploadTimeRemaining = Math.ceil(
                (event.total - event.loaded) / uploadSpeed
              );
              this.uploadTimeElapsed = Math.ceil(timeElapsed / 1000);
              this.uploadSpeed = uploadSpeed / 1024 / 1024;
            }
            break;
          case HttpEventType.Response:
            this.queueProgress = 100;
            this.isUploading = false;
            console.log("Done! ResponseBody:", event.body);
            break;
        }
      },
      (error: HttpErrorResponse) => {
        this.isUploading = false;
        console.log(error);
      }
    );
  }
پس از اینکه خروجی متد سرویس ارسال فایل‌ها را از نوع <<Observable<HttpEvent<any تعیین کردیم، اکنون پس از subscribe به آن، اینبار event: HttpEvent را بجای data متداول دریافت می‌کنیم. سپس بر اساس event.type می‌توان در مورد رخ‌داد گزارش داده شده، تصمیم‌گیری کرد:
- HttpEventType.Sent شروع عملیات است. برای مثال از آن می‌توان جهت تعیین زمان شروع به آپلود استفاده کرد. سپس این زمان را با زمان جاری، در رخ‌داد آپلود به سرور مقایسه و گزارش سرعت آپلود، زمان‌های صرف شده و باقیمانده را محاسبه کرد.
- HttpEventType.DownloadProgress و HttpEventType.UploadProgress گزارش درصد آپلود را مشخص می‌کنند. در اینجا event.total حجم کلی است و event.loaded حجم ارسالی کلی به سمت سرور می‌باشد. به همین جهت از این اطلاعات می‌توان برای نمایش درصد کل آپلود استفاده کرد.
- HttpEventType.Response در پایان عملیات رخ‌خواهد داد. در اینجا event.body همان بدنه‌ی response دریافتی از سمت سرور است.

3) تغییر رابط کاربری برنامه (قالب کامپوننت) جهت گزارش درصد پیشرفت کلی آپلود
    <div *ngIf="queueProgress > 0">
      <table class="table">
        <thead>
          <tr>
            <th width="15%">Event</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><strong>Elapsed time</strong></td>
            <td nowrap>{{uploadTimeElapsed | number:'.1'}} second(s)</td>
          </tr>
          <tr>
            <td><strong>Remaining time</strong></td>
            <td nowrap>{{uploadTimeRemaining | number:'.1'}} second(s)</td>
          </tr>
          <tr>
            <td><strong>Upload speed</strong></td>
            <td nowrap>{{uploadSpeed | number:'.3'}} MB/s</td>
          </tr>
          <tr>
            <td><strong>Queue progress</strong></td>
            <td>
              <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar"
                aria-valuemin="0" aria-valuemax="100" [attr.aria-valuenow]="queueProgress"
                [ngStyle]="{ 'width': queueProgress + '%' }">
                {{queueProgress}}%
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>

    <button class="btn btn-primary" [disabled]="form.invalid || isUploading" type="submit">Submit</button>
در اینجا کار نمایش زمان صرف شده، زمان باقیمانده، سرعت آپلود و همچنین درصد میزان پیشرفت آپلود انجام شده‌اند. درصد محاسبه شده به ngStyle متصل شده‌است تا سبب حرکت progressbar بوت استرپ شود.
همچنین در طی مدت آپلود، خاصیت isUploading به true تنظیم می‌شود تا دکمه‌ی ارسال را غیرفعال کند. این خاصیت در صورت بروز خطایی و یا تکمیل شدن عملیات، false می‌شود.



یک نکته: اگر می‌خواهید درصد پیشرفت آپلود را در حالت آزمایش local بهتر مشاهده کنید، دربرگه‌ی network، سرعت را بر روی 3G تنظیم کنید:



کدهای کامل این تغییرات را از اینجا می‌توانید دریافت کنید.
اشتراک‌ها
مقاله ای کامل درباره استفاده از MVC و jQuery و JSON و paging و mapRoute
How to make CRUD with good performance in MVC
How to use jQuery dialog instead of JavaScript confirm or alert
How to make paging in an MVC list
How to make "show more" link using jQuery in MVC
How to use attributes with link
How to make a AJAX call in jQuery
How to use the Form collection in MVC
How to delete multiple records at one shot
How to use partial action in MVC
How to use JSON format in an MVC application
How to fill a master-detail combobox
How to use the jQuery datepicker
How to upload an image in MVC with a jQuery dialog
How to create a table row at client side
How to customize a maproute in Global.asax 
مقاله ای کامل درباره استفاده از MVC و  jQuery و  JSON و  paging و  mapRoute
مطالب
واکشی اطلاعات سرویس Web Api با استفاده از TypeScript و AngularJs
در پست‌های قبلی با TypeScript، AngularJs و Web Api آشنا شدید. در این پست قصد دارم از ترکیب این موارد برای پیاده سازی عملیات واکشی اطلاعات سرویس Web Api در قالب یک پروژه استفاده نمایم. برای شروع ابتدا یک پروژه Asp.Net MVC ایجاد کنید.
در قسمت مدل ابتدا یک کلاس پایه برای مدل ایجاد خواهیم کرد:
public abstract class Entity
    {
        public Guid Id { get; set; }
    }
حال کلاسی به نام Book ایجاد می‌کنیم:
public class Book : EntityBase
    {
        public string Name { get; set; }
        public decimal Author { get; set; }
    }
در پوشه مدل یک کلاسی به نام BookRepository ایجاد کنید و کد‌های زیر را در آن کپی نمایید(به جای پیاده سازی بر روی بانک اطلاعاتی، عملیات بر روی لیست درون حافظه انجام می‌گیرد):
 public class BookRepository
    {
        private readonly ConcurrentDictionary<Guid, Book> result = new ConcurrentDictionary<Guid, Book>();

        public IQueryable<Book> GetAll()
        {
            return result.Values.AsQueryable();
        }        

        public Book Add(Book entity)
        {
            if (entity.Id == Guid.Empty) entity.Id = Guid.NewGuid();

            if (result.ContainsKey(entity.Id)) return null;

            if (!result.TryAdd(entity.Id, entity)) return null;

            return entity;
        }     
    }

نوبت به کلاس کنترلر می‌رسد. یک کنترلر Api به نام BooksController ایجاد کنید و سپس کد‌های زیر را در آن کپی نمایید:
 public class BooksController : ApiController
    {
        public static BookRepository repository = new BookRepository();       

public BooksController()
        {
            repository.Add(new Book 
            {
                Id=Guid.NewGuid(),
                Name="C#",
                Author="Masoud Pakdel"
            });

            repository.Add(new Book
            {
                Id = Guid.NewGuid(),
                Name = "F#",
                Author = "Masoud Pakdel"
            });

            repository.Add(new Book
            {
                Id = Guid.NewGuid(),
                Name = "TypeScript",
                Author = "Masoud Pakdel"
            });
        }

        public IEnumerable<Book> Get()
        {
            return repository.GetAll().ToArray();
        }          
    }

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

حال نویت به عملیات سمت کلاینت میرسد. برای استفاده از قابلیت‌های TypeScript و AngularJs در Vs.Net از این مقاله کمک بگیرید. بعد از آماده سازی در فولدر script، پوشه ای به نام app می‌سازیم و یک فایل TypeScript به نام  BookModel  در آن ایجاد می‌کنیم:
module Model {
    export class Book{
        Id: string;
        Name: string;
        Author: string;
    }
}
واضح است که ماژولی به نام Model داریم که در آن کلاسی به نام Book ایجاد شده است. برای انتقال اطلاعات از طریق سرویس http$ در Angular نیاز به سریالایز کردن این کلاس به فرمت Json خواهیم داشت. قصد داریم View مورد نظر را به صورت زیر ایجاد نماییم:
 <div ng-controller="Books.Controller">       
        <table class="table table-striped table-hover" style="width: 500px;">
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Author</th>              
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="book in books">
                    <td>{{book.Name}}</td>
                    <td>{{book.Author}}</td>                                     
                </tr>
            </tbody>
        </table>
    </div>

توضیح کد‌های بالا:
ابتدا یک کنترلری که به نام Controller که در ماژولی به نام Book تعریف شده است باید ایجاد شود. اطلاعات تمام کتب ثبت شده باید از سرویس مورد نظر دریافت و با یک ng-repeat در جدول نمایش داده خواهند شود.
در پوشه app یک فایل TypeScript دیگر برای تعریف برخی نیازمندی‌ها به نام  AngularModule ایجاد می‌کنیم که کد آن به صورت زیر خواهد بود:
declare module AngularModule {
    export interface HttpPromise {
        success(callback: Function) : HttpPromise;       
    }
    export interface Http {
        get(url: string): HttpPromise;   
    }
}
در این ماژول دو اینترفیس تعریف شده است. اولی به نام HttpPromise است که تابعی به نام success  دارد. این تابع باید بعد از موفقیت آمیز بودن  عملیات فراخوانی شود. ورودی آن از نوع Function است. بعنی اجازه تعریف یک تابع را به عنوان ورودی برای این توابع دارید.
در اینترفیس Http نیز تابعی به نام get تعریف شده  است که  برای دریافت اطلاعات از سرویس api، مورد استفاده قرار خواهد گرفت. از آن جا که تعریف توابع در اینترفیس فاقد بدنه است در نتیجه این جا فقط امضای توابع مشخص خواهد شد. پیاده سازی توابع به عهده کنترلر‌ها خواهد بود:
مرحله بعد مربوط است به تعریف کنترلری  به نام BookController تا اینترفیس بالا را پیاده سازی نماید. کد‌های آن به صورت زیر خواهد بود:
/// <reference path='AngularModule.ts' />
/// <reference path='BookModel.ts' />

module Books {
    export interface Scope {        
        books: Model.Book[];
    }

    export class Controller {
        private httpService: any;

        constructor($scope: Scope, $http: any) {
            this.httpService = $http;

            this.getAllBooks(function (data) {
                $scope.books = data;
            });
            var controller = this;
    }

        getAllBooks(successCallback: Function): void {
            this.httpService.get('/api/books').success(function (data, status) {
                successCallback(data);
            });
        }
    }
}


توضیح کد‌های بالا:
برای دسترسی به تعاریف انجام شده در سایر ماژول‌ها باید ارجاعی به فایل تعاریف ماژول‌های مورد نظر داشته باشیم. در غیر این صورت هنگام استفاده از این ماژول‌ها با خطای کامپایلری روبرو خواهیم شد. عملیات ارجاع به صورت زیر است:
/// <reference path='AngularModule.ts' />
/// <reference path='BookModel.ts' />
در پست قبلی توضیح داده شد که برای مقید سازی عناصر بهتر است یک اینترفیس به نام Scope تعریف کنیم تا بتوانیم متغیر‌های مورد نظر برای مقید سازی را در آن تعریف نماییم در این جا تعریف آن به صورت زیر است:
export interface Scope {  
        books: Model.Book[];      
    }
در این جا فقط نیاز به لیستی از کتاب‌ها داریم تا بتوان در جدول مورد نظر در View آنرا پیمایش کرد. تابعی به نام getAllBooks در کنترلر مورد نظر نوشته شده است که ورودی آن یک تابع خواهد بود که باید بعد از واکشی اطلاعات از سرویس، فراخوانی شود. اگر به کد‌های بالا دقت کنید می‌بینید که در ابتدا سازنده کنترلر،سرویس http$ موجود در Angular به متغیری به نام httpService نسبت داده می‌شود. با فراخوانی تابع get و ارسال آدرس سرویس که با توجه به مقدار مسیر یابی پیش فرض کلاس WebApiConfig باید با api شروع شود به راحتی اطلاعات مورد نظر به دست خواهد آمد. بعد از واکشی در صورت موفقیت آمیز بودن عملیات تابع success اجرا می‌شود که نتیجه آن انتساب مقدار به دست آمده به متغیر books تعریف شده در scope$ می‌باشد.

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


سورس پیاده سازی مثال بالا در Visual Studio 2013
نظرات مطالب
معرفی System.Text.Json در NET Core 3.0.
یک نکته‌ی تکمیلی: نوشتن تبدیلگرهای نوع‌ها برای System.Text.Json

System.Text.Json، در حال حاضر از مفهومی به نام type coercion/inference، پشتیبانی نمی‌کند. type coercion یعنی تبدیل یک مقدار، به مقداری دیگر که به صورت مستقیم قابل انتساب به یکدیگر نیستند. برای مثال اگر رشته‌ی "true" را درنظر بگیریم، قابلیت انتساب به یک خاصیت از نوع bool را ندارد. برای یک چنین مواردی در این API جدید، باید تبدیلگر نوشت.
یک مثال:
using System.Collections.Generic;
using System.Text.Json;

namespace JsonTests
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool IsInStock { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {            
         var products = JsonSerializer.Deserialize<List<Product>>("[{\"Id\":1026,\"Name\":\"P1\",\"IsInStock\":\"false\"}]");
        }
    }
}
در این مثال، خاصیت IsInStock از نوع bool است، اما مقداری را که باید از طریق متد Deserialize دریافت کنیم، یک رشته‌ی bool ای است که قابل انتساب به bool نیست. در این حالت اگر برنامه را اجرا کنیم به استثنای زیر خواهیم رسید:
An unhandled exception of type 'System.Text.Json.JsonException' occurred in System.Text.Json.dll
Inner exceptions found, see $exception in variables window for more details.
Innermost exception System.InvalidOperationException : Cannot get the value of a token type 'String' as a boolean.
برای رفع این مشکل، می‌توان تبدیلگر زیر را تدارک دید:
    public class BooleanConverter : JsonConverter<bool>
    {
        public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var value = reader.GetString();
            if (value.Equals("true", StringComparison.OrdinalIgnoreCase)
                 || value.Equals("yes", StringComparison.OrdinalIgnoreCase)
                 || value.Equals("1", StringComparison.Ordinal))
            {
                return true;
            }

            if (value.Equals("false", StringComparison.OrdinalIgnoreCase)
                 || value.Equals("no", StringComparison.OrdinalIgnoreCase)
                 || value.Equals("0", StringComparison.Ordinal))
            {
                return false;
            }

            throw new NotSupportedException($"`{value}` can't be converted to `bool`.");
        }

        public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
        {
            switch (value)
            {
                case true:
                    writer.WriteStringValue("true");
                    break;
                case false:
                    writer.WriteStringValue("false");
                    break;
            }
        }
    }
برای نوشتن یک تبدیلگر bool، کلاس مرتبط، باید <JsonConverter<bool را پیاده سازی کند. کلاس JsonConverter نیز به صورت زیر تعریف شده‌است:
    public abstract class JsonConverter<T> : JsonConverter
    {
        protected internal JsonConverter();

        public override bool CanConvert(Type typeToConvert);
        public abstract T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
        public abstract void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options);
    }
و پیاده سازی دو متد Read و Write آن الزامی است.
در متد Read آن، مقدار رشته‌ای دریافت شده‌ی از منبع داده، در اختیار ما قرار می‌گیرد. سپس باید بر اساس این مقدار، مقدار متناظری را از نوع T که در اینجا bool است، بازگشت دهیم. برای مثال اگر یکی از مقادیر رشته‌ای true ،yes و 1 را دریافت کردیم، بجای آن true را بازگشت می‌دهیم.

اکنون برای استفاده‌ی از آن خواهیم داشت:
var options = new JsonSerializerOptions();
options.Converters.Add(new BooleanConverter());
var products = JsonSerializer.Deserialize<List<Product>>(
   "[{\"Id\":1026,\"Name\":\"P1\",\"IsInStock\":\"false\"}]",
   options);
و یا روش دیگر انجام اینکار، استفاده از ویژگی JsonConverter، برای معرفی تبدیلگر تهیه شده‌است:
[JsonConverter(typeof(BooleanConverter))]
public bool IsInStock { get; set; }

از این تبدیلگر برای حالت Serialize نیز می‌توان استفاده کرد:
var options  = new JsonSerializerOptions() {WriteIndented = true };
options.Converters.Add(new BooleanConverter());
var data = JsonSerializer.Serialize<List<Product>>(productList, options);
مطالب
یافتن لیست اسمبلی‌های ارجاعی

اگر برنامه‌ی شما برای مثال با SMO مربوط به اس کیوال سرور 2008 کامپایل شود، روی سروری با SQL Server 2005 کار نخواهد کرد و پیغام می‌دهد که نگارش 10 اسمبلی Microsoft.SqlServer.Management.Sdk.Sfc یافت نشد.
یک راه حل آن، نصب Microsoft SQL Server 2008 Management Objects بر روی سرور است، یا راه حل دوم، پیدا کردن اسمبلی‌هایی که برنامه به آن‌ها ارجاع دارد و کپی کردن آن‌ها کنار فایل اجرایی برنامه در سرور. (درست کردن یک برنامه پرتابل دات نتی، یا نسبتا پرتابل!)
برای این منظور کلاس زیر تهیه شده است که مسیر فایل اجرایی یا dll یک پروژه را دریافت کرده و لیست تمام ارجاعات به آن‌را به صورت بازگشتی پیدا می‌کند. (البته در قسمت یافتن مسیر اسمبلی‌ها، اسمبلی‌های سیستمی که با خود دات نت فریم ورک نصب می‌شوند، حذف شده است)

using System.Collections.Generic;
using System.Reflection;
using System.IO;

namespace App
{
class CFindRef
{
#region Fields (2)

/// <summary>
/// لیستی جهت نگهداری نام اسمبلی‌ها
/// </summary>
private readonly List<string> _assemblies = new List<string>();
/// <summary>
/// لیستی جهت نگهداری مسیر اسمبلی‌ها
/// </summary>
private readonly List<string> _filePath = new List<string>();

#endregion Fields

#region Constructors (1)

/// <summary>
/// سازنده کلاس
/// </summary>
/// <param name="fileName">مسیر اولیه اسمبلی مورد نظر</param>
public CFindRef(string fileName)
{
ListReferences(fileName);
}

#endregion Constructors

#region Properties (2)

/// <summary>
/// لیست مسیر اسمبلی‌هایی که به آن‌ها ارجاعی وجود دارد منهای موارد سیستمی
/// </summary>
public List<string> ReferencedFiles
{
get
{
_filePath.Sort();
return _filePath;
}
}

/// <summary>
/// لیست کامل اسمبلی‌هایی که اسمبلی ما به آن‌ها وابسته است
/// </summary>
public List<string> ReferencedNames
{
get
{
_assemblies.Sort();
return _assemblies;
}
}

#endregion Properties

#region Methods (1)

// Private Methods (1)

/// <summary>
/// متدی بازگشتی جهت یافتن لیست ارجاعات
/// </summary>
/// <param name="path">مسیر یا نام اسمبلی</param>
private void ListReferences(string path)
{
//آیا تکراری است؟
if (_assemblies.Contains(path))
return;

Assembly asm;
// آیا فایل است یا نام کامل اسمبلی
if (File.Exists(path))
{
// load the assembly from a path
asm = Assembly.LoadFrom(path);
}
else
{
// سعی در بارگذاری اسمبلی
try
{
asm = Assembly.Load(path);
}
catch
{
asm = null; //جای بهبود دارد
}
}

if (asm == null) return;

// افزودن به لیست نام‌ها
_assemblies.Add(path);
string asmLocation = asm.Location;
//حذف موارد سیستمی از لیست مسیر فایل‌ها
if (asmLocation != null && !asmLocation.Contains("\\System.")
&& !asmLocation.Contains("\\mscorlib"))
_filePath.Add(asmLocation);

// پیدا کردن ارجاع‌ها
AssemblyName[] imports = asm.GetReferencedAssemblies();
// iterate
foreach (AssemblyName asmName in imports)
{
// فراخوانی بازگشتی جهت یافتن تمامی ارجاعات
ListReferences(asmName.FullName);
}
}

#endregion Methods
}
}

مثالی در مورد نحوه‌ی استفاده از آن:

CFindRef cfr = new CFindRef(@"C:\App\test.exe");
foreach (var asmRef in cfr.ReferencedFiles)
{
textBox1.Text += asmRef + Environment.NewLine;
//Application.DoEvents();
}
برای نمونه، برنامه‌ای که از SMO‌ مربوط به اس کیوال سرور 2008 استفاده می‌کند، این لیست ارجاعات را دارد:

C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.ConnectionInfo\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ConnectionInfo.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.Dmf\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Dmf.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.Management.Sdk.Sfc\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Management.Sdk.Sfc.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.ServiceBrokerEnum\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ServiceBrokerEnum.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.Smo\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Smo.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.SqlClrProvider\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.SqlClrProvider.dll
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.SqlEnum\10.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.SqlEnum.dll
با کپی کردن همین فایل‌ها کنار فایل اجرایی برنامه‌ای که قرار است روی سروری با SQL Server 2005 کار کند، مشکل برطرف می‌شود و برنامه بدون مشکل کار خواهد کرد.

برنامه آماده هم در این زمینه موجود است، برای مثال CheckAsm
مشاهده سایت

مطالب
کار با وب سرویس جاوایی تشخیص ایمیل‌های موقتی در دات نت
یکی از وب سرویس‌های سایت name api، امکان تشخیص موقتی بودن ایمیل مورد استفاده‌ی جهت ثبت نام در یک سایت را فراهم می‌کند. آدرس WSDL آن نیز در اینجا قرار دارد. اگر مطابق معمول استفاده از سرویس‌های وب در دات نت، بر روی ارجاعات پروژه کلیک راست کرده و گزینه‌ی Add service refrence را انتخاب کنیم و سپس آدرس WSDL یاد شده را به آن معرفی کنیم، بدون مشکل ساختار این وب سرویس دریافت و برای استفاده‌ی از آن به یک چنین کدی خواهیم رسید:
var client = new SoapDisposableEmailAddressDetectorClient();
 
var context = new soapContext
{
    //todo: get your API key here: http://www.nameapi.org/en/register/
    apiKey = "test"
};
var result = client.isDisposable(context, "DaDiDoo@mailinator.com"); 
 
if (result.disposable.ToString() == "YES")
{
    Console.WriteLine("YES! It's Disposable!");
}
متد isDisposable ارائه شده‌ی توسط این وب سرویس، دو پارامتر context که در آن باید API Key خود را مشخص کرد و همچنین آدرس ایمیل مورد بررسی را دریافت می‌کند. اگر به همین ترتیب این پروژه را اجرا کنید، با خطای Bad request از طرف سرور متوقف خواهید شد:
 Additional information: The remote server returned an unexpected response: (400) Bad Request.
اگر به خروجی این وب سرویس در فیدلر مراجعه کنیم، چنین شکلی را خواهد داشت:
 <html><head><title>Bad Request</title></head><body><h1>Bad Request</h1><p>No api-key provided!</p></body></html>
عنوان کرده‌است که api-key را، در درخواست وب خود ذکر نکرده‌ایم.
اگر همین وب سرویس را توسط امکانات سایت http://wsdlbrowser.com بررسی کنید، بدون مشکل کار می‌کند. اما تفاوت در کجاست؟
خروجی ارسالی به سرور، توسط سایت http://wsdlbrowser.com به این شکل است:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/">
  <SOAP-ENV:Body>
    <ns1:isDisposable>
      <context>
        <apiKey>test</apiKey>       
      </context>
      <emailAddress>sdsdg@site.com</emailAddress>
    </ns1:isDisposable>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
و نمونه‌ی تولید شده‌ی توسط WCF (امکان Add service reference در حقیقت یک WCF Client را ایجاد می‌کند) به صورت زیر می‌باشد:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     <isDisposable xmlns="http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/">
          <context xmlns=""><apiKey>test</apiKey></context>
          <emailAddress xmlns="">DaDiDoo@mailinator.com</emailAddress>
      </isDisposable>
  </s:Body>
</s:Envelope>
از لحاظ اصول XML، خروجی تولیدی توسط WCF هیچ ایرادی ندارد. از این جهت که نام فضای نام مرتبط با http://schemas.xmlsoap.org/soap/envelope/ را به s تنظیم کرده‌است و سپس با استفاده از این نام، Envelope را تشکیل داده‌است. اما ... این وب سرور جاوایی دقیقا با نام SOAP-ENV کار می‌کند و فضای نام ns1 بعدی آن. کاری هم به اصول XML ندارد که باید بر اساس نام xmlns ذکر شده، کار Parse ورودی دریافتی صورت گیرد و نه بر اساس یک رشته‌ی ثابت از پیش تعیین شده. بنابراین باید راهی را پیدا کنیم تا بتوان این s را تبدیل به SOAP-ENV کرد.

برای این منظور به سه کلاس ذیل خواهیم رسید:
public class EndpointBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    { }
 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    { }
 
    public void Validate(ServiceEndpoint endpoint)
    { }
 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new ClientMessageInspector());
    }
}
 
public class ClientMessageInspector : IClientMessageInspector
{
    public void AfterReceiveReply(ref Message reply, object correlationState)
    { }
 
    public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel)
    {
        request = new MyCustomMessage(request);
        return request;
    }
}
 
/// <summary>
/// To customize WCF envelope and namespace prefix
/// </summary>
public class MyCustomMessage : Message
{
    private readonly Message _message;
 
    public MyCustomMessage(Message message)
    {
        _message = message;
    }
 
    public override MessageHeaders Headers
    {
        get { return _message.Headers; }
    }
 
    public override MessageProperties Properties
    {
        get { return _message.Properties; }
    }
 
    public override MessageVersion Version
    {
        get { return _message.Version; }
    }
 
    protected override void OnWriteStartBody(XmlDictionaryWriter writer)
    {
        writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");
    }
 
    protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        _message.WriteBodyContents(writer);
    }
 
    protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
    {
        writer.WriteStartElement("SOAP-ENV", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
        writer.WriteAttributeString("xmlns", "ns1", null, value: "http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/");
    }
}
که پس از تعریف client به نحو ذیل معرفی می‌شوند:
 var client = new SoapDisposableEmailAddressDetectorClient();
client.Endpoint.Behaviors.Add(new EndpointBehavior());
توسط EndpointBehavior سفارشی، می‌توان به متد OnWriteStartEnvelope دسترسی یافت و سپس s آن‌را با SOAP-ENV درخواستی این وب سرویس جایگزین کرد. اکنون اگر برنامه را اجرا کنید، بدون مشکل کار خواهد کرد و دیگر پیام یافت نشدن API-Key را صادر نمی‌کند.

کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مطالب
Vue.js - نصب و راه‌اندازی اولیه - قسمت اول
Vue.js چیست؟
ویو‌جی‌اس یا وو جی اس (Vue.js) یکی از فریم‌ورک‌های جاوااسکریپتی است که به ما در ساختن اپلیکیشن‌های تحت وب و تحت معماری MVVM یا همان (Model–view–viewmodel) کمک می‌کند.
در حالیکه مدت کمی از انتشار Vue.js می‌گذرد، اما این فریم‌ورک به شدت محبوب شده و طرفداران زیادی پیدا کرده است.

پیش‌نیازها :
  • آشنایی کامل با جاوااسکریپت
  • آشنایی با Object-oriented در جاوااسکریپت 

اولین قدم برای استفاده از Vue.js، نصب آن می‌باشد که مرحله به مرحله توضیح خواهم داد. جهت نصب، سایت Vue.js به ما چندین راه پیشنهاد می‌دهد که ما آنها را در ذیل بررسی می‌کنیم:
1- CDN
در قسمت CDN به آدرس زیر مراجعه کرده و لینک آن را در صفحه‌ای که نیاز است از آن استفاده کنیم، قرار می‌دهیم. هرچندکه به صورت لوکال هم می‌توانید کدها را در یک فایل ذخیره کرده و از آن استفاده کنید.
ابتدا باید آدرس زیر، درون تگ < script> قرار بگیرد
https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script>

2- NPM
طبق همین دستور می‌توانید Vue.js را نصب کنید 
$ npm install vue

3- CLI 
 با استفاده از کامند لاین هم به راحتی قابل نصب می‌باشد؛ با استفاده از دستورات زیر
$ npm install -g vue-cli
$ vue init webpack my-project
$ cd my-project
$ npm install
$ npm run dev

توجه: بهترین روش نصب، استفاده از CDN می‌باشد که توصیه می‌شود جهت سهولت و جلوگیری از دردسرهای نصب فریم‌ورک، از مورد اول استفاده کنید.
حال پس از نصب، چنین کدی آماده خواهد شد.
<html> 
    <body> 

      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script> 
    </body> 
</html>
آخرین نسخه از ویو جی اس، 2.2.0 است.