Conversation
chrisjamiecarter
left a comment
There was a problem hiding this comment.
Hey @m1chael888 👋,
Excellent work on your Drinks Info project submission 🎉!
I have performed a peer review. Review/ignore any comments as you wish.
Your code demonstrates solid understanding of C# fundamentals and software architecture principles. The use of dependency injection, separation of concerns (Controllers/Services/Views), and the Spectre.Console library for a polished UI are particularly impressive. The project structure is clean and follows good practices.
Project-Wide Patterns:
-
Critical Bug in Extensions.cs - The GetDescription method will crash when an enum value has no DescriptionAttribute
-
Blocking Async Pattern - Using
.Resultinstead ofawaitin DrinksService -
Silent Failures - API errors return empty lists without any indication of what went wrong
-
Namespace Syntax - As per the academy's code-conventions, use file-scoped namespaces. From C# 10, we are able to remove the block/braces and save on level of indentation, optimising space and improving readability.
Critical Issue:
- The
Enums.Extensions.GetDescriptionmethod has a bug that will throwIndexOutOfRangeExceptionwhen an enum value lacks a Description attribute. The fallback should returnvalue.ToString()instead of accessingattributes[0].
Please fix the 🔴 critical bug in Enum.Extensions.cs, as it could cause a runtime crash. Once that's addressed, this is an excellent submission that demonstrates good architectural practices!
Please fix any 🔴 items, as they block approval. Commit and push your changes, then leave me a comment when done! 🔧
Thanks,
@chrisjamiecarter 👍
| { | ||
| return attributes[0].Description; | ||
| } | ||
| return attributes[0].Description; |
There was a problem hiding this comment.
🔴 Potential IndexOutOfRangeException Bug
💡 The GetDescription method has a logic error. When no DescriptionAttribute is found, it still tries to access attributes[0].Description, which will throw an IndexOutOfRangeException. Fix by returning the enum name instead:
if (attributes.Length > 0)
{
return attributes[0].Description;
}
return value.ToString();| @@ -0,0 +1,19 @@ | |||
| using DrinksInfo.m1chael888.Controllers; | |||
|
|
|||
| namespace DrinksInfo.m1chael888.Infratrstructure | |||
There was a problem hiding this comment.
🟠 Folder Name Typo
💡 The folder is named "Infratrstructure" instead of "Infrastructure". Consider renaming it to maintain professionalism and avoid confusion.
| { | ||
| var client = new RestClient(_drinkClient); | ||
| var request = new RestRequest("list.php?c=list"); | ||
| var response = client.ExecuteAsync(request); |
There was a problem hiding this comment.
🟠 Blocking Async Call
💡 Using .Result on an async operation blocks the thread and can cause deadlocks in certain scenarios. Prefer await for async operations:
var response = await client.ExecuteAsync(request);Remember to mark the method as async and return Task<List<Category>>.
| private readonly string _drinkClient = "https://www.thecocktaildb.com/api/json/v1/1/"; | ||
| public List<Category> GetCategories() | ||
| { | ||
| var client = new RestClient(_drinkClient); |
There was a problem hiding this comment.
🟠 RestClient Instantiation in Method
💡 Creating a new RestClient instance on every method call is inefficient. Consider injecting IRestClient as a singleton or creating it once in the constructor for better performance and resource management.
| var request = new RestRequest("list.php?c=list"); | ||
| var response = client.ExecuteAsync(request); | ||
|
|
||
| if (response.Result.StatusCode == System.Net.HttpStatusCode.OK) |
There was a problem hiding this comment.
🟠 Silent Failure on API Error
💡 When the API returns a non-OK status code, the method silently returns an empty list. Consider throwing an exception or logging the error so callers can handle failures appropriately.
| { | ||
| public class Drink | ||
| { | ||
| public string strDrink { get; set; } |
There was a problem hiding this comment.
🟡 Nullable Property Warnings
💡 The model properties generate CS8618 nullable warnings. Consider initializing them or marking them as nullable:
public string strDrink { get; set; } = string.Empty;
// OR
public string? strDrink { get; set; }| { | ||
| Console.OutputEncoding = Encoding.UTF8; | ||
|
|
||
| var collection = new ServiceCollection(); |
There was a problem hiding this comment.
🟢 Dependency Injection Setup
⭐ Great use of Microsoft.Extensions.DependencyInjection! This shows good understanding of dependency injection principles and makes the application testable and maintainable.
| MainMenuOption ShowMainMenu(); | ||
| void ShowAccessError(string msg); | ||
| } | ||
| public class DrinksView : IDrinksView |
There was a problem hiding this comment.
🟢 Clean UI Implementation
⭐ Excellent use of Spectre.Console for building a polished console UI! The SelectionPrompt usage with custom converters creates a professional user experience.
| { | ||
| private IDrinksView _drinksView; | ||
| private IDrinksService _drinksService; | ||
| public DrinksController(IDrinksView tableView, IDrinksService drinksService) |
There was a problem hiding this comment.
🟢 Separation of Concerns
⭐ Nice separation between controller logic and view logic. The controller handles user choices while delegating display responsibilities to the view - this follows the MVC pattern well.
|
|
||
| namespace DrinksInfo.m1chael888.Enums | ||
| { | ||
| public static class MainMenuEnums |
There was a problem hiding this comment.
🟢 Enum with Descriptions
⭐ Good use of the DescriptionAttribute pattern for displaying user-friendly text in the UI. This keeps display logic separate from the enum values themselves.
Thanks :)