نظرات مطالب
معماری لایه بندی نرم افزار #1
اگر مقاله فوق رو با دقت بخونید متوجه میشید که MVC و MVVM در لایه UI پیاده سازی میشن. البته در MVC لایه Model رو به Domain Model و Repository در برخی مواقع لایه Controller رو در لایه Presentation قرار میدن. در MVVM نیز لایه Model در Domain Model و Repository و لایه View Model نیز در لایه Presentation قرار میگیره. همچنین View Model‌ها نیز در لایه Service قرار میگیرن.
در مورد ماژول بندی هم اگر در مقاله خونده باشید میتونید لایه‌ها رو از طریق پوشه ها، فضای نام و یا پروژه‌ها از هم جدا کنید
اشتراک‌ها
انتشار سورس #Unity C

This Friday we published the Unity engine and editor C# source code on GitHub, under a reference-only license. 

انتشار سورس #Unity C
مطالب
کمی درباره httpmodule
قبل از اینکه به httpmodule‌ها بپردازیم، اجازه بدید کمی در در مورد  httphandler  اطلاعات کسب کنیم. httphandler ویژگی است که از asp.net  به بعد ایجاد شد و در asp کلاسیک خبری از آن نیست.
یک httphandler کامپوننتی است که از طریق اینترفیس System.Web.IHttpHandler پیاده سازی میشود و به پردازش درخواست‌های رسیده از httprequest رسیدگی می‌کند.
فرض کنید کاربری درخواست صفحه default.aspx را کرده است و سرور هم پاسخ آن را می‌دهد. در واقع پردازش اینکه چه پاسخی باید به کاربر یا کلاینت ارسال شود بر عهده این کامپوننت می‌باشد. برای وب سرویس هم موضوع به همین صورت است؛ هر نوع درخواست HTTP از این طریق انجام می‌شود.
حال به سراغ httpmodule می‌رویم. httpmodule‌ها اسمبلی یا ماژول‌هایی هستن که بر سر راه هر درخواست کاربر از سرور قرار گرفته و قبل از اینکه درخواست شما به httphandler برسد، اول از فیلتر این‌ها رد می‌شود. در واقع موقعی که شما درخواست صفحه default.aspx را می‌کنید، درخواست شما به موتور asp.net ارسال می‌شود و از میان فیلترهایی رد می‌شود تا به دست httphandler برای پردازش خروجی برسد. برای همین اگر گاهی به جای گفتن asp.net engine عبارت asp.net pipeline هم میگویند همین هست؛ چون درخواست شما از بین بخش‌های زیادی می‌گذرد تا به httphandler برسد که httpmodule یکی از آن بخش هاست. با هر درخواستی که سرور ارسال می‌شود، httpmodule‌ها صدا زده می‌شوند و به برنامه نویس امکان بررسی اطلاعات درخواستی و پردازش درخواست‌ها را در ورودی و خروجی، می‌دهد و شما میتوانید هر عملی را که نیاز دارید انجام دهید. تعدادی از این ماژول‌های آماده، همان state‌ها و Authentication می‌باشند.
تصویر زیر نحوه‌ی ارسال و بازگشت یک درخواست را به سمت httphandler نشان می‌دهد


برنامه نویس هم میتواند با استفاده از اینترفیس‌های IHttpModule و IHttpHandler در درخواست‌ها دخالت نماید.
برای شروع یک کلاس ایجاد کنید که اینترفیس IHttpModule را پیاده سازی می‌کند. شما دو متد را باید در این کلاس بنویسید؛ یکی Init و دیگر Dispose. همانطور که مطلع هستید، اولی در ابتدای ایجاد شیء و دیگر موقع از دست رفتن شی صدا زده می‌شود.
متد Init یک آرگومان از نوع httpapplication دارد که مانند رسم نامگذاری متغیرها، بیشتر به اسم context یا app نام گذاری می‌شوند:
public void Init(HttpApplication app)
{
   app.BeginRequest += new EventHandler(OnBeginRequest);
}

