بررسی روش آپلود فایل‌ها در ASP.NET Core
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: هفت دقیقه

مدیریت پردازش آپلود فایل‌ها در ASP.NET Core نسبت به ASP.NET MVC 5.x به طور کامل تغییر کرده‌است و اینبار بجای ذکر نوع System.Web.HttpPostedFileBase باید از اینترفیس جدید IFormFile واقع در فضای نام Microsoft.AspNetCore.Http کمک گرفت.


مراحل فعال سازی آپلود فایل‌ها در ASP.NET Core

مرحله‌ی اول فعال سازی آپلود فایل‌ها در ASP.NET Core، شامل افزودن ویژگی "enctype="multipart/form-data به یک فرم تعریف شده‌است:
<form method="post"
      asp-action="Index"
      asp-controller="TestFileUpload"
      enctype="multipart/form-data">
    <input type="file" name="files" multiple />
    <input type="submit" value="Upload" />
</form>
در اینجا همچنین ذکر ویژگی multiple در input از نوع file، امکان ارسال چندین فایل با هم را نیز میسر می‌کند.
در سمت سرور، امضای اکشن متد دریافت کننده‌ی این فایل‌ها به صورت ذیل خواهد بود:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(IList<IFormFile> files)
در اینجا نام پارامتر تعریف شده، باید دقیقا مساوی نام input از نوع file باشد. همچنین از آنجائیکه ویژگی multiple را نیز در سمت کلاینت قید کرده‌ایم، این پارامتر سمت سرور از نوع یک لیست، تعریف شده‌است. اگر ویژگی multiple را حذف کنیم می‌توان آن‌را به صورت ساده‌ی IFormFile files نیز تعریف کرد.


یافتن جایگزینی برای Server.MapPath در ASP.NET Core

زمانیکه فایل ارسالی، در سمت سرور دریافت شد، مرحله‌ی بعد، ذخیره سازی آن بر روی سرور است و از آنجائیکه ما دقیقا نمی‌دانیم ریشه‌ی سایت در کدام پوشه‌ی سرور واقع شده‌است، می‌شد از متد Server.MapPath برای یافتن دقیق آن کمک گرفت. با حذف این متد در ASP.NET Core، روش یافتن ریشه‌ی سایت یا همان پوشه‌ی wwwroot در اینجا شامل مراحل ذیل است:
public class TestFileUploadController : Controller
{
    private readonly IHostingEnvironment _environment;
    public TestFileUploadController(IHostingEnvironment environment)
    {
        _environment = environment;
    }
ابتدا اینترفیس توکار IHostingEnvironment را در سازنده‌ی کلاس تزریق می‌کنیم. سرویس HostingEnvironment جزو سرویس‌های از پیش تعریف شده‌ی ASP.NET Core است و نیازی به تنظیمات اضافه‌تری ندارد. همینقدر که ذکر شود، به صورت خودکار توسط ASP.NET Core مقدار دهی و تامین می‌گردد.
پس از آن خاصیت environment.WebRootPath_ به ریشه‌ی پوشه‌ی wwwroot برنامه، بر روی سرور اشاره می‌کند. به این ترتیب می‌توان مسیر دقیقی را جهت ذخیره سازی فایل‌های رسیده، مشخص کرد.


امکان ذخیره سازی async فایل‌ها در ASP.NET Core

عملیات کار با فایل‌ها، عملیاتی است که از مرزهای IO سیستم عبور می‌کند. به همین جهت یکی از بهترین مثال‌های پیاده سازی async، جهت رها سازی تردهای برنامه و بالا بردن میزان پاسخ‌دهی آن با بالا بردن تعداد تردهای آزاد بیشتر است. در ASP.NET Core، نوشتن async محتوای فایل رسیده در یک stream پشتیبانی می‌شود و این stream می‌تواند یک FileStream و یا MemoryStream باشد. در ذیل نحوه‌ی کار async با یک FileStream را مشاهده می‌کنید:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(IList<IFormFile> files)
{
    var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");
    if (!Directory.Exists(uploadsRootFolder))
    {
        Directory.CreateDirectory(uploadsRootFolder);
    }
 
    foreach (var file in files)
    {
        if (file == null || file.Length == 0)
        {
            continue;
        }
 
        var filePath = Path.Combine(uploadsRootFolder, file.FileName);
        using (var fileStream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(fileStream).ConfigureAwait(false);
        }
    }
    return View();
}
در اینجا کدهای کامل متد دریافت فایل‌ها را در سمت سرور مشاهده می‌کنید. ابتدا با استفاده از خاصیت environment.WebRootPath_، به مسیر ریشه‌ی wwwroot دسترسی و سپس پوشه‌ی uploads را در آن جهت ذخیره سازی فایل‌های دریافتی، تعیین کرده‌ایم.
چون برنامه‌های ASP.NET Core قابلیت اجرای بر روی لینوکس را نیز دارند، تا حد امکان باید از Path.Combine جهت جمع زدن اجزای مختلف یک میسر، استفاده کرد. از این جهت که در لینوکس، جداکننده‌ی اجزای مسیرها، / است بجای \ در ویندوز و متد Path.Combine به صورت خودکار این مسایل را لحاظ خواهد کرد.
در آخر با استفاده از متد file.CopyToAsync کار نوشتن غیرهمزمان محتوای فایل دریافتی در یک FileStream انجام می‌شود؛ به همین جهت در امضای متد فوق، <async Task<IActionResult را نیز ملاحظه می‌کنید.


پشتیبانی کامل از Model Binding آپلود فایل‌ها در ASP.NET Core

در ASP.NET MVC 5.x اگر ویژگی Required را بر روی یک خاصیت از نوع HttpPostedFileBase قرار دهید ... کار نمی‌کند و در سمت کلاینت تاثیری را به همراه نخواهد داشت؛ مگر اینکه تنظیمات سمت کلاینت آن‌را به صورت دستی انجام دهیم. این مشکلات در ASP.NET Core، کاملا برطرف شده‌اند:
public class UserViewModel
{
    [Required(ErrorMessage = "Please select a file.")]
    [DataType(DataType.Upload)]
    public IFormFile Photo { get; set; }
}
در اینجا یک خاصیت از نوع IFormFile، با دو ویژگی Required و DataType خاص آن در یک ViewModel تعریف شده‌اند. فرم معادل آن در ASP.NET Core به صورت ذیل خواهد بود:
@model UserViewModel
 
<form method="post"
      asp-action="UploadPhoto"
      asp-controller="TestFileUpload"
      enctype="multipart/form-data">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
 
