{"id":29178,"date":"2019-01-23T00:00:00","date_gmt":"2019-01-22T23:00:00","guid":{"rendered":"https:\/\/blexin.com\/?p=29178"},"modified":"2021-01-13T09:40:48","modified_gmt":"2021-01-13T08:40:48","slug":"upload-e-download-di-file-con-angular-e-asp-net-core","status":"publish","type":"post","link":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/","title":{"rendered":"Upload e Download di file con Angular e Asp.Net Core"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" data-attachment-id=\"29179\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/attachment\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&amp;ssl=1\" data-orig-size=\"1024,608\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=300%2C178&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?resize=1024%2C608&#038;ssl=1\" alt=\"\" class=\"wp-image-29179\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b-980x582.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b-480x285.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Un&#8217;attivit\u00e0 spesso richiesta, nei progetti su cui lavoro, \u00e8 quella di gestire l\u2019upload e il download di file in Angular. Ci sono diversi modi per poter sviluppare queste funzionalit\u00e0:&nbsp;l&#8217;approccio migliore dipende spesso dalle API che si hanno a dispozione.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Supponiamo di avere delle API scritte in Asp.Net Core, nello specifico un controller con tre action :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Upload<\/strong>, per ricevere un file e salvarlo nella cartella .\/wwwroot\/upload;<\/li><li><strong>Download<\/strong>, per recuperare un file dalla cartella .\/wwwroot\/upload;<\/li><li><strong>Files<\/strong>, per ottenere la&nbsp;lista dei file presenti in .\/wwwroot\/upload;<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Una possibile implementazione del controller \u00e8 la seguente:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nnamespace BackEnd.Controllers\n{\n\u00a0\u00a0\u00a0&#x5B;Route(&quot;api&quot;)]\n\u00a0\u00a0\u00a0&#x5B;ApiController]\n\u00a0\u00a0\u00a0public class UploadDownloadController: ControllerBase\n\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0private IHostingEnvironment _hostingEnvironment;\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public UploadDownloadController(IHostingEnvironment environment) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0_hostingEnvironment = environment;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;HttpPost]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;Route(&quot;upload&quot;)]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public async Task&lt;iactionresult&gt; Upload(IFormFile file)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var uploads = Path.Combine(_hostingEnvironment.WebRootPath, &quot;uploads&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if(!Directory.Exists(uploads))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Directory.CreateDirectory(uploads);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (file.Length &gt; 0) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var filePath = Path.Combine(uploads, file.FileName);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0using (var fileStream = new FileStream(filePath, FileMode.Create)) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await file.CopyToAsync(fileStream);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return Ok();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;HttpGet]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;Route(&quot;download&quot;)]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public async Task&lt;iactionresult&gt; Download(&#x5B;FromQuery] string file) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var uploads = Path.Combine(_hostingEnvironment.WebRootPath, &quot;uploads&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var filePath = Path.Combine(uploads, file);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (!System.IO.File.Exists(filePath))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return NotFound();\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var memory = new MemoryStream();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0using (var stream = new FileStream(filePath, FileMode.Open))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await stream.CopyToAsync(memory);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0memory.Position = 0;\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return File(memory, GetContentType(filePath), file);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;HttpGet]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#x5B;Route(&quot;files&quot;)]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public IActionResult Files() {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var result =\u00a0 new List&lt;string&gt;();\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var uploads = Path.Combine(_hostingEnvironment.WebRootPath, &quot;uploads&quot;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if(Directory.Exists(uploads))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\u00a0 \n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var provider = _hostingEnvironment.ContentRootFileProvider;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0foreach (string fileName in Directory.GetFiles(uploads))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var fileInfo = provider.GetFileInfo(fileName);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0result.Add(fileInfo.Name);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return Ok(result);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} \n\u00a0\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0private string GetContentType(string path)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var provider = new FileExtensionContentTypeProvider();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0string contentType;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if(!provider.TryGetContentType(path, out contentType))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0contentType = &quot;application\/octet-stream&quot;;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return contentType;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0}\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Come potete vedere, niente di complesso.&nbsp; Interessante il&nbsp;<em>FileExtensionContentTypeProvider<\/em>&nbsp;di .Net Core che vi permette di ricavare il content type dall&#8217;estensione del file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A questo punto possiamo creare un progetto Angular con la CLI, con il quale&nbsp;vogliamo caricare dei file, visualizzarli e farne il download. In pi\u00f9, mostreremo lo stato di avanzamento durante il download o l\u2019upload, sfruttando una delle funzionalit\u00e0 del nuovo HttpClient di Angular. \f<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Creeremo un componente specifico per ogni operazione, Upload e Download, che utilizzeremo da un componente FileManager che mostrer\u00e0 la lista dei file caricati.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tutti e tre i componenti condivideranno un service in cui implementeremo le chiamate HTTP alla nostre API:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nimport { Injectable } from &#039;@angular\/core&#039;;\nimport { HttpClient, HttpRequest, HttpEvent, HttpResponse } from &#039;@angular\/common\/http&#039;;\nimport { Observable } from &#039;rxjs&#039;;\n\u00a0\n@Injectable()\nexport class UploadDownloadService {\n\u00a0\u00a0private baseApiUrl: string;\n\u00a0\u00a0private apiDownloadUrl: string;\n\u00a0\u00a0private apiUploadUrl: string;\n\u00a0\u00a0private apiFileUrl: string;\n\u00a0\n\u00a0\u00a0constructor(private httpClient: HttpClient) {\n\u00a0\u00a0\u00a0\u00a0this.baseApiUrl = &#039;http:\/\/localhost:5001\/api\/&#039;;\n\u00a0\u00a0\u00a0\u00a0this.apiDownloadUrl = this.baseApiUrl + &#039;download&#039;;\n\u00a0\u00a0\u00a0\u00a0this.apiUploadUrl = this.baseApiUrl + &#039;upload&#039;;\n\u00a0\u00a0\u00a0\u00a0this.apiFileUrl = this.baseApiUrl + &#039;files&#039;;\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public downloadFile(file: string): Observable&lt;HttpEvent&lt;Blob&gt;&gt; {\n\u00a0\u00a0\u00a0\u00a0return this.httpClient.request(new HttpRequest(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#039;GET&#039;,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0`${this.apiDownloadUrl}?file=${file}`,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0null,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0reportProgress: true,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0responseType: &#039;blob&#039;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}));\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public uploadFile(file: Blob): Observable&lt;HttpEvent&lt;void&gt;&gt; {\n\u00a0\u00a0\u00a0\u00a0const formData = new FormData();\n\u00a0\u00a0\u00a0\u00a0formData.append(&#039;file&#039;, file);\n\u00a0\n\u00a0\u00a0\u00a0\u00a0return this.httpClient.request(new HttpRequest(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#039;POST&#039;,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.apiUploadUrl,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0formData,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0reportProgress: true\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}));\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public getFiles(): Observable&lt;string&#x5B;]&gt; {\n\u00a0\u00a0\u00a0\u00a0return this.httpClient.get&lt;string&#x5B;]&gt;(this.apiFileUrl);\n\u00a0\u00a0}\n\u00a0\u00a0\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Rispetto al classico uso che si fa di HttpClient, che potete vedere nel metodo\u00a0<em>getFiles()<\/em>, in\u00a0<em>dowloadFile()<\/em>\u00a0e\u00a0<em>uploadFile()<\/em>, utilizziamo il metodo\u00a0<em>request()<\/em>, che ci permette di specificare una HttpRequest con tutte le sue opzioni, tra cui l&#8217;opzione\u00a0<em>reportProgress<\/em>\u00a0impostata su true. Questa opzione ci abilita a ricevere gli aggiornamenti sullo stato dello scambio dati\u00a0tra client e server. Come? Guardiamolo nel nostro componente Upload:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nimport { Component, Output, EventEmitter, Input, ViewChild, ElementRef } from &#039;@angular\/core&#039;;\nimport { UploadDownloadService } from &#039;src\/app\/services\/upload-download.service&#039;;\nimport { HttpEventType } from &#039;@angular\/common\/http&#039;;\nimport { ProgressStatus, ProgressStatusEnum } from &#039;src\/app\/models\/progress-status.model&#039;;\n\u00a0\n@Component({\n\u00a0\u00a0selector: &#039;app-upload&#039;,\n\u00a0\u00a0templateUrl: &#039;upload.component.html&#039;\n})\n\u00a0\nexport class UploadComponent {\n\u00a0\u00a0@Input() public disabled: boolean;\n\u00a0\u00a0@Output() public uploadStatus: EventEmitter&lt;progressstatus&gt;;\n\u00a0\u00a0@ViewChild(&#039;inputFile&#039;) inputFile: ElementRef;\n\u00a0\n\u00a0\u00a0constructor(private service: UploadDownloadService) {\n\u00a0\u00a0\u00a0\u00a0this.uploadStatus = new EventEmitter&lt;ProgressStatus&gt;();\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public upload(event) {\n\u00a0\u00a0\u00a0\u00a0if (event.target.files &amp;&amp; event.target.files.length &gt; 0) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const file = event.target.files&#x5B;0];\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.uploadStatus.emit({status: ProgressStatusEnum.START});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.service.uploadFile(file).subscribe(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (data) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0switch (data.type) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case HttpEventType.UploadProgress:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.uploadStatus.emit( {status: ProgressStatusEnum.IN_PROGRESS, percentage: Math.round((data.loaded \/ data.total) * 100)});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case HttpEventType.Response:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.inputFile.nativeElement.value = &#039;&#039;;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.uploadStatus.emit( {status: ProgressStatusEnum.COMPLETE});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0error =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.inputFile.nativeElement.value = &#039;&#039;;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.uploadStatus.emit({status: ProgressStatusEnum.ERROR});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0}\n}\n\u00a0\n&lt;\/progressstatus&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Come potete vedere, la sottoscrizione all&#8217;observable restituito dal HttpClient ci fornisce un oggetto di tipo HttpEvent, la cui propriet\u00e0&nbsp;<em>type<\/em>&nbsp;pu\u00f2 assumere uno di cinque valori:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Sent<\/strong>: quando la richiesta \u00e8 stata inviata;<\/li><li><strong>UploadProgress<\/strong>: quando \u00e8 in corso l&#8217;upload;<\/li><li><strong>ResponseHeader<\/strong>: quando status code e intestazioni sono state ricevute;<\/li><li><strong>DownloadProgress<\/strong>: quando \u00e8 in corso il download;<\/li><li><strong>Response<\/strong>: quando l&#8217;intera risposta \u00e8 stata ricevuta;<\/li><li><strong>User<\/strong>: quando viene sollevato un evento custom da un interceptor o dal backend.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Volendo uniformare gli eventi tra upload e download e astrarci dalla libreria HTTP, aggiungiamo una nostra enumerazione e una nostra interfaccia al progetto:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nexport interface ProgressStatus {\n\u00a0\u00a0status: ProgressStatusEnum;\n\u00a0\u00a0percentage?: number;\n}\n\u00a0\nexport enum ProgressStatusEnum {\n\u00a0\u00a0START, COMPLETE, IN_PROGRESS, ERROR\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Nel componente potete vederne l&#8217;utilizzo: semplicemente emettiamo lo START all&#8217;avvio dell&#8217;operazione, IN_PROGRESS in corrispondenza di UploadProgress, COMPLETE in corrispondenza di Respose ed ERROR in caso di errore.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il template prevede una input file nascosta e un pulsante \u201cUPLOAD\u201d. Cliccando sul pulsante, si aprir\u00e0 la finestra di selezione della input, dando modo all\u2019utente di selezionare il file. Sul change della input richiamiamo il metodo upload del componente.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;div class=&quot;container-upload&quot;&gt;\n\u00a0\u00a0\u00a0\u00a0&lt;button &#x5B;disabled]=&quot;disabled&quot; &#x5B;ngClass]=&quot;{&#039;disabled&#039;: disabled}&quot; class=&quot;button upload&quot; (click)=&quot;inputFile.click()&quot;&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0UPLOAD\n\u00a0\u00a0\u00a0\u00a0&lt;\/button&gt;\n\u00a0\u00a0\u00a0\u00a0&lt;input name=&quot;file&quot; id=&quot;file&quot;(change)=&quot;upload($event)&quot; type=&quot;file&quot; #inputFile hidden&gt;\n&lt;\/div&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Al termine dell\u2019operazione, sia in caso di successo che di errore, va ripulita la input dalla selezione, altrimenti risulta impossibile effettuare l\u2019upload dello stesso file consecutivamente. Per fare questo, si pu\u00f2 utilizzare sia&nbsp;<em>ReactiveForm<\/em>&nbsp;associando un&nbsp;<em>FormControl<\/em>&nbsp;alla input, sia con&nbsp;<em>ngModel<\/em>&nbsp;andando a pulire la propriet\u00e0 bindata.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se non volete tirare dentro la gestione delle form per cos\u00ec poco, accettando di sporcare leggermente la logica del componente, potete utilizzare il decoratore&nbsp;<em>ViewChild<\/em>, per ottenere un riferimento all\u2019elemento del DOM, tramite il quale potete resettare il valore dal&nbsp;<em>nativeElement<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per il download, facciamo un ragionamento simile, ma qui introduciamo un ulteriore requisito: vogliamo scaricare il file, aggiornare il progress e fornire il file scaricato all&#8217;utente senza ulteriore interazione.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il markup del componente Download \u00e8 molto semplice:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;button\n\u00a0&#x5B;disabled]=&quot;disabled&quot;\n\u00a0class=&quot;button download&quot;\n\u00a0&#x5B;ngClass]=&quot;{&#039;disabled&#039;: disabled}&quot;\n\u00a0(click)=&quot;download()&quot;&gt;download&lt;\/button&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">La logica del componente \u00e8 molto simile a quella dell&#8217;upload\u00a0ma, come abbiamo detto, una volta terminato il download vogliamo subito fornire il file all&#8217;utente.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nimport { Component, Input, Output, EventEmitter } from &#039;@angular\/core&#039;;\nimport { HttpEventType } from &#039;@angular\/common\/http&#039;;\nimport { UploadDownloadService } from &#039;src\/app\/services\/upload-download.service&#039;;\nimport { ProgressStatus, ProgressStatusEnum } from &#039;src\/app\/models\/progress-status.model&#039;;\n\u00a0\n@Component({\n\u00a0\u00a0selector: &#039;app-download&#039;,\n\u00a0\u00a0templateUrl: &#039;download.component.html&#039;\n})\n\u00a0\nexport class DownloadComponent {\n\u00a0\u00a0@Input() public disabled: boolean;\n\u00a0\u00a0@Input() public fileName: string;\n\u00a0\u00a0@Output() public downloadStatus: EventEmitter&lt;progressstatus&gt;;\n\u00a0\n\u00a0\u00a0constructor(private service: UploadDownloadService) {\n\u00a0\u00a0\u00a0\u00a0this.downloadStatus = new EventEmitter&lt;progressstatus&gt;();\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public download() {\n\u00a0\u00a0\u00a0\u00a0this.downloadStatus.emit( {status: ProgressStatusEnum.START});\n\u00a0\u00a0\u00a0\u00a0this.service.downloadFile(this.fileName).subscribe(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0switch (data.type) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case HttpEventType.DownloadProgress:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.downloadStatus.emit( {status: ProgressStatusEnum.IN_PROGRESS, percentage: Math.round((data.loaded \/ data.total) * 100)});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case HttpEventType.Response:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.downloadStatus.emit( {status: ProgressStatusEnum.COMPLETE});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const downloadedFile = new Blob(&#x5B;data.body], { type: data.body.type });\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const a = document.createElement(&#039;a&#039;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.setAttribute(&#039;style&#039;, &#039;display:none;&#039;);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.body.appendChild(a);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.download = this.fileName;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.href = URL.createObjectURL(downloadedFile);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.target = &#039;_blank&#039;;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.click();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0document.body.removeChild(a);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0error =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.downloadStatus.emit( {status: ProgressStatusEnum.ERROR});\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0);\n\u00a0\u00a0}\n}\n&lt;\/progressstatus&gt;&lt;\/progressstatus&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Per farlo dobbiamo leggermente sporcarci le mani, manipolando il DOM dal componente. Questo perch\u00e9&nbsp;il modo pi\u00f9 veloce di scaricare il file, senza un&#8217;&nbsp;ulteriore interazione dell&#8217;utente, \u00e8 creare al volo un elemento&nbsp;<em>anchor<\/em>&nbsp;e&nbsp;agganciarci un object URL costruito a partire dal&nbsp;<em>blob<\/em>&nbsp;scaricato. Possiamo poi impostare la propriet\u00e0 download dell&#8217;elemento con il nome del file e, a&nbsp;quel punto, cliccando l&#8217;elemento da codice, riusciamo a ottenere un download diretto anche per i file che il browser sa aprire, come i PDF. Subito dopo possiamo eliminare l&#8217;<em>anchor<\/em>&nbsp;creato.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un po&#8217; bruttino, concordo. Probabilmente la cosa migliore sarebbe spostare tutta la parte di manipolazione in una direttiva, ma ai fini del nostro ragionamento non cambierebbe molto: ve lo lascio come esercizio!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Utilizziamo entrambi i componenti dal componente FileManager e il gioco \u00e8 fatto. L&#8217;HTML sar\u00e0 il seguente:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n&lt;app-upload &#x5B;disabled]=&quot;showProgress&quot; (uploadStatus)=&quot;uploadStatus($event)&quot;&gt;&lt;\/app-upload&gt;\n&lt;h2&gt;File List&lt;\/h2&gt;\n&lt;p *ngIf=&quot;showProgress&quot;&gt; progress &lt;strong&gt;{{percentage}}%&lt;\/strong&gt;&lt;\/p&gt;\n&lt;hr&gt;\n&lt;div class=&quot;container&quot;&gt;\n\u00a0\u00a0\u00a0\u00a0&lt;ul&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;li *ngFor=&quot;let file of files&quot;&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;a&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{{file}}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;app-download &#x5B;disabled]=&quot;showProgress&quot; &#x5B;fileName]=&quot;file&quot; (downloadStatus)=&quot;downloadStatus($event)&quot;&gt;&lt;\/app-download&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/a&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/li&gt;\n\u00a0\u00a0\u00a0\u00a0&lt;\/ul&gt;\n&lt;\/div&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">La logica del componente\u00a0 si limiter\u00e0 a recuperare la lista dei file disponibili e a mostrare lo stato di upload e download sulla base degli eventi ricevuti dai componenti figli:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nimport { Component, OnInit } from &#039;@angular\/core&#039;;\nimport { UploadDownloadService } from &#039;src\/app\/services\/upload-download.service&#039;;\nimport { ProgressStatusEnum, ProgressStatus } from &#039;src\/app\/models\/progress-status.model&#039;;\n\u00a0\n@Component({\n\u00a0\u00a0selector: &#039;app-filemanager&#039;,\n\u00a0\u00a0templateUrl: &#039;.\/file-manager.component.html&#039;\n})\nexport class FileManagerComponent implements OnInit {\n\u00a0\n\u00a0\u00a0public files: string&#x5B;];\n\u00a0\u00a0public fileInDownload: string;\n\u00a0\u00a0public percentage: number;\n\u00a0\u00a0public showProgress: boolean;\n\u00a0\u00a0public showDownloadError: boolean;\n\u00a0\u00a0public showUploadError: boolean;\n\u00a0\n\u00a0\u00a0constructor(private service: UploadDownloadService) { }\n\u00a0\n\u00a0\u00a0ngOnInit() {\n\u00a0\u00a0\u00a0\u00a0this.getFiles();\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0private getFiles() {\n\u00a0\u00a0\u00a0\u00a0this.service.getFiles().subscribe(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.files = data;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0);\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public downloadStatus(event: ProgressStatus) {\n\u00a0\u00a0\u00a0\u00a0switch (event.status) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.START:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showDownloadError = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.IN_PROGRESS:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.percentage = event.percentage;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.COMPLETE:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.ERROR:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showDownloadError = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0public uploadStatus(event: ProgressStatus) {\n\u00a0\u00a0\u00a0\u00a0switch (event.status) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.START:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showUploadError = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.IN_PROGRESS:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.percentage = event.percentage;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.COMPLETE:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.getFiles();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0case ProgressStatusEnum.ERROR:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showProgress = false;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this.showUploadError = true;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0break;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0}\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Il risultato finale \u00e8 il seguente:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"984\" height=\"768\" data-attachment-id=\"29187\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/attachment\/759bfc10-b393-4d39-b9db-b12dbfb80681\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681.png?fit=984%2C768&amp;ssl=1\" data-orig-size=\"984,768\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"759bfc10-b393-4d39-b9db-b12dbfb80681\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681.png?fit=300%2C234&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681.png?fit=984%2C768&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681.png?resize=984%2C768&#038;ssl=1\" alt=\"\" class=\"wp-image-29187\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681.png 984w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681-980x765.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/759bfc10-b393-4d39-b9db-b12dbfb80681-480x375.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 984px, 100vw\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"987\" height=\"768\" data-attachment-id=\"29189\" data-permalink=\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/attachment\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c.png?fit=987%2C768&amp;ssl=1\" data-orig-size=\"987,768\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"8d8ca34c-475f-4a0f-888d-5fefcbeca77c\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c.png?fit=300%2C233&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c.png?fit=987%2C768&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c.png?resize=987%2C768&#038;ssl=1\" alt=\"\" class=\"wp-image-29189\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c.png 987w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c-980x763.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2020\/12\/8d8ca34c-475f-4a0f-888d-5fefcbeca77c-480x373.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 987px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Potete scaricare i sorgenti dal mio GitHub al seguente indirizzo:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-handler-delloggetto-incorporato wp-block-embed-handler-delloggetto-incorporato\"><div class=\"wp-block-embed__wrapper\">\n<a href=\"https:\/\/github.com\/AARNOLD87\/down-up-load-with-angular\" rel=\"nofollow\">https:\/\/github.com\/AARNOLD87\/down-up-load-with-angular<\/a>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Alla prossima!<\/p>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Come caricare e scaricare file con un front-end Angular e un back-end Asp.Net Core<\/p>\n","protected":false},"author":196716250,"featured_media":29179,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"","_et_gb_content_width":"","_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_crdt_document":"","inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false},"categories":[688637374],"tags":[688637387,688637414,688637389],"class_list":["post-29178","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-angular","tag-asp-net-core","tag-web"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Upload e Download di file con Angular e Asp.Net Core - Blexin<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Upload e Download di file con Angular e Asp.Net Core - Blexin\" \/>\n<meta property=\"og:description\" content=\"Come caricare e scaricare file con un front-end Angular e un back-end Asp.Net Core\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\" \/>\n<meta property=\"og:site_name\" content=\"Blexin\" \/>\n<meta property=\"article:published_time\" content=\"2019-01-22T23:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-01-13T08:40:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"608\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Adolfo Arnold\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adolfo Arnold\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\"},\"author\":{\"name\":\"Adolfo Arnold\",\"@id\":\"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517\"},\"headline\":\"Upload e Download di file con Angular e Asp.Net Core\",\"datePublished\":\"2019-01-22T23:00:00+00:00\",\"dateModified\":\"2021-01-13T08:40:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\"},\"wordCount\":824,\"image\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1\",\"keywords\":[\"Angular\",\"Asp.net core\",\"Web\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"it-IT\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\",\"url\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\",\"name\":\"Upload e Download di file con Angular e Asp.Net Core - Blexin\",\"isPartOf\":{\"@id\":\"https:\/\/blexin.com\/it\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1\",\"datePublished\":\"2019-01-22T23:00:00+00:00\",\"dateModified\":\"2021-01-13T08:40:48+00:00\",\"author\":{\"@id\":\"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517\"},\"breadcrumb\":{\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1\",\"width\":1024,\"height\":608},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blexin.com\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Upload e Download di file con Angular e Asp.Net Core\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blexin.com\/it\/#website\",\"url\":\"https:\/\/blexin.com\/it\/\",\"name\":\"Blexin\",\"description\":\"Con noi \u00e8 semplice\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blexin.com\/it\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517\",\"name\":\"Adolfo Arnold\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/blexin.com\/it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/ff2a87b54d0f130d7452164533199af05ef16dbd08b9241729946cea0eec7cca?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/ff2a87b54d0f130d7452164533199af05ef16dbd08b9241729946cea0eec7cca?s=96&d=identicon&r=g\",\"caption\":\"Adolfo Arnold\"},\"url\":\"https:\/\/blexin.com\/it\/author\/adolfo-arnoldblexin-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Upload e Download di file con Angular e Asp.Net Core - Blexin","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/","og_locale":"it_IT","og_type":"article","og_title":"Upload e Download di file con Angular e Asp.Net Core - Blexin","og_description":"Come caricare e scaricare file con un front-end Angular e un back-end Asp.Net Core","og_url":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/","og_site_name":"Blexin","article_published_time":"2019-01-22T23:00:00+00:00","article_modified_time":"2021-01-13T08:40:48+00:00","og_image":[{"width":1024,"height":608,"url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","type":"image\/png"}],"author":"Adolfo Arnold","twitter_card":"summary_large_image","twitter_misc":{"Scritto da":"Adolfo Arnold","Tempo di lettura stimato":"9 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#article","isPartOf":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/"},"author":{"name":"Adolfo Arnold","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517"},"headline":"Upload e Download di file con Angular e Asp.Net Core","datePublished":"2019-01-22T23:00:00+00:00","dateModified":"2021-01-13T08:40:48+00:00","mainEntityOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/"},"wordCount":824,"image":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","keywords":["Angular","Asp.net core","Web"],"articleSection":["Blog"],"inLanguage":"it-IT"},{"@type":"WebPage","@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/","url":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/","name":"Upload e Download di file con Angular e Asp.Net Core - Blexin","isPartOf":{"@id":"https:\/\/blexin.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage"},"image":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","datePublished":"2019-01-22T23:00:00+00:00","dateModified":"2021-01-13T08:40:48+00:00","author":{"@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517"},"breadcrumb":{"@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#primaryimage","url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","contentUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","width":1024,"height":608},{"@type":"BreadcrumbList","@id":"https:\/\/blexin.com\/it\/blog\/upload-e-download-di-file-con-angular-e-asp-net-core\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blexin.com\/it\/"},{"@type":"ListItem","position":2,"name":"Upload e Download di file con Angular e Asp.Net Core"}]},{"@type":"WebSite","@id":"https:\/\/blexin.com\/it\/#website","url":"https:\/\/blexin.com\/it\/","name":"Blexin","description":"Con noi \u00e8 semplice","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blexin.com\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Person","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/0de430b61c8a48b0e9d81308817c1517","name":"Adolfo Arnold","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blexin.com\/it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/ff2a87b54d0f130d7452164533199af05ef16dbd08b9241729946cea0eec7cca?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ff2a87b54d0f130d7452164533199af05ef16dbd08b9241729946cea0eec7cca?s=96&d=identicon&r=g","caption":"Adolfo Arnold"},"url":"https:\/\/blexin.com\/it\/author\/adolfo-arnoldblexin-com\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2020\/12\/fc2a2f4b-08b6-41d8-9d20-62d7bb3ad98b.png?fit=1024%2C608&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/pcyUBx-7AC","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/29178","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/users\/196716250"}],"replies":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/comments?post=29178"}],"version-history":[{"count":6,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/29178\/revisions"}],"predecessor-version":[{"id":29192,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/posts\/29178\/revisions\/29192"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media\/29179"}],"wp:attachment":[{"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/media?parent=29178"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/categories?post=29178"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blexin.com\/it\/wp-json\/wp\/v2\/tags?post=29178"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}