Using Redux in a legacy ASP.NET Web Forms project
John Kapantzakis
Posted on August 22, 2019
Redux is an implementation of Facebook's Flux design pattern.
Someone might say "Why use Redux in other than a React app?". It may seems a little strange now, but it helped my team to organize the data flow.
In my current job, I am involved in a project built in ASP.NET Web Froms technology. It is a quite old fashioned technology but we have tried to use some modern tools , like Typescript and webpack, in order to improve the development process.
Application overview
The application uses a Master Page, which is the entry point and loads the appropriate User Control, depending on the url.
Each user control (from now on, we will call it a form) loads the respective javascript file which handles the client's interactions.
The communication with the server is happening via ajax calls to specific files with the .ashx
extension (Generic Handlers), althoug there are some cases that a postback is triggered, causing a full refresh of the page.
Here's a simple overview
The problem
In our project, it is a common case that a form has some filters (Kendo controls), an Apply filters button and a grid that displays the results.
Lets say that we have a form with 3 filters, a combobox for the available departments, a combobox for the employees and a textbox for some comments.
On load, each of these filters is getting some initial data. The two comboboxes get a list of departments and a list of employees, respectively, while the comments textbox gets a string. These datasources have to be retrieved from the database and be strored in some hidden fields on the backend.
On the frontend, on window.load
, the Kendo controls get initialized with the hidden field's values as the datasources.
function initFilters() {
const departments = JSON.parse($('#Hidden_departments').val());
const employees = JSON.parse($('#Hidden_employees').val());
const comments = $('#Hidden_comments').val();
$('#cmb_departments').kendoDropDownList({
data: departments
});
// Same for others ...
}
We can see that each filters gets its datasource from a different point.
The same happens when we want to gather the filters values and submit them to the server. We, again, have to search in different places to get each value, create an object with these values and send it to the server.
function getFiltersValues() {
const departmentVal = $('#cmb_departments').data('kendoDropDownList').value();
const employeeVal = $('#cmb_employees').data('kendoDropDownList').value();
const commentsVal = $('#txt_comments').val();
return {
department: departmentVal,
employee: employeeVal,
comments: commentsVal
}
}
The following diagram illustrates the above process.
So, the problem is that we have to search in many different places in order to get the filters datasources and the filters values, in a sentence:
There isn't a single source of truth!
Using Redux
As opposed to the previous approach, with Redux, we try to maintain a single source of truth. This source is the application state, or better, the user control state, because each user control maintains its own state (we do not implement a universal application state, instead, we treat each user control as a separate application).
The following diagram illustrates the user control's data lifecycle:
Implementation
Now, lets see how we use Redux in our ASP.NET Web Forms project.
Initial state
As the user control loads, the backend (.ascx.cs
) queries the database, creates an object that represents the initial state, serializes it and stores it in a hidden field.
Reducers
Before initializing the store object in the .ts
file, we have to create some reducers and some actions.
Create store
The user control loads a specific javascript file which initializes a Redux store. We have imported the appReducer
from the stateHelper.ts
file and we use it to initialize the store.
After getting the initial state, we can build the ui using the data from our single source of truth, the store!
Updating the state
While having a store object available, we can dispatch the actions declared in the stateHelper.ts
anywhere we want, inside our page.ts
file.
Any time we dispatch an action, the reducer returns an updated copy of our application state. The state itself should never be mutated according to Flux pattern.
Saving data
Now that we have a single source of truth, it is very easy to submit our data to the server. We just have to get the most recent verion of the application state and send it to the generic handler, which, in turn, saves the data to the database.
Conclusion
Despite the relative complexity and steep learing curve, Redux proved to be a helpful tool for our team. Here are some pros and cons that came out of Redux use:
👍 Pros
- Provides a single point of truth
- Use of functional paradigm principles (immutable data, pure functions etc)
- Quick addition / removal of ui controls without unwanted side effects
👎 Cons
- Overkill for small apps
- Steep learing curve (depends on the developer's experiense)
- Initial setup requires some time
It seems that Redux can be used in other than React applications too. If you have similar experiense you may want to drop your comments!
Posted on August 22, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.