    <input asp-for="Photo" />
    <span asp-validation-for="Photo" class="text-danger"></span>
    <input type="submit" value="Upload"/>
</form>
در اینجا ابتدا نوع مدل View تعیین شده‌است و سپس با استفاده از Tag Helpers، صرفا یک input را به خاصیت Photo مدل View جاری متصل کرده‌ایم. همین اتصال سبب فعال سازی مباحث اعتبارسنجی سمت سرور و کاربر نیز می‌شود.
اینبار جهت فعال سازی و استفاده‌ی از قابلیت‌های Model Binding می‌توان از ModelState نیز بهره گرفت:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UploadPhoto(UserViewModel userViewModel)
{
    if (ModelState.IsValid)
    {
        var formFile = userViewModel.Photo;
        if (formFile == null || formFile.Length == 0)
        {
            ModelState.AddModelError("", "Uploaded file is empty or null.");
            return View(viewName: "Index");
        }
 
        var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");
        if (!Directory.Exists(uploadsRootFolder))
        {
            Directory.CreateDirectory(uploadsRootFolder);
        }
 
        var filePath = Path.Combine(uploadsRootFolder, formFile.FileName);
        using (var fileStream = new FileStream(filePath, FileMode.Create))
        {
            await formFile.CopyToAsync(fileStream).ConfigureAwait(false);
        }
 
        RedirectToAction("Index");
    }
    return View(viewName: "Index");
}
اگر ModelState معتبر باشد، کار ذخیره سازی تک فایل رسیده را انجام می‌دهیم. سایر نکات این متد، با اکشن متد Index که پیشتر بررسی شد، یکی هستند.


بررسی پسوند فایل‌های رسیده‌ی به سرور

ASP.NET Core دارای ویژگی است به نام FileExtensions که ... هیچ ارتباطی به خاصیت‌هایی از نوع IFormFile ندارد:
 [FileExtensions(Extensions = ".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")]
ویژگی FileExtensions صرفا جهت درج بر روی خواصی از نوع string طراحی شده‌است. بنابراین قرار دادن این ویژگی بر روی خاصیت‌هایی از نوع IFormFile، سبب فعال سازی اعتبارسنجی سمت سرور پسوندهای فایل‌های رسیده، نخواهد شد.
در ادامه جهت بررسی پسوندهای فایل‌های رسیده، می‌توان یک ویژگی اعتبارسنجی سمت سرور جدید را طراحی کرد:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class UploadFileExtensionsAttribute : ValidationAttribute
{
    private readonly IList<string> _allowedExtensions;
    public UploadFileExtensionsAttribute(string fileExtensions)
    {
        _allowedExtensions = fileExtensions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
    }
 
    public override bool IsValid(object value)
    {
        var file = value as IFormFile;
        if (file != null)
        {
            return isValidFile(file);
        }
 
        var files = value as IList<IFormFile>;
        if (files == null)
        {
            return false;
        }
 
        foreach (var postedFile in files)
        {
            if (!isValidFile(postedFile)) return false;
        }
 
        return true;
    }
 
    private bool isValidFile(IFormFile file)
    {
        if (file == null || file.Length == 0)
        {
            return false;
        }
 
        var fileExtension = Path.GetExtension(file.FileName);
        return !string.IsNullOrWhiteSpace(fileExtension) &&
               _allowedExtensions.Any(ext => fileExtension.Equals(ext, StringComparison.OrdinalIgnoreCase));
    }
}
در اینجا با ارث بری از کلاس پایه ValidationAttribute و بازنویسی متد IsValid آن، کار اعتبارسنجی پسوند فایل‌ها و یا فایل رسیده را انجام داده‌ایم. این ویژگی جدید اگر بر روی خاصیتی از نوع IFormFile قرار بگیرد، پارامتر object value متد IsValid آن حاوی اطلاعات فایل و یا فایل‌های رسیده، خواهد بود. بر این اساس می‌توان تصمیم گیری کرد که آیا پسوند این فایل، مجاز است یا خیر.
public class UserViewModel
{
    [Required(ErrorMessage = "Please select a file.")]
    //`FileExtensions` needs to be applied to a string property. It doesn't work on IFormFile properties, and definitely not on IEnumerable<IFormFile> properties.
    //[FileExtensions(Extensions = ".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")]
    [UploadFileExtensions(".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")]
    [DataType(DataType.Upload)]
    public IFormFile Photo { get; set; }
}
در اینجا روش استفاده‌ی از این ویژگی اعتبارسنجی جدید را نیز با تکمیل ViewModel کاربر، مشاهده می‌کنید. پس از آن تنها بررسی if (ModelState.IsValid) در یک اکشن متد، نتیجه‌ی دریافتی از اعتبارسنج جدید UploadFileExtensions را در اختیار ما قرار می‌دهد و بر این اساس می‌توان تصمیم‌گیری کرد که آیا باید فایل رسیده را ذخیره کرد یا خیر.
  • #
    ‫۷ سال و ۹ ماه قبل، یکشنبه ۲۱ آذر ۱۳۹۵، ساعت ۲۱:۳۷
    اگر در Model پروپرتی Photo از جنس string باشد و در ViewModel این پروپرتی رو برای استفاده از امکانات validation و غیره به IFormFile تغییر بدیم. برای ارسال آدرس فایل به مدل که از طریق viewmodel تغذیه میشه، آیا نیاز به تعریف یک پروپرتی دیگر از جنس string  در viewmodel داریم؟ یا اینکه روش دیگری برای این کار وجود دارد؟
     public class Model
        {
            public string Photo { get; set; }        
        }

