Exploring User Interface (WPF)

Last week, I had the opportunity to explore the user interface of sandbox project. Mr. Peter assigned me a few tasks, one of which was to add a filter to an entity list in the view model, incorporating search functionality and page numbers. As usual, he provided me with a code example of a complete view model to learn from, which was very helpful.

From studying the example view model, I identified several important aspects that I should pay attention to. These include dependency injection, data binding, mapping, working with a DataGrid, and handling events.

Dependency injection, as I mentioned last week, is a crucial concept in the MVVM architecture. It promotes loose coupling, enhances maintainability, and facilitates testing. In the context of the view model, dependency injection involves providing the required dependencies (such as services, data repositories, or other objects) to the view model from an external source, typically through constructor parameters.

The use of a datagrid in the view model suggests that the view presents tabular data or a grid-like structure. A datagrid is a UI control that enables the display and manipulation of tabular data, typically in the form of rows and columns. The view model would provide the necessary data and commands to populate and interact with the datagrid in the view.

Data binding is another essential aspect of MVVM. It establishes a connection between the view and the view model, allowing for seamless synchronization of data changes between the two. With data binding, it bind properties of UI elements in the view to properties in the view model. When the bound properties change in the view model, the corresponding UI elements in the view automatically update, and vice versa.

Mapping is often used in view models to transform and adapt data between different representations. During a method that specifically require mapping, the entities are retrieved from the data source, mapped to view models using AutoMapper, and further processed or filtered as needed. Finally, the view models are assigned as the data source for the view, allowing them to be bound to UI controls and displayed to the user. Since I’m using AutoMapper, I also needed define mapping profiles that specify how properties from a source object should be mapped to properties in a destination object. These profiles can be configured with mapping rules, such as explicitly defining how specific properties should be mapped or specifying custom transformations using lambda expressions.

Lastly, events play a crucial role in MVVM for handling user interactions and notifying the view model of various actions or state changes. Events can be raised in the view when certain user actions occur, such as button clicks or selection changes, and the view model subscribes to these events to perform the appropriate actions or update its internal state accordingly.

Overall, by understanding these concepts and their application in the example view model had assist me in implementing the requested features, that is adding a filter with search functionality and pagination to the entity list in the sand box user interface.

WPF, MVVM and Prism

Last week, I embarked on a task to learn and discover the wonders of WPF (Windows Presentation Foundation), MVVM (Model-View-ViewModel), and Prism. I was thrilled to dive into these concepts, eager to expand my knowledge and enhance my skills. My first instinct was to turn to YouTube, so that I can grab a quick viewpoint of the concept before diving into the details.

I stumbled upon a video that aimed to teach XAML, the declarative markup language used in WPF. The video also touched upon the usage of code-behind, which involves writing code directly in the code-behind file of a XAML-based application. However, Mr. Peter advised focusing on MVVM rather than code-behind because the system we are now utilizing relies heavily on MVVM rather than code-behind. One of the significant reasons why MVVM was used instead was because by utilizing MVVM, we can effectively test the code. On the other hand, if we rely heavily on code-behind, it becomes challenging to isolate and test the code in a systematic manner. Code-behind tightly couples the user interface (View) and the underlying logic, making it difficult to isolate and verify specific functionalities independently. This lack of separation of concerns impedes the ability to write targeted unit tests, as the code-behind files often contain UI-related code that is tightly coupled with the View. 

MVVM stands for Model-View-ViewModel, and it provides a clear separation of concerns, making the codebase more maintainable, testable, and scalable. It promotes a clean architecture that isolates the business logic (ViewModel) from the user interface (View), with the Model representing the data and functionality. By adhering to MVVM principles, we can achieve a modular and extensible codebase. The ViewModel acts as a bridge between the Model and the View, ensuring efficient communication and decoupling of components. This separation is what allows for easier unit testing, as we can test the ViewModel independently of the View. Therefore, adopting MVVM promotes testability by providing a clear separation between the UI and the business logic, facilitating the creation of robust and easily testable code.

