From 28feb82931423df678c75526dd8706afb432b7f6 Mon Sep 17 00:00:00 2001 From: Irina Drot Date: Wed, 22 Jul 2026 09:07:25 -0400 Subject: [PATCH 1/2] changes to files --- .../src/Library.Console/ConsoleApp.cs | 8 + .../Services/LoanService.cs | 4 +- .../Services/PatronService.cs | 2 +- .../src/Library.Console/ConsoleApp.cs | 6 +- .../Data/JsonPatronRepository.cs | 4 +- readme.md | 155 +++++++++++++++++- 6 files changed, 164 insertions(+), 15 deletions(-) diff --git a/LabFiles/02-analyze-document-code/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs b/LabFiles/02-analyze-document-code/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs index 9fc9750..4de087d 100644 --- a/LabFiles/02-analyze-document-code/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs +++ b/LabFiles/02-analyze-document-code/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs @@ -47,6 +47,14 @@ public async Task Run() } } + /// + /// Handles the patron search state. Prompts the user for a patron name, + /// searches the repository, and validates the results before proceeding. + /// + /// + /// ConsoleState.PatronSearch if no results found or too many results (>20); + /// ConsoleState.PatronSearchResults if valid results are found. + /// async Task PatronSearch() { string searchInput = ReadPatronName(); diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/LoanService.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/LoanService.cs index 0f13d3a..7a70577 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/LoanService.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/LoanService.cs @@ -31,7 +31,7 @@ public async Task ReturnLoan(int loanId) await _loanRepository.UpdateLoan(loan); return LoanReturnStatus.Success; } - catch (Exception e) + catch (Exception) { return LoanReturnStatus.Error; } @@ -62,7 +62,7 @@ public async Task ExtendLoan(int loanId) await _loanRepository.UpdateLoan(loan); return LoanExtensionStatus.Success; } - catch (Exception e) + catch (Exception) { return LoanExtensionStatus.Error; } diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/PatronService.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/PatronService.cs index 7ba6d78..c9a73a9 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/PatronService.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Services/PatronService.cs @@ -29,7 +29,7 @@ public async Task RenewMembership(int patronId) try{ await _patronRepository.UpdatePatron(patron); return MembershipRenewalStatus.Success; - } catch (Exception e) { + } catch (Exception) { return MembershipRenewalStatus.Error; } } diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs index 9fc9750..fdfb72b 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs @@ -182,6 +182,8 @@ static void WriteInputOptions(CommonActions options) async Task PatronDetails() { + if (selectedPatronDetails == null) + throw new InvalidOperationException("selectedPatronDetails is null."); Console.WriteLine($"Name: {selectedPatronDetails.Name}"); Console.WriteLine($"Membership Expiration: {selectedPatronDetails.MembershipEnd}"); Console.WriteLine(); @@ -231,6 +233,8 @@ async Task PatronDetails() async Task LoanDetails() { + if (selectedPatronDetails == null) + throw new InvalidOperationException("selectedPatronDetails is null."); Console.WriteLine($"Book title: {selectedLoanDetails.BookItem!.Book!.Title}"); Console.WriteLine($"Book Author: {selectedLoanDetails.BookItem!.Book!.Author!.Name}"); Console.WriteLine($"Due date: {selectedLoanDetails.DueDate}"); @@ -257,7 +261,7 @@ async Task LoanDetails() Console.WriteLine(EnumHelper.GetDescription(status)); _currentState = ConsoleState.LoanDetails; // reload loan after returning - selectedLoanDetails = await _loanRepository.GetLoan(selectedLoanDetails.Id); + selectedLoanDetails = (await _loanRepository.GetLoan(selectedLoanDetails.Id))!; return ConsoleState.LoanDetails; } else if (action == CommonActions.Quit) diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data/JsonPatronRepository.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data/JsonPatronRepository.cs index efb05f8..43f30a5 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data/JsonPatronRepository.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data/JsonPatronRepository.cs @@ -17,7 +17,7 @@ public async Task> SearchPatrons(string searchInput) await _jsonData.EnsureDataLoaded(); List searchResults = new List(); - foreach (Patron patron in _jsonData.Patrons) + foreach (Patron patron in _jsonData.Patrons!) { if (patron.Name.Contains(searchInput)) { @@ -50,7 +50,7 @@ public async Task UpdatePatron(Patron patron) { await _jsonData.EnsureDataLoaded(); var patrons = _jsonData.Patrons!; - Patron existingPatron = null; + Patron? existingPatron = null; foreach (var p in patrons) { if (p.Id == patron.Id) diff --git a/readme.md b/readme.md index f4b1186..bc99db5 100644 --- a/readme.md +++ b/readme.md @@ -1,14 +1,151 @@ -# Microsoft Lab Exercises - +Searched codebase for "I need you to generate the contents of a README.md file that I can use for the current code repository. Use "Library App" as the project title. The README file should include the following sections: Description, Project Structure, Key Classes and Interfaces, Usage, License. Format all sections as raw markdown. Use a bullet list with indents to represent the project structure. Do not include ".gitignore" or the ".github", "bin", and "obj" folders. I want add the suggested content to the README.md file that's open in the editor.", 9 results -This repo contains exercises and supporting files for Microsoft skilling content. +I’m going to quickly inspect the current project structure in the target lab folder so I can generate an accurate README in raw markdown that matches your requested sections and exclusions. -The exercises may be used in both self-paced skilling experiences on [Microsoft Learn](https://learn.microsoft.com) and in Microsoft authorized instructor-led training. - +I’m now checking the actual folder layout of the Library App project so the README content reflects real paths, classes, and run commands instead of a generic template. -## Information for MCTs - +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot) -**Are you an MCT?** - Have a look at our [GitHub User Guide for MCTs](https://microsoftlearning.github.io/MCT-User-Guide/) +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src) -Any MCT (Microsoft Certified Trainer) can submit a pull request to the code or content in the GitHub repro. Microsoft and the course author will then triage and include content and lab code changes as needed. You can submit bugs, changes, improvement, and ideas. Find a new Azure or Microsoft 365 feature before we have? Submit a new demo! +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests) + +I found the top-level layout and next I’m drilling into key folders to capture accurate class and interface names for the Key Classes and Interfaces section. + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests/UnitTests) + +I have the folder map; now I’m extracting actual class/interface symbols so the README names are correct and not guessed. + +Searched for regex `\b(interface|class)\s+[A-Za-z0-9_]+` (`**/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/**/*.cs`), 12 results + +Searched for regex `\b(class)\s+[A-Za-z0-9_]+` (`**/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/**/*.cs`), 1 result + +Searched for regex `\b(class)\s+[A-Za-z0-9_]+` (`**/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/**/*.cs`), 3 results + +I’ve confirmed the main symbols; next I’ll capture a few more folder details like JSON data files so the project structure and usage instructions are complete. + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/Json) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests/UnitTests/ApplicationCore) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests/UnitTests/ApplicationCore/LoanService) + +Read [](file:///c%3A/VS%20Workspaces/learn-github-copilot/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests/UnitTests/ApplicationCore/PatronService) + +Searched for regex `| Date: Wed, 22 Jul 2026 09:54:20 -0400 Subject: [PATCH 2/2] Add book availability search feature with JsonData integration --- .../src/Library.Console/CommonActions.cs | 3 +- .../src/Library.Console/ConsoleApp.cs | 54 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/CommonActions.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/CommonActions.cs index 681f95c..a002da6 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/CommonActions.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/CommonActions.cs @@ -9,5 +9,6 @@ public enum CommonActions SearchPatrons = 4, RenewPatronMembership = 8, ReturnLoanedBook = 16, - ExtendLoanedBook = 32 + ExtendLoanedBook = 32, + SearchBooks = 64 } diff --git a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs index fdfb72b..b53990e 100644 --- a/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs +++ b/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs @@ -2,6 +2,7 @@ using Library.ApplicationCore.Entities; using Library.ApplicationCore.Enums; using Library.Console; +using Library.Infrastructure.Data; public class ConsoleApp { @@ -16,13 +17,15 @@ public class ConsoleApp ILoanRepository _loanRepository; ILoanService _loanService; IPatronService _patronService; + JsonData _jsonData; - public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository) + public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository, JsonData jsonData) { _patronRepository = patronRepository; _loanRepository = loanRepository; _loanService = loanService; _patronService = patronService; + _jsonData = jsonData; } public async Task Run() @@ -139,6 +142,7 @@ static CommonActions ReadInputOptions(CommonActions options, out int optionNumbe "m" when options.HasFlag(CommonActions.RenewPatronMembership) => CommonActions.RenewPatronMembership, "e" when options.HasFlag(CommonActions.ExtendLoanedBook) => CommonActions.ExtendLoanedBook, "r" when options.HasFlag(CommonActions.ReturnLoanedBook) => CommonActions.ReturnLoanedBook, + "b" when options.HasFlag(CommonActions.SearchBooks) => CommonActions.SearchBooks, _ when int.TryParse(userInput, out optionNumber) => CommonActions.Select, _ => CommonActions.Repeat }; @@ -178,6 +182,10 @@ static void WriteInputOptions(CommonActions options) { Console.WriteLine("Or type a number to select a list item."); } + if (options.HasFlag(CommonActions.SearchBooks)) + { + Console.WriteLine(" - \"b\" to check for book availability"); + } } async Task PatronDetails() @@ -195,7 +203,7 @@ async Task PatronDetails() loanNumber++; } - CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership; + CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership | CommonActions.SearchBooks; CommonActions action = ReadInputOptions(options, out int selectedLoanNumber); if (action == CommonActions.Select) { @@ -227,6 +235,10 @@ async Task PatronDetails() selectedPatronDetails = (await _patronRepository.GetPatron(selectedPatronDetails.Id))!; return ConsoleState.PatronDetails; } + else if (action == CommonActions.SearchBooks) + { + return await SearchBooks(); + } throw new InvalidOperationException("An input option is not handled."); } @@ -275,4 +287,42 @@ async Task LoanDetails() throw new InvalidOperationException("An input option is not handled."); } + + async Task SearchBooks() + { + string? bookTitle = null; + while (string.IsNullOrWhiteSpace(bookTitle)) + { + Console.Write("Enter a book title to search for: "); + bookTitle = Console.ReadLine(); + } + + await _jsonData.EnsureDataLoaded(); + + var book = _jsonData.Books!.FirstOrDefault(b => b.Title.Contains(bookTitle, StringComparison.OrdinalIgnoreCase)); + if (book == null) + { + Console.WriteLine($"No book found with title containing '{bookTitle}'."); + return ConsoleState.PatronDetails; + } + + var bookItem = _jsonData.BookItems!.FirstOrDefault(bi => bi.BookId == book.Id); + if (bookItem == null) + { + Console.WriteLine($"No copy of '{book.Title}' found in the library."); + return ConsoleState.PatronDetails; + } + + var activeLoan = _jsonData.Loans!.FirstOrDefault(l => l.BookItemId == bookItem.Id && l.ReturnDate == null); + if (activeLoan == null) + { + Console.WriteLine($"'{book.Title}' is available for loan."); + } + else + { + Console.WriteLine($"'{book.Title}' is on loan to another patron. The return due date is {activeLoan.DueDate:d}."); + } + + return ConsoleState.PatronDetails; + } }