Using Redux in a legacy ASP.NET Web Forms project
Tags: javascript, redux, aspnet, webforms
Published: 2019-08-22 07:36:49

[Redux](https://redux.js.org/) is an implementation of Facebook's [Flux](https://facebook.github.io/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](https://docs.microsoft.com/el-gr/aspnet/web-forms/what-is-web-forms) technology. It is a quite old fashioned technology but we have tried to use some modern tools , like [Typescript](https://www.typescriptlang.org/) and [webpack](https://webpack.js.org/), 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 <code>.ashx</code> 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

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zzf8sraxf4sutgw6gtfq.png)

# 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 <code>window.load</code>, 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.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ch4mps5by6evo49uhmxa.png)

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:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/leecx8km3etywhhn3xn0.png)

# Implementation

Now, lets see how we use Redux in our ASP.NET Web Forms project.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/s7nnyk2ahge90krbdopw.png)

### Initial state

As the user control loads, the backend (<code>.ascx.cs</code>) queries the database, creates an object that represents the initial state, serializes it and stores it in a hidden field.

{% gist https://gist.github.com/kapantzak/0f063097d904c73f30f27aa36460960b file=backend.ascx.cs %}

### Reducers

Before initializing the store object in the <code>.ts</code> file, we have to create some [reducers](https://redux.js.org/basics/reducers) and some [actions](https://redux.js.org/basics/actions).

{% gist https://gist.github.com/kapantzak/0f063097d904c73f30f27aa36460960b file=stateHelper.ts %}

### Create store

The user control loads a specific javascript file which initializes a [Redux store](https://redux.js.org/api/store). We have imported the <code>appReducer</code> from the <code>stateHelper.ts</code> file and we use it to initialize the store.

{% gist https://gist.github.com/kapantzak/0f063097d904c73f30f27aa36460960b file=page.ts %}

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 <code>stateHelper.ts</code> anywhere we want, inside our <code>page.ts</code> file.

{% gist https://gist.github.com/kapantzak/0f063097d904c73f30f27aa36460960b file=page_dispatch.ts %}

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.

{% gist https://gist.github.com/kapantzak/0f063097d904c73f30f27aa36460960b file=page_submit.ts %}


# 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!