Hence, I centred my attention to grasping the skill of properly using XAML and the MVVM pattern effectively. XAML, an XML-based markup language, empowers developers to define user interfaces in a declarative manner, enhancing productivity and fostering a better collaboration between designers and developers. As I delved deeper into XAML, I was fascinated by its versatility. It provided me with a powerful set of tools to create rich and interactive user interfaces, with its support for data binding, styling and much more. Data binding, for example, is what fascinated me the most. In the context of MVVM, data binding allows for automatic updating of UI elements when the underlying data changes, and vice versa. We also don’t need to manually update the UI or handle events to keep it in sync with the data. 

Data binding supports various modes, such as OneWay and TwoWay, providing flexibility in how data flows between the ViewModel and the View. OneWay binding updates the UI when the source property changes, while TwoWay binding allows changes in the UI to propagate back to the source property. By utilizing data binding, we can create dynamic and responsive user interfaces without writing extensive code for manual updates. It simplifies the development process, enhances code maintainability, and promotes a separation of concerns between the UI and the underlying data logic.

While exploring Prism, a framework for building composite applications in WPF and other XAML-based platforms, I was introduced to its modularity and navigation capabilities. Prism embraces the MVVM pattern and offers a range of features that streamline application development, including dependency injection, event aggregation, and region management. It enables the creation of scalable and maintainable applications with ease. 

Throughout this journey, I realised that grasping the fundamental ideas and patterns is like exploring a vast realm of potential. It is not enough to know how to create code or utilise certain tools, it is also necessary to understand the basic principles that form these technologies.

Creating a Get Query for an Entity

For the past few weeks, I’ve been learning and expanding my knowledge of the CQRS pattern. Under the guidance of Mr. Peter, I have been steadily progressing in my understanding of CQRS. This week, my focus was on implementing the final components of the pattern: the “Get by Id” and “Get List” functionalities for an entity.

First, I created the Get List Query Handler class. This class implements the IRequestHandler interface and is responsible for handling the query to retrieve a list of entities. It utilizes the IMapper and a specific service interface. Then, within the Handle method, I first check if the search name provided in the query is null and assign an empty string if necessary. This allows for more flexible search functionality. Next, I call a service to read the paged entity based on the search criteria and pagination details provided in the query.

To prepare the response, I use AutoMapper to map the retrieved list of entities to a list of the entity Dto objects. Additionally, I fetch the total count of entities that match the search criteria to assist with pagination. Finally, I return a PagedDto object containing the count, the mapped list, and the page and size information from the query. 

Moving on to the Get Query By Id Handler class, which handles the query to retrieve a specific entity by its ID. Similar to the previous handler, it implements the IRequestHandler interface and relies on the IMapper and service interfaces. Inside the Handle method, I perform validation using the Get Query Validator. If any validation errors occur, I throw an InvalidOperationException with the corresponding error messages. Otherwise, I proceed to retrieve the entity using the service based on the supplied Id in the query. If an entity is found, I map it to the Dto using AutoMapper and return the result. However, if the entity is not found, I return null to indicate that no entity with the specified ID exists.

To ensure the correctness of my implementation, I have also included a couple of unit tests. These tests verify the success scenarios for both the Read By Id and Read List methods. They utilize a client to simulate HTTP requests and check the returned status codes and data.

In addition to the query handlers and tests, I have also expanded my knowledge by implementing another implementation of the service interface. This interface serves as the abstraction for fetching entities based on various criteria, and I made sure to create the methods in asynchronous form as advised by Mr Peter.

The added methods in the service interface provide the flexibility to retrieve entities by ID, search name, and pagination. For example, the ReadByIdAsync method accepts an ID as a parameter and fetches the corresponding entity asynchronously. It utilizes the underlying data access layer, to retrieve the entity. Similarly, the ReadPagedByAsync method takes parameters such as a search name, page number, and page size to perform a paged retrieval of entities based on the search criteria.