public void Dispose(){ }
همانطور که می‌بینید این شیء یک رویداد دارد که ما این رویداد را به تابعی به نام OnBeginRequest متصل کردیم. سایر رویداد‌های موجود در httpapplication  به شرح زیر می‌باشند:
 BeginRequest  این رویداد اولین رویدادی است که اجرا می‌شود، هر نوع عملی که میخواهید در ابتدای ارسال درخواست انجام دهید، باید در این قسمت قرار بگیرد؛ مثلا قرار دادن یک بنر بالای صفحه 
AuthenticateRequest خود دانت از یک سیستم امنیتی توکار بهره مند است و اگر می‌خواهید در مورد آن خصوصی سازی انجام بدهید، این رویداد می‌تواند کمکتان کند 
AuthorizeRequest بعد از رویداد بالا، این رویداد برای شناسایی انجام می‌شود. مثلا دسترسی ها؛ دسترسی به قسمت هایی خاصی از منابع به او داده شود و قسمت هایی بعضی از منابع از او گرفته شود.
ResolveRequestCache این رویداد برای کش کردن اطلاعات استفاده می‌شود. خود دانت تمامی این رویدادها را به صورت تو کار فراهم آورده است؛ ولی اگر باز خصوصی سازی خاصی مد نظر شماست می‌توانید در این قسمت‌ها، تغییراتی را اعمال کنید. مثلا ایجاد file caching به جای memory cache و ... 
AcquireRequestState این قسمت برای مدیریت state می‌باشد مثلا مدیریت session ها
PreRequestHandlerExecute این رویداد قبل از httphandler اجرا می‌شود.
PostRequestHandlerExecute این رویداد بعد از httphandler اجرا می‌شود.
ReleaseRequestState این رویداد برای این صدا زده می‌شود که به شما بگوید عملیات درخواست پایان یافته است و باید state‌های ایجاد شده را release یا رها کنید.
UpdateRequestCache   برای خصوصی سازی output cache بکار می‌رود.
EndRequest عملیات درخواست پایان یافته است. در صورتیکه قصد نوشتن دیباگری در طی تمامی عملیات دارید، میتواند به شما کمک کند. 
PreSendRequestHeaders این رویداد قبل از ارسال طلاعات هدر هست. اگر قصد اضافه کردن اطلاعاتی به هدر دارید، این رویداد را به کار ببرید.
PreSendRequestContent  این رویداد موقعی صدا زده می‌شود که متد response.flush فراخوانی شود.، اگر می‌خواهید به محتوا چیزی اضافه کنید، از اینجا کمک بگیرید.
Error این رویداد موقعی رخ می‌دهد که یک استثنای مدیریت نشده رخ بدهد. برای نوشتن سیستم خطایابی خصوصی از این قسمت عمل کنید.
Disposed  این رویداد موقعی صدا زده میشود که درخواست، بنا به هر دلیلی پایان یافته است. برای عملیات پاکسازی و .. می‌شود از آن استفاده کرد. مثلا یک جور rollback برای کارهای انجام گرفته.