     public class viewModel
        {
            public IFormFile Photo { get; set; }
        }
    • #
      ‫۷ سال و ۹ ماه قبل، یکشنبه ۲۱ آذر ۱۳۹۵، ساعت ۲۱:۴۴
      IFormFile دارای خاصیتی رشته‌ای به نام FileName است.
  • #
    ‫۷ سال و ۱ ماه قبل، چهارشنبه ۱ شهریور ۱۳۹۶، ساعت ۱۶:۲۹
    با سلام؛ آیا این روش آپلود را با Unobtrusive Ajax  در Asp.net Core نیز می‌شود پیاده سازی کرد؟
  • #
    ‫۶ سال و ۷ ماه قبل، سه‌شنبه ۱ اسفند ۱۳۹۶، ساعت ۲۲:۴۱
    اگر بخواهیم یک رشته string که حاوی آدرس یک عکس می‌باشد را آپلود کنیم باید چکار کنیم ؟ چگونه می‌توانیم آن را به FileName انتساب دهیم درصورتی که FileName خاصیت readonly دارد!
    • #
      ‫۶ سال و ۷ ماه قبل، سه‌شنبه ۱ اسفند ۱۳۹۶، ساعت ۲۲:۵۲
      از HttpClient برای دریافت آن آدرس مشخص، در سمت سرور استفاده کنید.
  • #
    ‫۶ سال و ۵ ماه قبل، چهارشنبه ۲۹ فروردین ۱۳۹۷، ساعت ۱۹:۰۰
    خلاصه نکات این مطلب در برنامه‌های ASP.NET Core