Overall, by implementing these methods in an asynchronous manner, I ensure that the retrieval operations can be performed efficiently and non-blocking. This enables better scalability and responsiveness in the application, especially when dealing with a large number of entities or concurrent requests. Moving forward, my next task involves delving into the UI aspect, where I will embark on learning about WPF, MVVM, and Prism.

Testing Update and Delete Command

Last week, early in the week, I focused on testing the update command handler for an entity. I conducted a total of 6 tests. The first test verified the successful update of an entity without contact information. I checked the HTTP status code returned by the update API, which should be 200 (OK). I also made assertions on the updated data to ensure the changes were applied correctly.

The second test handled scenarios where an update was attempted on an entity with an invalid ID. The update API was called with an invalid ID, and the application was expected to return a 400 (BadRequest) status code. The test also validated the error message received against the expected error message for an invalid entity.

I also conducted tests focusing on updating entities with various contact scenarios. This included updates involving multiple contacts, a single contact, and adding new contacts while retaining existing ones. The last test addressed cases where duplicate contacts were provided during the update process. By intentionally supplying duplicate contacts, I expected the application to detect this duplication and return a 400 (BadRequest) status code. The error message received was also validated against the expected error message for duplicate contacts.

After completing the tests for the update command handler, I moved on to the next task, which involved implementing the delete command. This command encapsulates the necessary information to delete an entity, including identification, associated user, code, name, creation timestamp, ID, contact details, and default settings. To handle the delete command, I implemented the delete command handler, which is responsible for processing the command.

The handler uses a service interface to perform the deletion of the entity. The delete command is first validated using the delete command validator, ensuring that required fields such as the entity’s ID are provided and valid. If the command passes validation, I retrieve the entity using its ID from the service interface. If the entity is not found, an exception indicating an invalid entity is thrown. If the entity exists, a transaction is initiated to delete the entity by invoking the appropriate method on the service interface. After successful deletion, the transaction is completed by performing an audit using the provided ID.

To ensure the correctness of the implementation, I created two unit tests for the delete command. The first test verifies the successful deletion of a valid entity. It retrieves the entity from the service, sends a delete request to the API endpoint, and asserts that the entity no longer exists after deletion.

The second test checks the behavior when attempting to delete an entity with an invalid ID. It sends a delete request to the API endpoint with an invalid ID and asserts that a BadRequest response is received. The response is then deserialized into an ErrorDto object, and the error message is checked against the expected error message for an invalid ID.

For this week, my focus will be on continuing on Get command implementation. Additionally, I will also begin on learning and familiarizing myself with the UI, as instructed by Mr. Peter.

Update Command Handler

In the previous week, after I finished a task of create command handler for an entity, I continued on the next part which is the update command handler, which is for handling update operations on the entity. The update command handler plays a crucial role in ensuring that the entity’s data remains accurate and up to date.

Initially, I assumed that the command handler for creating and updating entities would follow a similar pattern. However, Mr. Peter pointed out the distinct responsibilities of the update command handler, prompting me to gain a deeper understanding of its requirements. One of the challenges I faced was developing a method to identify the exact entity instance that needed to be updated. Considering that the update operation can impact various properties of the entity, it was crucial to adopt a robust approach capable of handling different update scenarios effectively.

To address this challenge, I implemented the FirstOrDefault() method, allowing me to locate the ID of the entity instance intended for modification. This approach ensured that the update command handler acted on the correct data, precisely targeting the entity in question. Additionally, I prioritized improving the update command handler’s overall functionality by incorporating error handling mechanisms. I implemented appropriate exception handling and error reporting to provide clear and informative feedback to users in case of any issues during the update operation. This helped in facilitating prompt troubleshooting and resolution of any potential problems.

Moving forward next week, I plan to continuously refine and optimize the update command handler, particularly during the unit testing phase, as it provides valuable insights into the evolving requirements.

Exploring Unit Testing for Entity Creation

Last week, I was fully focused on testing the Create Command functionality of an entity. Along the way, I gained a deeper understanding of the importance of unit testing. Creating unit tests allowed me to explore different scenarios and cover as many possibilities as possible with the guidance of Mr. Peter.