کد زیر را در نظر بگیرید:
کد زیر یک رویداد را تعریف کرده و سپس خود httpapplication را به عنوان sender استفاده می‌کند.
در اینجا قصد داریم یکی از صفحات را در خروجی تغییر دهیم. آدرس تایپ شده همان باشد ولی صفحه‌ی درخواست شده، صفحه‌ی دیگری است. این کار موقعی بیشتر کاربردی است که آدرس یک صفحه تغییر کرده و کاربر آدرس قبلی را وارد می‌کند. حالا یا از طریق بوک مارک یا از طریق یک لینک، در یک جای دیگر و شما میخواهید او را به صفحه‌ای جدید انتقال دهید، ولی در نوار آدرس، همان آدرس قبلی باقی بماند. همچنین کار دیگری که قرار است انجام بگیرد محاسبه مدت زمان رسیدگی به درخواست را محاسبه کند ، برای همین در رویداد BeginRequest زمان شروع درخواست را ذخیره و در رویداد EndRequest با به دست آوردن اختلاف زمان فعلی با زمان شروع به مدت زمان مربوطه پی خواهیم برد.
با استفاده از app.Context.Request.RawUrl آدرس اصلی و درخواست شده را یافته و در صورتی که شامل نام صفحه مربوطه بود، با نام صفحه‌ی جدید جابجا می‌کنیم تا اطلاعات به صفحه‌ی جدید پاس شوند ولی در نوار آدرس، هنوز آدرس قبلی یا درخواست شده، قابل مشاهده است.
در خط ["app.Context.Items["start  که یک کلاس ارث بری شده از اینترفیس IDictionary است، بر اساس کلید، داده شما را ذخیره و در مواقع لزوم در هر رویداد به شما باز می‌گرداند.
 public class UrlPath : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            app.BeginRequest+=new EventHandler(_BeginRequest);
            app.EndRequest+=new EventHandler(_EndRequest);
        }

        public void Dispose()
        {

        }

         void _BeginRequest(object sender, EventArgs e)
         {
             
             HttpApplication app = (HttpApplication) sender;
             app.Context.Items["start"] = DateTime.Now;

             if (app.Context.Request.RawUrl.ToLower().Contains("tours_list.aspx"))
             {
                 app.Context.RewritePath(app.Context.Request.RawUrl.ToLower().Replace("tours_list.aspx","tours_cat.aspx"));
             }

         }
         void _EndRequest(object sender, EventArgs e)
         {
             HttpApplication app = (HttpApplication)sender;
             string log = (DateTime.Now - DateTime.Parse(app.Context.Items["start"].ToString())).ToString();
             Debugger.Log(0,"duration","request took " + log+Environment.NewLine); 
             
         } 
    }
حالا باید کلاس نوشته شده را به عنوان یک httpmodule به سیستم معرفی کنیم. به همین منظور وارد web.config شوید و کلاس جدید را معرفی کنید:
  <httpModules>
     <add name="UrlPath" type="UrlPath"/> 
   </httpModules>
اگر کلاس شما داخل یک namespace قرار دارد، در قسمت type حتما قبل از نام کلاس، آن را تعریف کنید namspace.ClassName
حالا دیگر کلاس UrlPath  به عنوان یک httpmodule به سیستم معرفی شده است. تگ httpmodule را بین تگ <system.web> قرار داده ایم.
در ادامه پروژه را start بزنید تا نتیجه کار را ببینید:
اگر IIS شما، هم نسخه‌ی IIS من باشد، نباید تفاوتی مشاهده کنید و می‌بینید که درخواست‌ها هیچ تغییری نکردند؛ چرا که اصلا httpmodule اجرا نشده است. در واقع در نسخه‌های قدیمی IIS یعنی 6 به قبل، این تعریف درست است ولی از نسخه‌ی 7 به بعد IIS، روش دیگری برای تعریف را قبول دارد و باید تگ httpmodule، بین دو تگ <syste.webserver> قرار بگیرد و نام تگ httpmodule به module تغییر پیدا کند.
پس کد فوق به این صورت تغییر می‌کند:
<system.webServer>
  
    <modules>
      <add name="UrlRewrite" type="UrlRewrite"/>
    </modules>
</system.webServer>
حالا اگر قصدا دارید که پروژه‌ی شما در هر دو IIS مورد حمایت قرار گیرد، باید این ماژول را در هر دو جا معرفی کرده و در تگ system.webserver  نیاز است تگ زیر تعریف شود که به طوری پیش فرض در webconfig می‌باشد:
    <validation validateIntegratedModeConfiguration="false"/>
در غیر این صورت خطای زیر را دریافت می‌کنید:

HTTP Error 500.22 - Internal Server Error 

در کل استفاده از این ماژول به شما کمک می‌کند تمامی اطلاعات ارسالی به سیستم را قبل از رسیدن به قسمت پردازش بررسی نمایید و هر نوع تغییری را که میخواهید اعمال کنید و لازم نیست این تغییرات را روی هر بخش، جداگانه انجام دهید یا یک کلاس بنویسید که هر بار در یک جا صدا بزنید و خیلی از موارد دیگر

