-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Change CSV builder to allow expansion of type mapper and add Customer CSV DTO * Frontend: Export as CSV for Products and Customers
- Loading branch information
1 parent
5affa2d
commit ac0385b
Showing
21 changed files
with
345 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Northwind.Application.Common.Interfaces; | ||
|
||
public interface ICsvBuilder | ||
{ | ||
Task<byte[]> GetCsvBytes<T>(IEnumerable<T> records); | ||
} |
18 changes: 18 additions & 0 deletions
18
Src/Application/Customers/Queries/GetCustomersCsv/CustomerCsvLookupDto.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using AutoMapper; | ||
using Northwind.Application.Common.Mappings; | ||
using Northwind.Domain.Customers; | ||
|
||
namespace Northwind.Application.Customers.Queries.GetCustomersCsv; | ||
|
||
public class CustomerCsvLookupDto : IMapFrom<Customer> | ||
{ | ||
public required string Id { get; init; } | ||
public required string Name { get; init; } | ||
|
||
public void Mapping(Profile profile) | ||
{ | ||
profile.CreateMap<Customer, CustomerCsvLookupDto>() | ||
.ForMember(d => d.Id, opt => opt.MapFrom(s => s.Id.Value)) | ||
.ForMember(d => d.Name, opt => opt.MapFrom(s => s.CompanyName)); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
Src/Application/Customers/Queries/GetCustomersCsv/CustomersCsvVm.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Northwind.Application.Customers.Queries.GetCustomersCsv; | ||
|
||
public class CustomersCsvVm | ||
{ | ||
public required byte[] Data { get; set; } | ||
public required string FileName { get; set; } | ||
public readonly string ContentType = "text/csv"; | ||
} |
31 changes: 31 additions & 0 deletions
31
Src/Application/Customers/Queries/GetCustomersCsv/GetCustomersCsvQuery.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using AutoMapper; | ||
using AutoMapper.QueryableExtensions; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
using Northwind.Application.Common.Interfaces; | ||
|
||
namespace Northwind.Application.Customers.Queries.GetCustomersCsv; | ||
|
||
public sealed record GetCustomersCsvQuery : IRequest<CustomersCsvVm>; | ||
|
||
public sealed class GetCustomersCsvQueryHandler( | ||
INorthwindDbContext context, | ||
IMapper mapper, | ||
IDateTime dateTime, | ||
ICsvBuilder csvBuilder) : IRequestHandler<GetCustomersCsvQuery, CustomersCsvVm> | ||
{ | ||
public async Task<CustomersCsvVm> Handle(GetCustomersCsvQuery request, CancellationToken cancellationToken) | ||
{ | ||
IEnumerable<CustomerCsvLookupDto> customers = await context.Customers | ||
.ProjectTo<CustomerCsvLookupDto>(mapper.ConfigurationProvider) | ||
.ToListAsync(cancellationToken); | ||
|
||
byte[] data = await csvBuilder.GetCsvBytes(customers); | ||
|
||
return new CustomersCsvVm | ||
{ | ||
Data = data, | ||
FileName = $"{dateTime.Now:yyyy-MM-dd}-Products.csv", | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 0 additions & 6 deletions
6
Src/Application/Products/Queries/GetProductsFile/ICsvFileBuilder.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using CsvHelper; | ||
using Northwind.Application.Common.Interfaces; | ||
using System.Globalization; | ||
|
||
namespace Northwind.Infrastructure.Files; | ||
|
||
public class CsvBuilder : ICsvBuilder | ||
{ | ||
public Task<byte[]> GetCsvBytes<T>(IEnumerable<T> records) | ||
{ | ||
using var stream = new MemoryStream(); | ||
using var streamWriter = new StreamWriter(stream); | ||
using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture)) | ||
{ | ||
csvWriter.Context.ConfigureMappingProvider<T>(); | ||
csvWriter.WriteRecords(records); | ||
} | ||
|
||
return Task.FromResult(stream.ToArray()); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using CsvHelper; | ||
using Northwind.Application.Customers.Queries.GetCustomersCsv; | ||
using Northwind.Application.Products.Queries.GetProductsFile; | ||
|
||
namespace Northwind.Infrastructure.Files; | ||
|
||
public static class CsvMapProviders | ||
{ | ||
private static readonly IReadOnlyDictionary<Type, Action<CsvContext>> TypeConfiguration = new Dictionary<Type, Action<CsvContext>> | ||
{ | ||
{ typeof(ProductRecordDto), context => context.RegisterClassMap<ProductFileRecordMap>() }, | ||
{ typeof(CustomerCsvLookupDto), context => context.RegisterClassMap<CustomerFileRecordMap>() }, | ||
}; | ||
|
||
public static void ConfigureMappingProvider<T>( | ||
this CsvContext csvContext) | ||
{ | ||
TypeConfiguration.GetValueOrDefault(typeof(T))?.Invoke(csvContext); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using CsvHelper.Configuration; | ||
using Northwind.Application.Customers.Queries.GetCustomersCsv; | ||
using System.Globalization; | ||
|
||
namespace Northwind.Infrastructure.Files; | ||
|
||
public sealed class CustomerFileRecordMap : ClassMap<CustomerCsvLookupDto> | ||
{ | ||
public CustomerFileRecordMap() | ||
{ | ||
AutoMap(CultureInfo.InvariantCulture); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 19 additions & 10 deletions
29
Src/WebUI/ClientApp/src/app/customers/customers.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,38 @@ | ||
import { Component } from '@angular/core'; | ||
import { Client, CustomerDetailVm, CustomersListVm } from '../northwind-traders-api'; | ||
import { Component, inject, OnInit } from '@angular/core'; | ||
import { Client, CustomersListVm } from '../northwind-traders-api'; | ||
import { CustomerDetailComponent } from '../customer-detail/customer-detail.component'; | ||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; | ||
import { BsModalService } from 'ngx-bootstrap/modal'; | ||
import { saveAs } from 'file-saver'; | ||
|
||
@Component({ | ||
selector: 'app-customers', | ||
templateUrl: './customers.component.html' | ||
}) | ||
export class CustomersComponent { | ||
export class CustomersComponent implements OnInit { | ||
private client = inject(Client); | ||
private modalService =inject(BsModalService); | ||
|
||
public vm: CustomersListVm = new CustomersListVm(); | ||
private bsModalRef: BsModalRef; | ||
|
||
constructor(private client: Client, private modalService: BsModalService) { | ||
client.getCustomersList().subscribe(result => { | ||
ngOnInit(): void { | ||
this.client.getCustomersList().subscribe(result => { | ||
this.vm = result; | ||
}, error => console.error(error)); | ||
}); | ||
} | ||
|
||
public customerDetail(id: string) { | ||
this.client.getCustomer(id).subscribe(result => { | ||
const initialState = { | ||
customer: result | ||
}; | ||
this.bsModalRef = this.modalService.show(CustomerDetailComponent, {initialState}); | ||
}, error => console.error(error)); | ||
this.modalService.show(CustomerDetailComponent, {initialState}); | ||
}); | ||
} | ||
|
||
protected exportAsCsv() { | ||
this.client.getCustomersCsv().subscribe(result => { | ||
const blob = new Blob([result.data], { type: result.headers.contentType }); | ||
saveAs(blob, result.fileName); | ||
}); | ||
} | ||
} |
Oops, something went wrong.