In the initial test, I ensured that an entity could be created successfully even without providing any contact details. The accuracy of saving the entity information in the database was verified, along with confirming the receipt of the expected response. Building on that, the next test included a phone contact. I validated that the entity and contact details were accurately saved and associated with each other.

Moreover, with Mr. Peter’s expert guidance, I took on the challenge of creating an entity with multiple entity contacts, then specifically designating one of them as the phone contact. His insights helped me navigate the complexities involved in ensuring the proper association of the chosen contact with the entity and the flawless storage of all entity contacts in the database. Throughout these tests, to validate the expected behavior of the test methods, I used the FluentAssertions library, making assertions with confidence.

Overall, this tests successfully validated the entity creation and contact management functionalities. These tests covered a range of scenarios, including entities without contacts, entities with phone contacts, entities with multiple contacts, and entities with fax contacts. The results obtained from these tests provide a solid foundation for maintaining the integrity of the entity-related features within the application.

Unit Testing

Once the creation of Create command for an object was finished, I continued on building the unit test. Unit testing is an important part of software development because it helps to ensure that the code is working correctly and meets the requirements of the system we’re building.

Unit testing is also crucial for maintaining the quality of code over time. It allows developers to test new features or changes made to the system and detect any regression bugs or unexpected side effects.

To test the Create command, I started with the simplest test. Firstly, in the unit test, I created a test environment for the application to run in. Then, I initialized a set of data by creating an array of entity objects and added them to the database using the AddRange() method then called SaveChanges() method to save the changes to the database.

Next, I created a new test method that simulated the creation of a new object by sending a POST request to the object controller API endpoint with a CreateCommand object containing the necessary details. The test method checked whether the response status code was OK, which confirmed that the object was successfully created. It also checked whether the created object ID was not equal to 0, which confirmed that a new object was indeed created. Additionally, the test method checked whether the number of objects in the database increased by one by retrieving the count of objects before and after the creation of the new object using the AsNoTracking method.

To summarize, unit testing plays a critical role in verifying that the code is functioning correctly and meets the system requirements. Moving forward next week, I will continue creating unit tests, to detect any bugs or errors early on. By thoroughly testing the system, I can ensure that it functions as intended and meets the necessary specifications.

Creating CRUD using CQRS Pattern (part 2)

Last week, in order to create a Create command for an entity, I first needed to create four components: CreateCommand, CreateCommandHandler, CreateCommandResponse, and CreateCommandValidator.

CreateCommand represents the command itself and contains all the necessary data required to create a new entity in the system, including things like the entity’s name, description, and other important details. This was where I also learned something new about using a question mark when defining a property (e.g., public int? Age { get; set; }). The “?” symbol allows the property to be set to null if no information is available.

Next, I created the CreateCommandHandler, which is responsible for handling the CreateCommand and performing the necessary actions to create the entity in the system. It receives the CreateCommand, validates the data, and creates the entity in the appropriate data store. This part of the code (CreateCommandHandler) was challenging for me because I wasn’t sure what code to write, but Mr. Peter helped me understand by using an example from a previous entity. He also pointed out that my difficulty was due to not fully grasping OOP principles.

Then, there’s the CreateCommandResponse, which is the component returned by the CreateCommandHandler after the entity has been successfully created. It contains the ID or other relevant information about the newly created entity. Moving on to next week, I’ll be continuing on creating another component named CreateCommandValidator, which is responsible for validating the data in the CreateCommand before it is processed by the CreateCommandHandler. This component ensures that the data is in the correct format and meets any required constraints.

Together, these four components create a system that is capable of creating new entities within a CQRS-based system. CreateCommand encapsulates all the necessary data, CreateCommandHandler creates the entity, CreateCommandResponse provides information about the newly created entity, and CreateCommandValidator ensures that the data is valid before it is processed.

Creating CRUD using CQRS Pattern (part 1)