Global.asax و HttpModule
اگر با global.asax کار کرده باشید حتما می‌پرسید که الان چه تفاوتی با httpmodule دارد؟ در فایل global هم همین‌ها را دارید و دقیقا همین مزایا مهیاست؛ در واقع global.asax یک پیاده سازی از httpapplication هست.
کلاس‌های httpmodule  نام دیگری هم دارند به اسم Portable global .asax به معنی یک فایل global.asax قابل حمل یا پرتابل. دلیل این نام گذاری این هست که شما موقعی که یک کد را در فایل global می‌نویسید، برای همیشه آن کد متعلق به همان پروژه هست و قابل انتقال به یک پروژه دیگر نیست ولی شما میتوانید httpmodule‌ها را در قالب یک پروژه به هر پروژه ای که دوست دارید رفرنس کنید و کد شما قابلیت استفاده مجدد و Reuse پیدا می‌کند و هم اینکه در صورت نیاز می‌توانید آن‌ها را در قالب یک dll منتشر کنید.
مطالب
روش کار با فایل‌های پویای ارائه شده‌ی توسط یک برنامه‌ی ASP.NET Core در برنامه‌های React
پس از آشنایی با «روش کار با فایل‌های ایستا در برنامه‌های React»، اکنون اگر این فایل‌ها ایستا نباشند و توسط یک برنامه‌ی ASP.NET Core بازگشت داده شوند، چطور می‌توان از آن‌ها در برنامه‌های React استفاده کرد؟

برپایی پروژه‌های مورد نیاز

ابتدا یک پوشه‌ی جدید را مانند DownloadFilesSample، ایجاد کرده و در داخل آن دستور زیر را اجرا می‌کنیم:
> dotnet new react
در مورد این قالب که امکان تجربه‌ی توسعه‌ی یکپارچه‌ی ASP.NET Core و React را میسر می‌کند، در مطلب «روش یکی کردن پروژه‌های React و ASP.NET Core» بیشتر بحث کردیم.
سپس در این پوشه، پوشه‌ی ClientApp پیش‌فرض آن‌را حذف می‌کنیم؛ چون کمی قدیمی است. همچنین فایل‌های کنترلر و سرویس آب و هوای پیش‌فرض آن‌را به همراه پوشه‌ی صفحات Razor آن، حذف می‌کنیم.
به علاوه بجای تنظیم پیش فرض زیر در فایل کلاس آغازین برنامه:
spa.UseReactDevelopmentServer(npmScript: "start");
از تنظیم زیر استفاده کرده‌ایم تا با هر بار تغییری در کدهای پروژه‌ی ASP.NET، یکبار دیگر از صفر npm start اجرا نشود:
spa.UseProxyToSpaDevelopmentServer("http://localhost:3000");
بدیهی است در این حالت باید از طریق خط فرمان به پوشه‌ی clientApp وارد شد و دستور npm start را یکبار به صورت دستی اجرا کرد، تا این وب سرور بر روی پورت 3000، راه اندازی شود.

اکنون در ریشه‌ی پروژه‌ی ASP.NET Core ایجاد شده، دستور زیر را صادر می‌کنیم تا پروژه‌ی کلاینت React را با فرمت جدید آن ایجاد کند:
> create-react-app clientapp
سپس وارد این پوشه‌ی جدید شده و بسته‌های زیر را نصب می‌کنیم:
> cd clientapp
> npm install --save bootstrap axios
توضیحات:
- برای استفاده از شیوه‌نامه‌های بوت استرپ، بسته‌ی bootstrap نیز در اینجا نصب می‌شود که برای افزودن فایل bootstrap.css آن به پروژه‌ی React خود، ابتدای فایل clientapp\src\index.js را به نحو زیر ویرایش خواهیم کرد:
 import "bootstrap/dist/css/bootstrap.css";
این import به صورت خودکار توسط webpack ای که در پشت صحنه کار bundling & minification برنامه را انجام می‌دهد، مورد استفاده قرار می‌گیرد.
- برای دریافت فایل‌ها از سمت سرور، از کتابخانه‌ی معروف axios استفاده خواهیم کرد.


کدهای سمت سرور دریافت فایل‌های پویا

