namespace Microsoft.eShopOnContainers.Services.Identity.API.Data { using Microsoft.Extensions.Logging; public class ApplicationDbContextSeed { private readonly IPasswordHasher _passwordHasher = new PasswordHasher(); public async Task SeedAsync(ApplicationDbContext context, IWebHostEnvironment env, ILogger logger, IOptions settings, int? retry = 0) { int retryForAvaiability = retry.Value; try { var useCustomizationData = settings.Value.UseCustomizationData; var contentRootPath = env.ContentRootPath; var webroot = env.WebRootPath; if (!context.Users.Any()) { context.Users.AddRange(useCustomizationData ? GetUsersFromFile(contentRootPath, logger) : GetDefaultUser()); await context.SaveChangesAsync(); } if (useCustomizationData) { GetPreconfiguredImages(contentRootPath, webroot, logger); } } catch (Exception ex) { if (retryForAvaiability < 10) { retryForAvaiability++; logger.LogError(ex, "EXCEPTION ERROR while migrating {DbContextName}", nameof(ApplicationDbContext)); await SeedAsync(context, env, logger, settings, retryForAvaiability); } } } private IEnumerable GetUsersFromFile(string contentRootPath, ILogger logger) { string csvFileUsers = Path.Combine(contentRootPath, "Setup", "Users.csv"); if (!File.Exists(csvFileUsers)) { return GetDefaultUser(); } string[] csvheaders; try { string[] requiredHeaders = { "cardholdername", "cardnumber", "cardtype", "city", "country", "email", "expiration", "lastname", "name", "phonenumber", "username", "zipcode", "state", "street", "securitynumber", "normalizedemail", "normalizedusername", "password" }; csvheaders = GetHeaders(requiredHeaders, csvFileUsers); } catch (Exception ex) { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return GetDefaultUser(); } List users = File.ReadAllLines(csvFileUsers) .Skip(1) // skip header column .Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)")) .SelectTry(column => CreateApplicationUser(column, csvheaders)) .OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; }) .Where(x => x != null) .ToList(); return users; } private ApplicationUser CreateApplicationUser(string[] column, string[] headers) { if (column.Count() != headers.Count()) { throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'"); } string cardtypeString = column[Array.IndexOf(headers, "cardtype")].Trim('"').Trim(); if (!int.TryParse(cardtypeString, out int cardtype)) { throw new Exception($"cardtype='{cardtypeString}' is not a number"); } var user = new ApplicationUser { CardHolderName = column[Array.IndexOf(headers, "cardholdername")].Trim('"').Trim(), CardNumber = column[Array.IndexOf(headers, "cardnumber")].Trim('"').Trim(), CardType = cardtype, City = column[Array.IndexOf(headers, "city")].Trim('"').Trim(), Country = column[Array.IndexOf(headers, "country")].Trim('"').Trim(), Email = column[Array.IndexOf(headers, "email")].Trim('"').Trim(), Expiration = column[Array.IndexOf(headers, "expiration")].Trim('"').Trim(), Id = Guid.NewGuid().ToString(), LastName = column[Array.IndexOf(headers, "lastname")].Trim('"').Trim(), Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(), PhoneNumber = column[Array.IndexOf(headers, "phonenumber")].Trim('"').Trim(), UserName = column[Array.IndexOf(headers, "username")].Trim('"').Trim(), ZipCode = column[Array.IndexOf(headers, "zipcode")].Trim('"').Trim(), State = column[Array.IndexOf(headers, "state")].Trim('"').Trim(), Street = column[Array.IndexOf(headers, "street")].Trim('"').Trim(), SecurityNumber = column[Array.IndexOf(headers, "securitynumber")].Trim('"').Trim(), NormalizedEmail = column[Array.IndexOf(headers, "normalizedemail")].Trim('"').Trim(), NormalizedUserName = column[Array.IndexOf(headers, "normalizedusername")].Trim('"').Trim(), SecurityStamp = Guid.NewGuid().ToString("D"), PasswordHash = column[Array.IndexOf(headers, "password")].Trim('"').Trim(), // Note: This is the password }; user.PasswordHash = _passwordHasher.HashPassword(user, user.PasswordHash); return user; } private IEnumerable GetDefaultUser() { var user = new ApplicationUser() { CardHolderName = "DemoUser", CardNumber = "4012888888881881", CardType = 1, City = "Redmond", Country = "U.S.", Email = "demouser@microsoft.com", Expiration = "12/25", Id = Guid.NewGuid().ToString(), LastName = "DemoLastName", Name = "DemoUser", PhoneNumber = "1234567890", UserName = "demouser@microsoft.com", ZipCode = "98052", State = "WA", Street = "15703 NE 61st Ct", SecurityNumber = "535", NormalizedEmail = "DEMOUSER@MICROSOFT.COM", NormalizedUserName = "DEMOUSER@MICROSOFT.COM", SecurityStamp = Guid.NewGuid().ToString("D"), }; user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1"); return new List() { user }; } static string[] GetHeaders(string[] requiredHeaders, string csvfile) { string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(','); if (csvheaders.Count() != requiredHeaders.Count()) { throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'"); } foreach (var requiredHeader in requiredHeaders) { if (!csvheaders.Contains(requiredHeader)) { throw new Exception($"does not contain required header '{requiredHeader}'"); } } return csvheaders; } static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger logger) { try { string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip"); if (!File.Exists(imagesZipFile)) { logger.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile); return; } string imagePath = Path.Combine(webroot, "images"); string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray(); using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read)) { foreach (ZipArchiveEntry entry in zip.Entries) { if (imageFiles.Contains(entry.Name)) { string destinationFilename = Path.Combine(imagePath, entry.Name); if (File.Exists(destinationFilename)) { File.Delete(destinationFilename); } entry.ExtractToFile(destinationFilename); } else { logger.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile); } } } } catch (Exception ex) { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); ; } } } }