LEITURA DE ARQUIVO EXCEL ASP.NET CORE
By: Érik Thiago
Tags: Aspnetcore, Angular 7, Excel

LEITURA DE ARQUIVO EXCEL ASP.NET CORE

* imagem feita com base no site freepik.com

Como integrar Angular 7 e ASP.NET CORE para ler arquivo Excel

Diz aee meu caros leitores?!! Tudo bem com vocês? É isso mesmo, neste artigo vamos aprender como ler um arquivo Excel.

Vamos criar dois projetos distintos. Um em Angular e outro em ASP.NET CORE Web Api. Em que, um envia o arquivo e outro faz a leitura. O detalhe aqui é que vamos utilizar a lib EPPlus.Core, que faz operações com arquivos Excel.

Vamos lá? SHOW ME THE CODE Érik!!!

Primeiro, vamos começar pelo backend. Crie um projeto do tipo ASP.NET CORE Web Api. Isso não vou passar aqui como faz porque é muito simples, e, vocês devem saber, ok?

Ok, criado o projeto, você vai instalar, via Package Manager Console,digitando o comando Install-Package EPPlus.Core . Caso queira, também pode ir pelo nugget, beleza? Fica a seu critério.

Após o projeto ser criado, vá na classe Startup.cs e deixe ela da forma que tá abaixo:

public class Startup

{

public Startup(IConfiguration configuration)

{

Configuration = configuration;

}



public IConfiguration Configuration { get; }



// This method gets called by the runtime. Use this method to add services to the container.

public void ConfigureServices(IServiceCollection services)

{

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);



services.AddCors(options => {

options.AddPolicy("AllowDev",

builder => builder.WithOrigins("*").AllowAnyHeader()

.AllowAnyMethod()

);

});

}



// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

if (env.IsDevelopment())

{

app.UseDeveloperExceptionPage();

app.UseCors("AllowDev");

}



app.UseMvc();

}

}

Porque isso? Pra evitar erro de CORS e fazer com que sua api receba as chamadas feitas pelo nosso projeto em Angular.

Aqui pra fins de didática, eu criei um model MUITO simples, apenas pra vocês verem no debug, caso queira ver né, os valores do seu Excel sendo preenchidos em uma variável.

O código dele está abaixo:

public class Teste

{

public string T1 { get; set; }

public string T2 { get; set; }

}

É isso. Agora crie um controller e deixe ele com o código abaixo:

[Route("api/receivefile")]

[ApiController]

public class ReceiveFileController : ControllerBase

{

Teste teste = new Teste();



[HttpPost]

public async Task<IActionResult> UploadFile(IFormFile file)

{

if (file == null || file.Length == 0)

{

return RedirectToAction("");

}



using (var memoryStream = new MemoryStream())

{

await file.CopyToAsync(memoryStream).ConfigureAwait(false);



using (var package = new ExcelPackage(memoryStream))

{

for (int i = 1; i <= package.Workbook.Worksheets.Count; i++)

{

var totalRows = package.Workbook.Worksheets[i].Dimension?.Rows;

var totalCollumns = package.Workbook.Worksheets[i].Dimension?.Columns;

for (int j = 1; j <= totalRows.Value; j++)

{

for (int k = 1; k <= totalCollumns.Value; k++)

{

teste.T1 = package.Workbook.Worksheets[i].Cells[j, k].Value.ToString();

teste.T2 = package.Workbook.Worksheets[i].Cells[j, k].Value.ToString();

}

}

}



return Content(teste.T1);

}

}

}

}

Ok, o que esse trecho todo faz? É muito código!!!!!

Calma, calma. Fiquem calmos. O que esse trecho faz é: LER SEU EXCEL. Simples. Mas a rotina que temos é: verificamos quantas folhas tem seu Excel, quantas linhas e colunas cada folha tem e iteramos sobre cada uma para pegar o valor da coluna e da linha específica que estamos passando no momento.

Eu retorno um Content pro Angular, neste caso, pra mostrar no console qual foi o último valor que a variável teste recebeu e mostrar em um console no seu navegador. Aqui você pode salvar no banco, realizar alguma operação… Fica a seu critério.

Na parte do backend, é isso. Somente isso. Muito tranquilo, não?

Agora vamos para o frontend, nosso famoso e querido Angular X, qualquer que seja a versão que está usando, tirando o JS né? Hahaha.

É a coisa mais tranquila.

Primeiro, você vai criar a estrutura: um form com um input. Nesse caso, eu instalei uma lib que usa o material angular pra criar um input file bem bonito, que é o ngx-material-file-input. Mas não precisa usar se não quiser, ok?

Bom, no nosso html, de forma bem prática e pra ser didático, tem somente o file input, conforme código abaixo:

<form class="app-form" [formGroup]="form">

<mat-form-field class="app-form-control">

<ngx-mat-file-input placeholder="Anexos" formControlName="anexos"></ngx-mat-file-input>

<mat-icon matSuffix>folder</mat-icon>

</mat-form-field>



<button (click)="onSubmit()">Salvar</button>

</form>

É somente isso mesmo. Mas no seu caso real de uma aplicação real, você vai ter os seus dados aqui também, ok?

Bom, como eu estou usando o material angular, precisei criar um module a parte com todos os componentes do material angular, conforme código abaixo, e chamar ele no App Module. Segue o código:

import { NgModule } from '@angular/core';

