@ -1,15 +1,14 @@
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure
{
using EntityFrameworkCore ;
using Extensions.Logging ;
using global : : Catalog . API . Extensions ;
using Microsoft.AspNetCore.Builder ;
using Microsoft.AspNetCore.Hosting ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Options ;
using Model ;
using Polly ;
using System ;
using System.Collections.Generic ;
using System.Data.SqlClient ;
using System.Globalization ;
using System.IO ;
using System.IO.Compression ;
@ -19,56 +18,48 @@
public class CatalogContextSeed
{
public static async Task SeedAsync ( IApplicationBuilder applicationBuilder , IHostingEnvironment env , ILoggerFactory loggerFactory , int? retry = 0 )
public async Task SeedAsync ( CatalogContext context , IHostingEnvironment env , IOptions < CatalogSettings > settings , ILogger < CatalogContextSeed > logger )
{
var log = loggerFactory . CreateLogger ( "catalog seed" ) ;
var policy = CreatePolicy ( logger , nameof ( CatalogContextSeed ) ) ;
var context = ( CatalogContext ) applicationBuilder
. ApplicationServices . GetService ( typeof ( CatalogContext ) ) ;
context . Database . Migrate ( ) ;
var settings = ( CatalogSettings ) applicationBuilder
. ApplicationServices . GetRequiredService < IOptions < CatalogSettings > > ( ) . Value ;
var useCustomizationData = settings . UseCustomizationData ;
var contentRootPath = env . ContentRootPath ;
var picturePath = env . WebRootPath ;
if ( ! context . CatalogBrands . Any ( ) )
await policy . ExecuteAsync ( async ( ) = >
{
context . CatalogBrands . AddRange ( useCustomizationData
? GetCatalogBrandsFromFile ( contentRootPath , log )
: GetPreconfiguredCatalogBrands ( )
) ;
var useCustomizationData = settings . Value . UseCustomizationData ;
var contentRootPath = env . ContentRootPath ;
var picturePath = env . WebRootPath ;
await context . SaveChangesAsync ( ) ;
}
if ( ! context . CatalogBrands . Any ( ) )
{
context . CatalogBrands . AddRange ( useCustomizationData
? GetCatalogBrandsFromFile ( contentRootPath , logger )
: GetPreconfiguredCatalogBrands ( ) ) ;
if ( ! context . CatalogTypes . Any ( ) )
{
context . CatalogTypes . AddRange ( useCustomizationData
? GetCatalogTypesFromFile ( contentRootPath , log )
: GetPreconfiguredCatalogTypes ( )
) ;
await context . SaveChangesAsync ( ) ;
}
await context . SaveChangesAsync ( ) ;
}
if ( ! context . CatalogTypes . Any ( ) )
{
context . CatalogTypes . AddRange ( useCustomizationData
? GetCatalogTypesFromFile ( contentRootPath , logger )
: GetPreconfiguredCatalogTypes ( ) ) ;
if ( ! context . CatalogItems . Any ( ) )
{
context . CatalogItems . AddRange ( useCustomizationData
? GetCatalogItemsFromFile ( contentRootPath , context , log )
: GetPreconfiguredItems ( )
) ;
await context . SaveChangesAsync ( ) ;
}
await context . SaveChangesAsync ( ) ;
if ( ! context . CatalogItems . Any ( ) )
{
context . CatalogItems . AddRange ( useCustomizationData
? GetCatalogItemsFromFile ( contentRootPath , context , logger )
: GetPreconfiguredItems ( ) ) ;
GetCatalogItemPictures ( contentRootPath , picturePath ) ;
}
await context . SaveChangesAsync ( ) ;
GetCatalogItemPictures ( contentRootPath , picturePath ) ;
}
} ) ;
}
static IEnumerable < CatalogBrand > GetCatalogBrandsFromFile ( string contentRootPath , ILogger log )
private IEnumerable < CatalogBrand > GetCatalogBrandsFromFile ( string contentRootPath , ILogger < CatalogContextSeed > logger )
{
string csvFileCatalogBrands = Path . Combine ( contentRootPath , "Setup" , "CatalogBrands.csv" ) ;
@ -85,18 +76,18 @@
}
catch ( Exception ex )
{
log . LogError ( ex . Message ) ;
logger . LogError ( ex . Message ) ;
return GetPreconfiguredCatalogBrands ( ) ;
}
return File . ReadAllLines ( csvFileCatalogBrands )
. Skip ( 1 ) // skip header row
. SelectTry ( x = > CreateCatalogBrand ( x ) )
. OnCaughtException ( ex = > { log . LogError ( ex . Message ) ; return null ; } )
. OnCaughtException ( ex = > { logger . LogError ( ex . Message ) ; return null ; } )
. Where ( x = > x ! = null ) ;
}
static CatalogBrand CreateCatalogBrand ( string brand )
private CatalogBrand CreateCatalogBrand ( string brand )
{
brand = brand . Trim ( '"' ) . Trim ( ) ;
@ -111,7 +102,7 @@
} ;
}
static IEnumerable < CatalogBrand > GetPreconfiguredCatalogBrands ( )
private IEnumerable < CatalogBrand > GetPreconfiguredCatalogBrands ( )
{
return new List < CatalogBrand > ( )
{
@ -123,7 +114,7 @@
} ;
}
static IEnumerable < CatalogType > GetCatalogTypesFromFile ( string contentRootPath , ILogger log )
private IEnumerable < CatalogType > GetCatalogTypesFromFile ( string contentRootPath , ILogger < CatalogContextSeed > logger )
{
string csvFileCatalogTypes = Path . Combine ( contentRootPath , "Setup" , "CatalogTypes.csv" ) ;
@ -140,18 +131,18 @@
}
catch ( Exception ex )
{
log . LogError ( ex . Message ) ;
logger . LogError ( ex . Message ) ;
return GetPreconfiguredCatalogTypes ( ) ;
}
return File . ReadAllLines ( csvFileCatalogTypes )
. Skip ( 1 ) // skip header row
. SelectTry ( x = > CreateCatalogType ( x ) )
. OnCaughtException ( ex = > { log . LogError ( ex . Message ) ; return null ; } )
. OnCaughtException ( ex = > { logger . LogError ( ex . Message ) ; return null ; } )
. Where ( x = > x ! = null ) ;
}
static CatalogType CreateCatalogType ( string type )
private CatalogType CreateCatalogType ( string type )
{
type = type . Trim ( '"' ) . Trim ( ) ;
@ -166,7 +157,7 @@
} ;
}
static IEnumerable < CatalogType > GetPreconfiguredCatalogTypes ( )
private IEnumerable < CatalogType > GetPreconfiguredCatalogTypes ( )
{
return new List < CatalogType > ( )
{
@ -177,7 +168,7 @@
} ;
}
static IEnumerable < CatalogItem > GetCatalogItemsFromFile ( string contentRootPath , CatalogContext context , ILogger log )
private IEnumerable < CatalogItem > GetCatalogItemsFromFile ( string contentRootPath , CatalogContext context , ILogger < CatalogContextSeed > logger )
{
string csvFileCatalogItems = Path . Combine ( contentRootPath , "Setup" , "CatalogItems.csv" ) ;
@ -195,7 +186,7 @@
}
catch ( Exception ex )
{
log . LogError ( ex . Message ) ;
logger . LogError ( ex . Message ) ;
return GetPreconfiguredItems ( ) ;
}
@ -206,11 +197,11 @@
. Skip ( 1 ) // skip header row
. Select ( row = > Regex . Split ( row , ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)" ) )
. SelectTry ( column = > CreateCatalogItem ( column , csvheaders , catalogTypeIdLookup , catalogBrandIdLookup ) )
. OnCaughtException ( ex = > { log . LogError ( ex . Message ) ; return null ; } )
. OnCaughtException ( ex = > { logger . LogError ( ex . Message ) ; return null ; } )
. Where ( x = > x ! = null ) ;
}
static CatalogItem CreateCatalogItem ( string [ ] column , string [ ] headers , Dictionary < String , int > catalogTypeIdLookup , Dictionary < String , int > catalogBrandIdLookup )
private CatalogItem CreateCatalogItem ( string [ ] column , string [ ] headers , Dictionary < String , int > catalogTypeIdLookup , Dictionary < String , int > catalogBrandIdLookup )
{
if ( column . Count ( ) ! = headers . Count ( ) )
{
@ -316,7 +307,7 @@
return catalogItem ;
}
static IEnumerable < CatalogItem > GetPreconfiguredItems ( )
private IEnumerable < CatalogItem > GetPreconfiguredItems ( )
{
return new List < CatalogItem > ( )
{
@ -335,7 +326,7 @@
} ;
}
static string [ ] GetHeaders ( string csvfile , string [ ] requiredHeaders , string [ ] optionalHeaders = null )
private string [ ] GetHeaders ( string csvfile , string [ ] requiredHeaders , string [ ] optionalHeaders = null )
{
string [ ] csvheaders = File . ReadLines ( csvfile ) . First ( ) . ToLowerInvariant ( ) . Split ( ',' ) ;
@ -363,7 +354,7 @@
return csvheaders ;
}
static void GetCatalogItemPictures ( string contentRootPath , string picturePath )
private void GetCatalogItemPictures ( string contentRootPath , string picturePath )
{
DirectoryInfo directory = new DirectoryInfo ( picturePath ) ;
foreach ( FileInfo file in directory . GetFiles ( ) )
@ -374,7 +365,18 @@
string zipFileCatalogItemPictures = Path . Combine ( contentRootPath , "Setup" , "CatalogItems.zip" ) ;
ZipFile . ExtractToDirectory ( zipFileCatalogItemPictures , picturePath ) ;
}
}
private Policy CreatePolicy ( ILogger < CatalogContextSeed > logger , string prefix , int retries = 3 )
{
return Policy . Handle < SqlException > ( ) .
WaitAndRetryAsync (
retryCount : retries ,
sleepDurationProvider : retry = > TimeSpan . FromSeconds ( 5 ) ,
onRetry : ( exception , timeSpan , retry , ctx ) = >
{
logger . LogTrace ( $"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}" ) ;
}
) ;
}
}
}