    ابتدا بسته‌ی نیوگت DNTCommon.Web.Core را نصب کنید:
    PM> Install-Package DNTCommon.Web.Core
    سپس مثالی از UploadFileExtensions آن‌را در اینجا می‌توانید مشاهده کنید. همچنین قسمت ذخیره سازی فایل آن نیز تبدیل به یک سرویس به نام IUploadFileService شده‌است. 
    • #
      ‫۴ سال و ۱۰ ماه قبل، پنجشنبه ۲۵ مهر ۱۳۹۸، ساعت ۱۱:۲۹
       با سلام؛ شما در کلاس UploadFileService از این بسته یک متد با امضا زیر تعریف کردید:
       Task < bool > SavePostedFileAsync ( IFormFile formFile , string destinationDirectoryName , bool allowOverwrite );
      متد فوق تصاویر را با نامی خاص (که توسط متد  getUniqueFilePath ( IFormFile formFile , string uploadsRootFolder )  )مشخص میشه ذخیره می‌کنه و مقدار True  رو بر می‌گردنه. مشکلی که وجود دارد عدم پاس دادن نام فایل برای ذخیره در دیتابیس و نمایش‌های بعدی هست.   
      • #
        ‫۴ سال و ۱۰ ماه قبل، پنجشنبه ۲۵ مهر ۱۳۹۸، ساعت ۱۱:۳۵
        لطفا از issue tracker یک پروژه برای بحث در مورد آن استفاده کنید.
  • #
    ‫۶ سال و ۳ ماه قبل، چهارشنبه ۳۰ خرداد ۱۳۹۷، ساعت ۰۱:۰۴
    یک نکته‌ی تکمیلی: روش تعیین حداکثر اندازه‌ی فایل قابل آپلود در برنامه‌های ASP.NET Core
    الف) اگر برنامه توسط IIS هاست شده‌است
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
     <!-- To customize the asp.net core module uncomment and edit the following section. 
     For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
     <system.webServer>
      <handlers>
      <remove name="aspNetCore"/>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
      </handlers>
      <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
      <security>
       <requestFiltering>
        <!-- This will handle requests up to 50MB -->
        <requestLimits maxAllowedContentLength="52428800" />
       </requestFiltering>
      </security>
      </system.webServer>
    </configuration>
    در اینجا (در فایل web.config برنامه) مقدار خاصیت maxAllowedContentLength است که تعیین کننده‌ی حداکثر اندازه‌ی فایل قابل آپلود است. به علاوه مطمئن شوید که فایل web.config شما حتما publish شده.
    همچنین requestTimeout را نیز به صورت زیر می‌توان مقدار دهی کرد:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.webServer>
        <aspNetCore requestTimeout="00:20:00"  .... />
      </system.webServer>
    </configuration>
    به همراه این تنظیمات:
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<IISServerOptions>(options =>
                {
                    options.MaxRequestBodySize = int.MaxValue;
                });
                services.Configure<FormOptions>(options =>
                {
                    options.ValueLengthLimit = int.MaxValue;
                    options.MultipartBodyLengthLimit = long.MaxValue; // <-- ! long.MaxValue
                    options.MultipartBoundaryLengthLimit = int.MaxValue;
                    options.MultipartHeadersCountLimit = int.MaxValue;
                    options.MultipartHeadersLengthLimit = int.MaxValue;
                });
     
    ب) اگر برنامه در لینوکس و بر اساس وب سرور Kestrel هاست شده‌است
    روش اول: استفاده از ویژگی RequestSizeLimit که از نگارش ASP.NET Core 2.0 به بعد قابل استفاده‌است و صرفا به قسمتی از برنامه اعمال می‌شود:
    [HttpPost]
    [RequestSizeLimit(40000000)]
    public async Task<IActionResult> UploadFiles(IFormFile file)
    روش دوم: تنظیم سراسری آن برای کل برنامه:
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder
                            .UseStartup<Startup>()
                            .ConfigureKestrel(kestrelServerOptions =>
                            {
                                kestrelServerOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
                                kestrelServerOptions.Limits.MaxRequestBodySize = 52428800; //50MB
                            });
                    });
    بدیهی است تنظیم این دو روش در حالت استفاده‌ی از IIS تاثیری نخواهند داشت.
  • #
    ‫۶ سال و ۱ ماه قبل، دوشنبه ۱۵ مرداد ۱۳۹۷، ساعت ۱۹:۵۴
    با سلام؛ اگر ما بخواهیم به طور مثال کاربری را ثبت نام کنیم  و این کاربر علاوه بر داشتن اطلاعات پایه شامل عکس نیز می‌باشد و این ثبت کاربر را از طریق پروژه غیر وبی با استفاده از   Httpclient  انجام دهیم، فیلد عکس کاربر را از چه نوعی تعریف کنیم. نوع فیلد عکس کاربر که در متد اکشن سرور تعریف کرده ایم از نوع IFormFile  است و بعد از آن از تابع اکشنی که در بالا تعریف کرده‌اید اپدیت را انجام می‌دهیم.
    • #
      ‫۶ سال و ۱ ماه قبل، دوشنبه ۱۵ مرداد ۱۳۹۷، ساعت ۲۰:۲۷
      هیچ تفاوتی از لحاظ جزئیات پروتکل HTTP در حالت ارسال اطلاعات به سرور در این حالت وجود ندارد. کلاینت وبی باشد یا غیر وبی مهم نیست. پس از ذخیره‌ی فایل عکس بر روی سرور، نوع فیلد آن می‌تواند رشته‌ای باشد و نام عکس را در آن ثبت کنید. یک مثال
      • #
        ‫۲ سال و ۲ ماه قبل، شنبه ۱۴ خرداد ۱۴۰۱، ساعت ۲۲:۱۵
        اگرکلاینتها ویندوزی نباشند چطور؟مثلا برای api ما که با دات نت  و با استفاده از IFormFile  فایل‌های ارسالی رو ذخیره میکنیم، یک کلاینت اندرویدی میتونه فایل ارسال کنه؟ یابایدازاون کلاینت خاص با فرمت base64فقط فایل‌ها رو دریافت کرد؟
        • #
          ‫۲ سال و ۲ ماه قبل، شنبه ۱۴ خرداد ۱۴۰۱، ساعت ۲۲:۳۱
          این مباحث ویندوزی و غیر ویندوزی نیستند. استاندارد عمومی HTTP هستند. همینکه این استاندارد رعایت شود، برای یک برنامه‌ی سمت سرور ASP.NET Core، کافی است و مهم نیست که کلاینت آن (برنامه‌ی سمت کلاینتی که فایل را ارسال می‌کند) یک مرورگر باشد (بر روی هر سیستم عاملی) و یا یک برنامه‌ی دست‌نویس ثالث.
        • #
          ‫۲ سال و ۲ ماه قبل، سه‌شنبه ۱۷ خرداد ۱۴۰۱، ساعت ۰۳:۱۳
          اکثرا از base64 استفاده میکنم. برای برنامه نویس‌های موبایل و فرانت قابل قبول‌تر است :)
          نمونه کد تبدیل base64 به iformfile:
          public static async Task<ResponsePayload<string>> SaveBase64(this string imgBase64, string filePath, FileSizeType fileSizeType)
              {
                  if (string.IsNullOrWhiteSpace(imgBase64))
                      return new ResponsePayload<string>(false, "فایل را وارد کنید.", null);
          
                  string data;
                  if (imgBase64.StartsWith("data:"))
                  {
                      string[] base64Arr = imgBase64.Split(',');
                      if (base64Arr.Length == 0)
                          return new ResponsePayload<string>(false, "فایل را وارد کنید.", null);
                      data = base64Arr[1];
                  }
                  else
                  {
                      data = imgBase64;
                  }
          
                  byte[] bytes = Convert.FromBase64String(data);
                  var fileType = GetFileExtension(imgBase64);
                  if (string.IsNullOrEmpty(fileType))
                      return new ResponsePayload<string>(false, "فایل وارد شده صحیح نمی‌باشد.", null);
          
                  using var stream = new MemoryStream(bytes);
                  IFormFile file = new FormFile(stream, 0, bytes.Length, filePath, "." + fileType);
          
                  string fileName = Guid.NewGuid().ToString().Replace("-", "");
                  return await UploadFile(file, filePath + fileName, fileSizeType);
              }
          private static string GetFileExtension(string base64String)
              {
                  string data;
          
                  if (base64String.StartsWith("data:"))
                  {
                      string[] base64Arr = base64String.Split(',');
                      if (base64Arr.Length == 0)
                          return "";
                      data = base64Arr[1];
                  }
                  else
                  {
                      data = base64String;
                  }
                  return data.Substring(0, 5).ToUpper() switch
                  {
                      "IVBOR" => "png",
                      "/9J/4" => "jpg",
                      "AAAAF" => "mp4",
                      "JVBER" => "pdf",
                      "AAABA" => "ico",
                      "UMFYI" => "rar",
                      "E1XYD" => "rtf",
                      "U1PKC" => "txt",
                      "MQOWM" => "srt",
                      "77U/M" => "srt",
                      "UESDB" => "",
                      "" => "docx",
                      _ => string.Empty,
                  };
              }
          }
          
          public class FileSizeType
          {
              public int Size { get; set; }
          }

          • #
            ‫۲ سال و ۲ ماه قبل، سه‌شنبه ۱۷ خرداد ۱۴۰۱، ساعت ۰۴:۱۵
            دریک فرم blazor wasm از کدزیراستفاده کردیم.که فایلهای انتخابی کاربر رو تبدیل به آرایه ای ازجنس بایت در نظر میگیریم.ودر سمت سرور نیز همین آرایه رو پردازش و ذخیره میکنیم و ازسایرکلاینها هم فایلها رو درهمین قالب دریافت خواهیم کرد یعنی آرایه ای از جنس بایت.
             private async Task UploadFiles(InputFileChangeEventArgs e)
                {
                    foreach (var file in e.GetMultipleFiles())
                    {
                        var fileData = new FileToBeSaveVM();
                        var buffers = new byte[file.Size];
                        await file.OpenReadStream().ReadAsync(buffers);
            
                        fileData.FileName = file.Name;
                        fileData.FileSize = file.Size;
                        fileData.FileType = file.ContentType;
                        fileData.Extension = Path.GetExtension(file.Name);
                        fileData.ImageBytes = buffers;
                        lstFileToBeSaves.fileToBeSaves.Add(fileData);
                    }
            
                }
            public class FileToBeSaveVM
            {
                public byte[] ImageBytes { get; set; }
                public string FileName { get; set; }
                public string FileType { get; set; }
                public string Extension { get; set; }
                public long FileSize { get; set; }
            }
            کدهای سمت سرور:
            public async Task UploadFileAsync(List<FileToBeSaveVM> files, string uploadFolder)
                {
                    var folderDirectory=createUploadDir(uploadFolder);
                    foreach (var file in files)
                    {            
                        string fileExtenstion = Path.GetExtension(file.FileName);
                        string fileuniqName =$"{Guid.NewGuid()}{fileExtenstion}";
                        string fileName = Path.Combine(folderDirectory, fileuniqName);
                        string url=$"{uploadFolder}/{fileuniqName}";
                        using (var fileStream = File.Create(fileName))
                        {
                            await fileStream.WriteAsync(file.ImageBytes);
                       }
                  }

  • #
    ‫۵ سال و ۸ ماه قبل، دوشنبه ۲۴ دی ۱۳۹۷، ساعت ۱۴:۰۸
    چگونه می‌توان در Asp.net Core به یک پوشه که در درایو دیگر هست ، در پروژه به آن دسترسی داد و فایل‌های آپلود شده در آن ذخیره کرد؟
    • #
      ‫۵ سال و ۸ ماه قبل، دوشنبه ۲۴ دی ۱۳۹۷، ساعت ۱۸:۵۸
      برنامه‌های هاست شده‌ی در IIS، از لحاظ خواندن و نوشتن فایل‌ها، تفاوتی با سایر برنامه‌های ویندوزی ندارند. هر برنامه‌ی ویندوزی بر اساس سطوح دسترسی کاربری که تحت مجوز آن اجرا می‌شود، یکسری از دسترسی‌ها را پیدا می‌کند، یا خیر. برای مثال به صورت پیش‌فرض کاربری که برنامه‌های ASP.NET، بر اساس آن اجرا می‌شوند، همان کاربر Application pool آن‌ها است و این کاربر هیچ نوع دسترسی نوشتنی را در هیچکدام از پوشه‌های سیستم، ندارد. به همین جهت حتی اگر سعی کنید در پوشه‌ی خود برنامه هم فایلی را آپلود کنید، با خطای access is denied متوقف خواهید شد. همان کاری را که برای دادن دسترسی نوشتن، به کاربر Application pool برنامه‌ی خود جهت آپلود فایل‌های فعلی انجام داده‌اید، باید برای هر پوشه‌ی دیگری که مدنظر شما است نیز انجام دهید و از این لحاظ تفاوتی نمی‌کند (مهم نیست که در این درایو باشد یا در آن درایو؛ مهم دسترسی نوشتن است):
      Right click on the folder -> Properties -> Security tab -> Click at Edit button ->
      Enter `IIS AppPool\DefaultAppPool` user (IIS AppPool\<app_pool_name>) -> Click at Check names -> OK ->
      Then give it `write` or other permissions.
  • #
    ‫۵ سال و ۷ ماه قبل، چهارشنبه ۳ بهمن ۱۳۹۷، ساعت ۱۴:۲۲
    سلام.من از روش بالا استفاده کردم اما این اتربیوت بر روی modelstate برای من تاثیر گذار نیست . در واقع چه متد isvalidfile مقدار true را برگرداند و چه مقدار false.مقدار modelstate همواره true خواهد بود .برای بقیه موارد modelstate بدرستی عمل میکند و فقط این اتربیوت را جوابگو نیست.ممنون میشم راهنمایی کنید که کجا رو اشتباه رفتم ؟
    • #
      ‫۵ سال و ۷ ماه قبل، چهارشنبه ۳ بهمن ۱۳۹۷، ساعت ۱۴:۳۱
      این روش در این مثال عمومی قابل دسترسی و دیباگ (^ و ^)، استفاده شده و کار می‌کند. برای آزمایش آن، فایلی غیر از .png,.jpg,.jpeg,.gif را آپلود کنید.
      • #
        ‫۵ سال و ۷ ماه قبل، پنجشنبه ۴ بهمن ۱۳۹۷، ساعت ۰۲:۵۸
        ممنون . 
        چرا برای Iformfile نمیتونیم از خاصیت remote استفاده کنیم ؟در واقع remote جواب نمیده؟
          • #
            ‫۴ سال و ۱۱ ماه قبل، یکشنبه ۱۴ مهر ۱۳۹۸، ساعت ۱۶:۳۴
            من از jquery.bootstrap.modal.form.js  شما استفاده میکنم. به چه صورتی میشه فایل رو ارسال کرد؟ پروژه .net core هست و اینکه پیش نیازها رو هم استفاده کردم. Unobtrusive Ajax و jquey
            • #
              ‫۴ سال و ۱۱ ماه قبل، یکشنبه ۱۴ مهر ۱۳۹۸، ساعت ۱۶:۴۰
              - فقط Unobtrusive Ajax را بر روی فرم خود فعال کنید. در نسخه‌ی اخیر افزونه jquery-ajax-unobtrusive، ارسال فایل با استفاده از FormData نیز به صورت توکار پشتیبانی می‌شود و نیاز به تنظیمی خاص، یا کد نویسی اضافه‌تری ندارد.
              - برای افزونه‌های دیگر هم از همان قطعه کد مایکروسافت برای تکمیل آن‌ها ایده بگیرید.
              • #
                ‫۴ سال و ۱۱ ماه قبل، یکشنبه ۱۴ مهر ۱۳۹۸، ساعت ۱۶:۵۸
                فعال است
                "node_modules/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.min.js",
                اما وقتی از مودال فوق استفاده میکنم کار نمیکند
                • #
                  ‫۴ سال و ۱۱ ماه قبل، یکشنبه ۱۴ مهر ۱۳۹۸، ساعت ۱۷:۰۰
                  بله. آن افزونه از روش unobtrusive-ajax استفاده نمی‌کند. اما خودتان می‌توانید از کدهای مایکروسافت برای تکمیل آن استفاده کنید و از آن‌ها ایده بگیرید.
  • #
    ‫۵ سال و ۴ ماه قبل، پنجشنبه ۲۶ اردیبهشت ۱۳۹۸، ساعت ۱۶:۳۵
    چند نکته‌ی تکمیلی
    چگونه فایل دریافتی را تبدیل به آرایه‌ای از بایت‌ها کنیم؟
    public async Task<IActionResult> FileUpload(IFormFile file)
            {
                if (file == null || file.Length == 0)
                {
                    return BadRequest();
                }
    
                using (var memoryStream = new MemoryStream())
                {
                    await file.CopyToAsync(memoryStream);
                    var fileBytes = memoryStream.ToArray();
                    // ... save it
                }
            }

    چگونه فایل تصویر دریافتی را تبدیل به یک شیء تصویر کنیم؟
    public async Task<IActionResult> FileUpload(IFormFile file)
            {
                if (file == null || file.Length == 0)
                {
                    return BadRequest();
                }
    
                using (var memoryStream = new MemoryStream())
                {
                    await file.CopyToAsync(memoryStream);
                    using (var img = Image.FromStream(memoryStream))
                    {
                      // TODO: ResizeImage(img, 100, 100);
                    }
                }
            }
  • #
    ‫۴ سال و ۶ ماه قبل، جمعه ۱۶ اسفند ۱۳۹۸، ساعت ۲۰:۳۶
    با سلام؛ چطوری امکان آپلود فایل از مسیر لوکال کاربر نباشد و از مسیر share شبکه باشد. زمان انتخاب فایل برای آپلود از مسیر شبکه که share هست رو باز کنند. فایل‌های اون مسیر را انتخاب و آپلود کنند. آیا از نظر امنیتی امکان پذیر می‌باشد؟
    • #
      ‫۴ سال و ۶ ماه قبل، جمعه ۱۶ اسفند ۱۳۹۸، ساعت ۲۳:۳۲
      بله. ابتدا باید map network drive و یا add a network location صورت بگیرد (نتیجه‌ی هر دو یکی است):

      بعد از اینکار، مسیر اشتراکی شبکه‌ی داخلی (که دسترسی کاربر وارد شده‌ی به سیستم و شبکه، پیشتر به آن تنظیم شده)، به صورت یک درایو جدید، کنار سایر درایوهای قابل انتخاب توسط open file dialog استاندارد، ظاهر شده و قابل انتخاب می‌شود.

      • #
        ‫۴ سال و ۶ ماه قبل، شنبه ۱۷ اسفند ۱۳۹۸، ساعت ۰۱:۱۲
        سپاس؛ آیا تنظیمی هست open file dialog فقط مسیر اشتراکی شبکه‌ی داخلی را  نشان دهد و سایر درایوها رو نشان ندهد.
        • #
          ‫۴ سال و ۶ ماه قبل، شنبه ۱۷ اسفند ۱۳۹۸، ساعت ۰۱:۲۶
          در مرورگرها و استانداردهای وب، خیر.
  • #
    ‫۴ سال و ۶ ماه قبل، سه‌شنبه ۲۰ اسفند ۱۳۹۸، ساعت ۲۳:۴۷
    سلام، با توجه به اینکه پروژه که با React نوشته شده در آدرس http://localhost:3000 اجرا میشود و پروژه Api که با Asp.net core ایجاد شده است در آدرس http://localhost:5001 اجرا میشود، در هنگام آپلود فایل دستور : 
    Path.Combine(_environment.WebRootPath, "uploads");
    آیا به آدرس با پورت 5001 اشاره میکند؟ اگر بله است باید چیکار کنیم که در محل برنامه پروژه React آپلود شود، و  نهایتا روش درست چیست؟ آیا اینی که بنده گفتم اصلا روش درستی است یا خیر؟
    با تشکر 
  • #
    ‫۴ سال و ۴ ماه قبل، شنبه ۱۳ اردیبهشت ۱۳۹۹، ساعت ۰۱:۲۵
    با فرض استفاده از مرورگرهای مدرن، چگونه می‌توان فایلهای یک یا چند پوشه (و زیرپوشه‌ها در صورت وجود) را یکجا آپلود کرد. در واقع بجای select file داشته باشیم select folder ؟
    • #
      ‫۴ سال و ۴ ماه قبل، شنبه ۱۳ اردیبهشت ۱۳۹۹، ساعت ۰۵:۵۵
      مرورگرهای جدید با استفاده از ویژگی webkitdirectory، امکان انتخاب یک پوشه و تمام زیر پوشه‌های آن‌را دارند:
      <form method="post" asp-action="UploadFiles" asp-controller="Home" enctype="multipart/form-data">
          <input type="file" name="files" webkitdirectory />
          <input type="submit" value="Upload" />
      </form>
      در این حالت کدهای سمت سرور آن به صورت زیر تغییر می‌کند:
      using System.Collections.Generic;
      using System.IO;
      using System.Threading.Tasks;
      using Microsoft.AspNetCore.Hosting;
      using Microsoft.AspNetCore.Http;
      using Microsoft.AspNetCore.Mvc;
      
      namespace UploadFolderASPNETCore.Controllers
      {
          public class HomeController : Controller
          {
              private readonly IWebHostEnvironment _environment;
              private const int MaxBufferSize = 0x10000;
      
              public HomeController(IWebHostEnvironment environment)
              {
                  _environment = environment;
              }
      
              public IActionResult Index()
              {
                  return View();
              }
      
              [HttpPost("[action]")]
              public async Task<IActionResult> UploadFiles(IList<IFormFile> files)
              {
                  var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");
                  CreateDir(uploadsRootFolder);
      
                  foreach (var file in files)
                  {
                      var dirPath = Path.GetDirectoryName(file.FileName);
                      CreateDir(Path.Combine(uploadsRootFolder, dirPath));
      
                      var filePath = Path.Combine(uploadsRootFolder, file.FileName);
                      using (var fileStream = new FileStream(filePath, FileMode.Create,
                                                              FileAccess.Write,
                                                              FileShare.None,
                                                              MaxBufferSize,
                                                              useAsync: true
                                                              ))
                      {
                          await file.CopyToAsync(fileStream);
                      }
                  }
      
                  return RedirectToAction("Index");
              }
      
              private void CreateDir(string path)
              {
                  if (!Directory.Exists(path))
                  {
                      Directory.CreateDirectory(path);
                  }
              }
          }
      }
      • #
        ‫۳ سال و ۴ ماه قبل، پنجشنبه ۱۶ اردیبهشت ۱۴۰۰، ساعت ۱۸:۲۶
        سلام؛ من هر IFormFile رو در یک کلاس، با یک سری مشخصه‌ی دیگه در یک لیست ذخیره میکنم. چطوری میشه کلاس خودمو در سشن قرار داد؟
        • #
          ‫۳ سال و ۴ ماه قبل، پنجشنبه ۱۶ اردیبهشت ۱۴۰۰، ساعت ۱۸:۴۸
          نمی‌توانید. IFormFile که یک اینترفیس است، قابلیت Serialization ندارد. ضمن اینکه نگهداری فایل‌های حجیم در حافظه‌ی سشن، کار اشتباهی است. بهتر است بر اساس نکات مطلب جاری، آن‌ها را ابتدا ذخیره کنید و فقط مسیرهای نهایی را نگهداری کنید.