در اینجا کدهای سمت سرور برنامه، یک فایل PDF ساده را بازگشت می‌دهند. این محتوای باینری می‌تواند حاصل اجرای یک گزارش اکسل، PDF و یا کلا هر نوع فایلی باشد:
using Microsoft.AspNetCore.Mvc;

namespace DownloadFilesSample.Controllers
{
    [Route("api/[controller]")]
    public class ReportsController : Controller
    {
        [HttpGet("[action]")]
        public IActionResult GetPdfReport()
        {
            return File(virtualPath: "~/app_data/sample.pdf",
                        contentType: "application/pdf",
                        fileDownloadName: "sample.pdf");
        }
    }
}
فایل بازگشتی فوق که در این مثال در مسیر wwwroot\app_data\sample.pdf برنامه‌ی وب کپی شده‌است، در نهایت با آدرس api/Reports/GetPdfReport در سمت کلاینت قابل دسترسی خواهد بود.


روش دریافت محتوای باینری در برنامه‌های React

برای دریافت یک محتوای باینری از سرور توسط axios مانند تصاویر، فایل‌های PDF و اکسل و غیره، مهم‌ترین نکته، تنظیم ویژگی responseType آن به blob است:
  const getResults = async () => {
      const { headers, data } = await axios.get(apiUrl, {
        responseType: "blob"
      });
  }


ساخت URL برای دسترسی به اطلاعات باینری

تمام مرورگرهای جدید از ایجاد URL برای اشیاء Blob دریافتی از سمت سرور، توسط متد توکار URL.createObjectURL پشتیبانی می‌کنند. این متد، شیء URL را از شیء window جاری دریافت می‌کند و سپس اطلاعات باینری را دریافت کرده و آدرسی را جهت دسترسی موقت به آن تولید می‌کند. حاصل آن، یک URL ویژه‌است مانند blob:https://localhost:5001/03edcadf-89fd-48b9-8a4a-e9acf09afd67 که گشودن آن در مرورگر، یا سبب نمایش آن تصویر و یا دریافت مستقیم فایل خواهد شد.
در ادامه کدهای تبدیل blob دریافت شده‌ی از سرور را به این URL ویژه، مشاهده می‌کنید:
import axios from "axios";
import React, { useEffect, useState } from "react";