import {

MatAutocompleteModule,

MatBadgeModule,

MatBottomSheetModule,

MatButtonModule,

MatButtonToggleModule,

MatCardModule,

MatCheckboxModule,

MatChipsModule,

MatDatepickerModule,

MatDialogModule,

MatDividerModule,

MatExpansionModule,

MatGridListModule,

MatIconModule,

MatInputModule,

MatListModule,

MatMenuModule,

MatNativeDateModule,

MatPaginatorModule,

MatProgressBarModule,

MatProgressSpinnerModule,

MatRadioModule,

MatRippleModule,

MatSelectModule,

MatSidenavModule,

MatSliderModule,

MatSlideToggleModule,

MatSnackBarModule,

MatSortModule,

MatStepperModule,

MatTableModule,

MatTabsModule,

MatToolbarModule,

MatTooltipModule,

MatTreeModule,

MatFormFieldModule,

MatPaginatorIntl} from '@angular/material';



import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

import {CdkTableModule} from '@angular/cdk/table';

import {CdkTreeModule} from '@angular/cdk/tree';



@NgModule({

imports: [BrowserAnimationsModule, MatButtonModule, MatCheckboxModule, MatSidenavModule, MatFormFieldModule],

exports: [

CdkTableModule,

CdkTreeModule,

MatAutocompleteModule,

MatBadgeModule,

MatBottomSheetModule,

MatButtonModule,

MatButtonToggleModule,

MatCardModule,

MatCheckboxModule,

MatChipsModule,

MatStepperModule,

MatDatepickerModule,

MatDialogModule,

MatDividerModule,

MatExpansionModule,

MatGridListModule,

MatIconModule,

MatInputModule,

MatListModule,

MatMenuModule,

MatNativeDateModule,

MatPaginatorModule,

MatProgressBarModule,

MatProgressSpinnerModule,

MatRadioModule,

MatRippleModule,

MatSelectModule,

MatSidenavModule,

MatSliderModule,

MatSlideToggleModule,

MatSnackBarModule,

MatSortModule,

MatTableModule,

MatTabsModule,

MatToolbarModule,

MatTooltipModule,

MatTreeModule,

MatFormFieldModule

]

})



export class MaterialComponentsModule { }

Criei também um serivce base. É uma abordagem pra organizar seu código e deixar ele mais limpo. Segue o código do service base:

import { Observable, of } from "rxjs";

import { environment } from "src/environments/environment";

import { HttpClient } from "@angular/common/http";

import { tap, catchError } from 'rxjs/operators';



export class BaseService {



constructor(public http: HttpClient, public api) {

}



/** POST: add a new file to the server */

sendFile(file: any) : Observable<any> {

const url = `${this.service()}/${this.api}`;

return this.http.post(url, file, { responseType: 'text' })

.pipe(tap(), catchError(this.handleError<any>('base service add')));

}



protected log(message: string) {

message = message;

}



/**

* Handle Http operation that failed.

* Let the app continue.

* @param operation - name of the operation that failed

* @param result - optional value to return as the observable result

*/

protected handleError<T>(operation = 'operation', result?: T) {

return (error: any): Observable<T> => {



// TODO: send the error to remote logging infrastructure

console.error(error); // log to console instead



// TODO: better job of transforming error for user consumption

this.log(`${operation} failed: ${error.message}`);



// Let the app keep running by returning an empty result.

return of(result as T);

};

}



service(): string {

var url = environment.endpoint.endsWith("/") ?

environment.endpoint.substring(0, environment.endpoint.length - 1) : environment.endpoint;



return url;

}

}

E herdei ele no service que vou utilizar no ts. Esse service herda todas as características do base e se eu precisar de mais rotinas, eu vou colocando. O base é pra conter todas as operações comuns, que serão herdadas nos services subjacentes. Isso é ótimo, pois deixa seu código mais limpo e organizado. Segue o código do service subjacente:

import { BaseService } from "./base/base.service";

import { Injectable } from "@angular/core";

import { HttpClient } from "@angular/common/http";



@Injectable({

providedIn: 'root'

})

export class FileService extends BaseService {

constructor(http: HttpClient) {

super(http, 'receivefile')

}

}

Bom, com toda a infra já estruturada e feita, vamos agora codificar o ts pra poder fazer a captura e o envio do arquivo Excel para a API. Segue o código:

import { Component, OnInit } from '@angular/core';

import { FormGroup, FormControl } from '@angular/forms';

import { FileService } from 'src/app/services/file.service';



@Component({

selector: 'app-ler-arquivo-excel',

templateUrl: './ler-arquivo-excel.component.html',

styleUrls: ['./ler-arquivo-excel.component.scss']

})

export class LerArquivoExcelComponent implements OnInit {



form: FormGroup;



constructor(private service: FileService) { }



ngOnInit() {

this.form = new FormGroup({

anexos: new FormControl()

});

}



onSubmit() {

let file = new FormData();

file.append("file", this.form.controls.anexos.value.files[0])

this.service.sendFile(file).subscribe(res => {

// mostra no log o ultimo registro passado pelo excel

console.log(res)

});

}



}

E pronto!!! Simples não? Agora você enviar um arquivo Excel para a API e fazer a leitura e manipular os dados da forma como desejar!!

Então é isso, galera!! Críticas construtivas são muito bem vindas. Os projetos estão no GitHub. A API e o projeto Angular. Como é de código aberto, caso queiram contribuir, à vontade!!