یک نکته‌ی تکمیلی: به روز رسانی مثال مطلب جاری جهت گزارش درصد پیشرفت آپلود فایل‌ها توسط 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 تنظیم کنید:



کدهای کامل این تغییرات را از اینجا می‌توانید دریافت کنید.
‫۷ سال و ۱ ماه قبل، یکشنبه ۲۹ مرداد ۱۳۹۶، ساعت ۱۲:۵۱
- همان «محافظت از المنت‌های صفحه» در مطلب «کنترل دسترسی‌ها در Angular با استفاده از Ng2Permission» است.
- مانند سرویس auth.service.ts در مطلب « مسیریابی در Angular - قسمت دوم - مسیریابی ماژول‌ها » است.
‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۲۳:۲۷
افزونه‌ی #C مخصوص VSCode دقیقا همان روزی که NET Core 2.0. ارائه شد، به روز شده‌است. بنابراین پس از نصب SDK جدید، یکبار VSCode را بسته، به اینترنت متصل شوید، سپس VSCode را باز کنید. در برگه‌ی افزونه‌ها مشاهده خواهید کرد که این افزونه به روز شده‌است و باید صفحه را reload کنید. پس از آن یک فایل #C را هم باز کنید تا کار دریافت دیباگر جدید آن آغاز شود. اینجا است که کار به روز رسانی «دو مرحله‌ای» آن تکمیل می‌شود. پس از آن به ریشه‌ی پروژه وارد شده و دستور dotnet restore را صادر کنید تا وابستگی‌های شناسایی نشده، شناسایی شوند.
‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۲۲:۳۰
استفاده از کامپایلر 1.1 برای پروژه‌های 1.1

اگر NET Core SDK. جدید را نصب کنید، سیستم build پروژه، به صورت خودکار از آخرین نگارش نصب شده استفاده می‌کند (یعنی نگارش 2). اگر می‌خواهید این مورد را بازنویسی کنید، نیاز است فایل ویژه‌ای را به نام global.json با محتوای ذیل به ریشه‌ی solution در بالاترین سطح ممکن اضافه کنید:
{ 
  "sdk": { 
    "version": "1.0.4" 
  } 
}
در اینجا عدد 1.0.4 شماره نگارش SDK مدنظر است. این شماره‌ها را در مسیر C:\Program Files\dotnet\sdk می‌توانید مشاهده کنید و بر این اساس باید تصمیم گیری کنید (بر اساس شماره‌های موجود و نصب شده‌ی بر روی سیستم شما).
و همچنین اگر فایل global.json را اضافه کرده‌اید، حین ارتقاء پروژه حتما باید شماره SDK موجود در آن‌را به صورت دستی اصلاح کنید؛ وگرنه پروژه build نخواهد شد. عدم وجود این فایل به معنای استفاده‌ی از آخرین شماره نگارش SDK موجود است.
‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۲۲:۱۲
من مدتی هست که از نگارش کامل ویژوال استودیو دیگر استفاده نمی‌کنم. با VSCode هیچ مشکلی نیست و همه چیز روان است. نگارش کامل ویژوال استودیو مربوط به زمانی بود که یک فایل ISO چندگیگابایتی را ارائه می‌دادند و تا سه سال بعدش نیازی به به‌روز رسانی نبود. سیستم کار NET Core. چابک هست و با VSCode بیشتر سازگاری دارد تا ویژوال استودیوی سنگین و حجیم.
‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۱۹:۳۱
Default Compile Item Values in the the .NET Core SDK : لیستی که در این ماخذ ذکر شده به صورت خودکار به پروژه اضافه می‌شوند. اگر این لیست را مجددا به فایل csproj اضافه کنید، دوبار به پروژه الحاق خواهند شد که سبب بروز خطای فوق می‌گردد. برای مثال نیازی به ذکر یک چنین تنظیمی دیگر نیست و ذکر مجدد آن خطای محتوای تکراری را ایجاد می‌کند:
<ItemGroup>
    <Content Include="wwwroot\**" />
</ItemGroup>

‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۱۶:۵۳
ارتقاء به C# 7.1 و ASP.NET Core 2.0

اگر در فایل‌های Razor برنامه‌های ASP.NET Core 2.0 می‌خواهید از قابلیت‌های C# 7.1 استفاده کنید، نیاز است تنظیم LangVersion ذیل را به فایل csproj اضافه نمائید:
  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
     <LangVersion>latest</LangVersion>
  </PropertyGroup>
‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۱۵:۱۲
تکمیل نکته‌ی «نکته‌ای مهم در مورد تزریق وابستگی‌ها در کلاس ویژه‌ی آغازین برنامه » که در بالا عنوان شد

در ASP.NET Core 2.0 در صورت عدم رعایت این نکته و عدم ایجاد یک scope جدید، ممکن است خطای ذیل را دریافت کنید:
Unhandled Exception: System.InvalidOperationException: Cannot resolve scoped service from root provider.
تنظیم این بررسی در فایل program.cs صورت می‌گیرد:
namespace ASPNETCoreIdentitySample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
               // ...
                .UseDefaultServiceProvider((context, options) =>
                {
                    options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                })
               // ...

            host.Run();
        }
    }
}
در اینجا اگر ValidateScopes را false کنید این استثناء را دریافت نخواهید کرد. اما بهتر است این تنظیم وجود داشته باشد تا مشکلاتی از این دست پیش از ارائه‌ی نهایی برنامه مشخص شوند. راه حل صحیح آن هم ایجاد یک scope جدید توسط scopeFactory.CreateScope است که به آن اشاره شد.