export default function DisplayPdf() {
  const apiUrl = "https://localhost:5001/api/Reports/GetPdfReport";

  const [blobInfo, setBlobInfo] = useState({
    blobUrl: "",
    fileName: ""
  });

  useEffect(() => {
    getResults();
  }, []);

  const getResults = async () => {
    try {
      const { headers, data } = await axios.get(apiUrl, {
        responseType: "blob"
      });
      console.log("headers", headers);

      const pdfBlobUrl = window.URL.createObjectURL(data);
      console.log("pdfBlobUrl", pdfBlobUrl);

      const fileName = headers["content-disposition"]
        .split(";")
        .find(n => n.includes("filename="))
        .replace("filename=", "")
        .trim();
      console.log("filename", fileName);

      setBlobInfo({
        blobUrl: pdfBlobUrl,
        fileName: fileName
      });
    } catch (error) {
      console.log(error);
    }
  };
توضیحات:
- توسط useEffect Hook و بدون ذکر وابستگی خاصی در آن، سبب شبیه سازی رویداد componentDidUpdate شده‌ایم. به این معنا که متد getResults فراخوانی شده‌ی در آن، پس از رندر کامپوننت در DOM فراخوانی می‌شود و بهترین محلی است که از آن می‌توان برای ارسال درخواست‌های Ajaxای به سمت سرور و دریافت اطلاعات از backend، استفاده کرد و سپس setState را با اطلاعات جدید فراخوانی نمود. معادل setState در اینجا نیز، همان شیء حالتی است که توسط useState Hook و متد setBlobInfo آن تعریف کرده‌ایم.
- پس از دریافت headers و data از سرور، با استفاده از متد createObjectURL، آن‌را تبدیل به یک blob URL کرده‌ایم.
- همچنین در سمت سرور، پارامتر fileDownloadName را نیز تنظیم کرده‌ایم. این نام در سمت کلاینت، توسط هدری با کلید content-disposition ظاهر می‌شود:
ontent-disposition: "attachment; filename=sample.pdf; filename*=UTF-8''sample.pdf"
 بنابراین می‌توان آن‌را تجزیه کرد و سپس filename را از آن استخراج نمود.
- اکنون که نام فایل و URL دسترسی به داده‌ی فایل باینری دریافتی از سرور را استخراج و ایجاد کرده‌ایم. با فراخوانی متد setBlobInfo، سبب تنظیم متغیر حالت blobInfo خواهیم شد. این مورد، رندر مجدد UI را سبب شده و توسط آن می‌توان برای مثال فایل PDF دریافتی را نمایش داد.


نمایش فایل PDF دریافتی از سرور، به همراه دکمه‌های دریافت، چاپ و بازکردن آن در برگه‌ای جدید

در ادامه کدهای کامل قسمت رندر این کامپوننت را مشاهده می‌کنید:
import axios from "axios";
import React, { useEffect, useState } from "react";

export default function DisplayPdf() {

  // ...

  const { blobUrl } = blobInfo;

  return (
    <>
      <h1>Display PDF Files</h1>
      <button className="btn btn-info" onClick={handlePrintPdf}>
        Print PDF
      </button>
      <button className="btn btn-primary ml-2" onClick={handleShowPdfInNewTab}>
        Show PDF in a new tab
      </button>
      <button className="btn btn-success ml-2" onClick={handleDownloadPdf}>
        Download PDF
      </button>

      <section className="card mb-5 mt-3">
        <div className="card-header">
          <h4>using iframe</h4>
        </div>
        <div className="card-body">
          <iframe
            title="PDF Report"
            width="100%"
            height="600"
            src={blobUrl}
            type="application/pdf"
          ></iframe>
        </div>
      </section>

      <section className="card mb-5">
        <div className="card-header">
          <h4>using object</h4>
        </div>
        <div className="card-body">
          <object
            data={blobUrl}
            aria-label="PDF Report"
            type="application/pdf"
            width="100%"
            height="100%"
          ></object>
        </div>
      </section>

      <section className="card mb-5">
        <div className="card-header">
          <h4>using embed</h4>
        </div>
        <div className="card-body">
          <embed
            aria-label="PDF Report"
            src={blobUrl}
            type="application/pdf"
            width="100%"
            height="100%"
          ></embed>
        </div>
      </section>
    </>
  );
}
که چنین خروجی را ایجاد می‌کند:


در اینجا با انتساب مستقیم blob URL ایجاد شده، به خواص src و یا data اشیائی مانند iframe ،object و یا embed، می‌توان سبب نمایش فایل pdf دریافتی از سرور شد. این نمایش نیز توسط قابلیت‌های توکار مرورگر صورت می‌گیرد و نیاز به نصب افزونه‌ی خاصی را ندارد.

در ادامه کدهای مرتبط با سه دکمه‌ی چاپ، دریافت و بازکردن فایل دریافتی از سرور را مشاهده می‌کنید.


مدیریت دکمه‌ی چاپ PDF

پس از اینکه به blobUrl دسترسی یافتیم، اکنون می‌توان یک iframe مخفی را ایجاد کرد، سپس src آن‌را به این آدرس ویژه تنظیم نمود و در آخر متد print آن‌را فراخوانی کرد که سبب نمایش خودکار دیالوگ چاپ مرورگر می‌شود:
  const handlePrintPdf = () => {
    const { blobUrl } = blobInfo;
    if (!blobUrl) {
      throw new Error("pdfBlobUrl is null");
    }

    const iframe = document.createElement("iframe");
    iframe.style.display = "none";
    iframe.src = blobUrl;
    document.body.appendChild(iframe);
    if (iframe.contentWindow) {
      iframe.contentWindow.print();
    }
  };


مدیریت دکمه‌ی نمایش فایل PDF در یک برگه‌ی جدید

اگر علاقمند بودید تا این فایل PDF را به صورت تمام صفحه و در برگه‌ای جدید نمایش دهید، می‌توان از متد window.open استفاده کرد:
const handleShowPdfInNewTab = () => {
    const { blobUrl } = blobInfo;
    if (!blobUrl) {
      throw new Error("pdfBlobUrl is null");
    }

    window.open(blobUrl);
  };

مدیریت دکمه‌ی دریافت فایل PDF

بجای نمایش فایل PDF می‌توان دکمه‌ای را بر روی صفحه قرار داد که با کلیک بر روی آن، این فایل توسط مرورگر به صورت متداولی جهت دریافت به کاربر ارائه شود:
  const handleDownloadPdf = () => {
    const { blobUrl, fileName } = blobInfo;
    if (!blobUrl) {
      throw new Error("pdfBlobUrl is null");
    }

    const anchor = document.createElement("a");
    anchor.style.display = "none";
    anchor.href = blobUrl;
    anchor.download = fileName;
    document.body.appendChild(anchor);
    anchor.click();
  };
در اینجا یک anchor جدید به صورت مخفی به صفحه اضافه می‌شود که href آن به blobUrl تنظیم شده‌است و همچنین از فایل fileName استخراجی نیز در اینجا جهت ارائه‌ی نام اصلی فایل دریافتی از سرور، کمک گرفته شده‌است. سپس متد click آن فراخوانی خواهد شد. این روش در مورد تدارک دکمه‌ی دریافت تمام blobهای دریافتی از سرور کاربرد دارد و منحصر به فایل‌های PDF نیست.
اگر خواستید عملیات axios.get و دریافت فایل، با هم یکی شوند، می‌توان متد handleDownloadPdf را پس از پایان کار await axios.get، فراخوانی کرد.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: DownloadFilesSample.zip
برای اجرای آن، پس از صدور فرمان dotnet restore که سبب بازیابی وابستگی‌های سمت کلاینت نیز می‌شود، ابتدا به پوشه‌ی clientapp مراجعه کرده و فایل run.cmd را اجرا کنید. با اینکار react development server بر روی پورت 3000 شروع به کار می‌کند. سپس به پوشه‌ی اصلی برنامه‌ی ASP.NET Core بازگشته و فایل dotnet_run.bat را اجرا کنید. این اجرا سبب راه اندازی وب سرور برنامه و همچنین ارائه‌ی برنامه‌ی React بر روی پورت 5001 می‌شود.
مطالب
لینک‌های هفته آخر آذر

وبلاگ‌ها و سایت‌های ایرانی


امنیت


Visual Studio


ASP. Net


طراحی وب


PHP

  • Aptana PHP 1.0 منتشر شد (اگر قبلا این IDE بسیار قابل توجه را دریافت کرده بودید فقط کافی است به منوی aptana و گزینه my aptana مراجعه کرده و از قسمت plugins ، این پلاگین 18 مگابایتی را دریافت کنید.)

اس‌کیوال سرور


سی شارپ


عمومی دات نت


ویندوز


متفرقه


بازخوردهای دوره
بایدها و نبایدهای استفاده از IoC Containers
- همیشه بجای ()new MyClass می‌توان نوشت ()<>ObjectFactory.GetInstance<MyClass. در این حالت به صورت خودکار تا n سطح، تمام وابستگی‌های MyClass به صورت خودکار وهله سازی می‌شوند.
- همچنین بحث مفصلی در مورد مسیریابی و تزریق وابستگی‌ها در ASP.NET MVC در اینجا: «Improving ASP.NET MVC Routing Configuration »
اشتراک‌ها
آموزش کار با Razor pages

Asp.net core mvc (7.0) in one video | Asp.net core mvc tutorial for beginners
Entity framework core tutorial
.Net 7 Razor pages full course | Razor pages for .net core
 

آموزش کار با Razor pages
نظرات مطالب
Garbage Collector در #C - قسمت سوم
سلام، 
خیر، به تغییر دیگه ای نیازی نیست اما به این نکته توجه کنید که اگر منظورتون از "پروژه mvc"، یک پروژه ASP.NET MVC هست، نیازی به اضافه کردن این مورد بصورت Explicit داخل Web.Config نیست، چون بصورت پیشفرض برنامه‌های ASP.NET و بطور کلی سمت سرور، از Server GC استفاده میکنن.