در آموزش برنامه نویسی وب معمولا صحبت زیادی از ارسال و دریافت فایل نمی شود و معمولا آموزش ارسال داده ها بصورت پارامتر یا درقالب json و ... صورت می گیرد. اما در پروژه های واقعی خیلی از اوقات نیاز است که کاربر اطلاعاتی را در قالب یک فایل آماده به سرور ارسال کند. حتی ممکن است سرور آن فایل را مجددا به سرور دیگری مانند سرور فایل ها ارسال کند. در این مقاله قصد داریم نحوه دریافت فایل از کلاینت و نیز ارسال فایل از سرور را در asp.net core آموزش دهیم.
ارسال فایل از کلاینت به سرور
برای دریافت فایل از کلاینت از IFormFile استفاده می شود.
When the client posts a file in a multipart/form-data request, it’s loaded into an IFormFile object. This contains file information (such as the file name) and exposes the file content as a stream. This allows you to save the file or process it however you want to.
You can access the IFormFile object through Request.Form.Files:
[Route("[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Post()
{
IFormFile file = Request.Form.Files.FirstOrDefault();
//process file content
return Ok($"Received file {file.FileName} with size in bytes {file.Length}");
}
}
Or you can add an IFormFile parameter (or add it as a model property), and it’ll map the file form data to the parameter by name:
[Route("[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{
//process file content
return Ok($"Received file {file.FileName} with size in bytes {file.Length}");
}
}
Note: Make sure the IFormFile parameter name matches the file’s name attribute in the form data, otherwise it won’t map and will be null.
Saving to disk
IFormFile exposes the file content as a stream. You can save this to disk by creating a FileStream and copying the file stream to it.
Here’s an example of saving the file to disk:
using System.IO;
[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{
if (file.Length <= 0)
return BadRequest("Empty file");
//Strip out any path specifiers (ex: /../)
var originalFileName = Path.GetFileName(file.FileName);
//Create a unique file path
var uniqueFileName = Path.GetRandomFileName();
var uniqueFilePath = Path.Combine(@"C:\temp\", uniqueFileName);
//Save the file to disk
using (var stream = System.IO.File.Create(uniqueFilePath))
{
await file.CopyToAsync(stream);
}
return Ok($"Saved file {originalFileName} with size {file.Length / 1024m:#.00} KB using unique name {uniqueFileName}");
}
Note: For simplicity, this hardcodes the file upload directory (C:\temp\). Realistically, you’d want to put this setting with the rest of your config data.
When I send a request to this, it saves the file to a dedicated file upload directory and uses a unique filename. It returns the response:
Saved file class-hierarchy-diagram.png with size 6.88 KB using unique name hseadpgk.xgf
IFormFile as a model property
In many cases, you’ll want to post the file with associated data as part of a model. You can add the IFormFile as a model property.
public class Document
{
public string Title { get; set; }
public string Version { get; set; }
public IFormFile File { get; set; }
}
Then include the model as a parameter and apply the [FromForm] attribute:
[HttpPost]
public async Task<IActionResult> Post([FromForm]Document document)
{
//process file
return Ok($"Processed document {document.Title} v{document.Version} - {document.File.FileName}");
}
It’ll load the file data into the IFormFile property and you can process / save it however you want.
Note: Include the [FromForm] attribute when mapping form data to a model, otherwise you’ll get a 415- Media Not Supported response.
File size limits
File / request size limits are different per web server. In Kestrel-hosted web apps, the main default limits are:
- Request size limit of 30 MB.
- Multipart form section size limit of 128 MB.
You can change the limits for all requests or per action. I recommend changing the limits per action, because you’ll probably want drastically different limits for actions that deal with file uploading compared with other actions.
Here’s an example of increasing the request size limit to 60 MB:
[HttpPost]
[RequestSizeLimit(bytes: 60_000_000)]
public async Task<IActionResult> Post(IFormFile file)
{
//process file
return Ok();
}
Files are sent as form data, so you also have to take the form size limits into account. It’ll use the smallest applicable limit to determine if the request has exceeded limits. You can change the form size limits with the [RequestFormLimits] attribute.
Receiving multiple files
There are two ways to receive multiple files:
- Add an IFormFile parameter for each file.
- Use IEnumerable<IFormFile> to receive multiple files into a single parameter.
The first option is better when you know exactly how many files you require the client to pass in. The second option is better when the client can send any number of files.
Here’s an example of receiving multiple files:
[HttpPost]
public async Task<IActionResult> Post(IEnumerable<IFormFile> files)
{
foreach(var file in files)
{
//process each file
}
return Ok();
}
When using this approach, the client will need to use the same name for each file they add to the form data.
ارسال فایل از سرور به کلاینت
برای ارسال فایل به کلاینت یا از یک سرور به سرور دیگر از کلاس FileResult و مشتقات آن استفاده می شود.
در asp.net core چهار نوع خروجی فایل میتوانیم داشته باشیم:
- FileResult
- FileContentResult
- FileStreamResult
- VirtualFileResult
- PhysicalFileResult
که چهارتای آنها از کلاس FileResult ارث می برند و در واقع FileResult پدر آنهاست. در کنترلر می توان شی جداگانه ای از هریک از پنج نوع بالا ایجاد کرد و به عنوان خروجی ارسال کرد چرا که تمام این 5 نوع خود از کلاس ActionResult ارث برده اند و در واقع هر کدام از آنها یک ActionResult می باشد.
همچنین کلاس ControllerBase دارای تابعی با نام File می باشد که بسته به ورودی های مختلف، یک شی از یکی از انواع بالا را تولید می کند و می توان از این تابع نیز برای ارسال فایل استفاده کرد. از آنجایی که کلاس Controller هم از کلاس ControllerBase ارث برده است بنابراین در کلاس Controller هم می توان از تابع File استفاده کرد.
FileResult
FileResult is the parent of all file-related action results. It is a base class that is used to send binary file content to the response. It represents an ActionResult that when executed will write a file as the response.
public FileResult DownloadFile()
{
return File("/Files/File Result.pdf", "text/plain", "File Result.pdf");
}
FileContentResult
اگر یک آرایه byte داریم و می خواهیم آن را بصورت فایل برگردانیم از FileContentResult استفاده می کنیم.
FileContentResult is an ActionResult that when executed will write a binary file to the response.
public FileContentResult DownloadContent()
{
var myfile = System.IO.File.ReadAllBytes("wwwroot/Files/FileContentResult.pdf");
return new FileContentResult(myfile, "application/pdf");
}
FileStreamResult
اگر یک Stream داریم و می خواهیم آن را بصورت فایل برگردانیم از FileStreamResult استفاده می کنیم.
FileStreamResult Sends binary content to the response by using a Stream instance when we want to return the file as a FileStream.
public FileStreamResult CreateFile()
{
var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))
{
FileDownloadName = "test.txt"
};
}
VirtualFileResult
A FileResult that on execution writes the file specified using a virtual path to the response using mechanisms provided by the host. You can use VirtualFileResult if you want to read a file from a virtual address and return it.
public VirtualFileResult VirtualFileResult()
{
return new VirtualFileResult("/Files/PhysicalFileResult.pdf", "application/pdf");
}
PhysicalFileResult
A FileResult on execution will write a file from disk to the response using mechanisms provided by the host.You can use PhysicalFileResult to read a file from a physical address and return it, as shown in PhysicalFileResult method.
public PhysicalFileResult PhysicalFileResult()
{
return new PhysicalFileResult(_environment.ContentRootPath + "/wwwroot/Files/PhysicalFileResult.pdf", "application/pdf");
}
لینک منابع:
https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/
https://makolyte.com/aspnetcore-receive-a-file-in-the-request/