This week marked the beginning of my opportunity to apply the knowledge that I gained from the courses that I learnt from the previous weeks. Mr. Peter gave me my first task: creating CRUD for an entity using CQRS pattern. However, before diving into the task at hand, it was necessary to set up the environment by launching the SandBox app, which Mr. Peter graciously guided me through. This included various debugging processes essential for successfully launching the system. First, I needed to create a database and import the existing tables into it. Then, cloned a git repository from an existing repository named Sandbox(which is the main solution used for trying out new features first before implementing it on a real application). There’s also another repo for context and modules under the main repository where this is the first I discover that there can be more repositories created under an existing git repository. 

Launching the Sandbox app took quite some time as there’s a bit of debugging needed which most of it was solved by Mr Peter. One of the issues that arose was due to my carelessness in setting up the credentials of the API. I unwittingly included a space in a word that was not supposed to have one, causing the issue of invalid authentication. From this experience, I learned a valuable lesson that even the slightest error, such as a space, can cause significant time wastage during debugging. As a result, I now realize the importance of paying attention to the smallest of details. 

Throughout the week when I’m completely lost on what to and what should I debug, I instead just go through the codes from an existing project to guide me through creating the CRUD for an entity while also watching the courses again to have deeper understanding on how the code works. Moreover, I learned about a new git method known as git stash, which allows you to temporarily shelve changes you’ve made to your working copy so that you can work on something else and then re-apply them later. When it came time to create the CRUD for the entity, I initially created all folders and pages at once for creating, updating, deleting, and getting information. However, Mr. Peter advised that it would be best to create them one by one and test each unit immediately to ensure the stability of the code before moving on to the next feature.

Overall, I am grateful for the opportunity to learn from Mr. Peter this week. While I feel that I did not make significant progress personally, I am eager to continue learning and growing. I look forward to the challenges that lie ahead, particularly in creating the CRUD for an entity next week.

ASP.Net Core and RESTful API

Last week, I had the opportunity to learn the architecture of ASP.NET Core 3. The first part of the course I was exposed to the importance of separating concerns in an application by organizing code into layers, including the presentation layer, application layer, domain layer, and infrastructure layer. Additionally, I also explored how to implement clean architecture in ASP.NET Core 3 applications, including how to structure the code and how to use interfaces and dependency injection to decouple components so that the code easier to maintain for future usage.

Going to the next part, I started to delved into Automapper, a powerful tool that can simplify the process of mapping data between different objects in the application. I learned how to install and configure Automapper in ASP.NET Core 3 application, and how to use it to map data between entities and DTOs (data transfer objects). Next, a design pattern known as CQRS (Command Query Responsibility Segregation), which divides the duties of managing read and write operations in an application, was the next area of emphasis for me. At first, I struggled to understand the CQRS concept, but Mr. Peter clarified it for me, helping me to understand the idea of it as a whole. I learned about the benefits of CQRS, including how it improved scalability and performance. I even also explored how to use MediatR, a popular library for implementing CQRS in .NET applications.

After few days going through the architecture of ASP.NET, the next 2 and a half day of the week I started to go through a new topic called “Building a RESTful API with ASP.NET Core 3”. I learned about the difference between the Outer Facing Model and the Entity Model. The Outer Facing Model represents the data that will be exposed to clients through the API, while the Entity Model represents the data that is stored in the database. the course also taught on how to map between these two models, and how to use Automapper to simplify the process.

Another key aspect of building a RESTful API is handling HTTP requests, including POST, PUT, and PATCH requests. I learned the differences between these requests and how to handle them in an API. I also explored how to use data annotations and custom validators to validate user input, which is critical for ensuring the integrity of data. Finally, the course covered how to delete a resource in an API, including how to handle deleting a single and related resources in the database.

Overall, the past week learning is quite complex for me. I did gained the understanding of the whole concept and idea of the materials but in term of practicality and codes, I must say I’m still very weak. However, I really look forward on exploring more on these topics and gaining deeper understanding on implementing the knowledge of the ASP.NET architecture and building the RESTful API.