Power of Reference in Elanat, vs Middleware in ASP.NET Core
Tags: dotnet, tutorial, csharp, aspdotnet
Published: 2023-10-14 16:36:06

The middleware is placed as an intermediate layer between the request and the response and can perform operations such as changing the request, applying filters, changing the response, etc.

Please note that ASP.NET Core is a framework and [Elanat](https://elanat.net) is a CMS; Our purpose of this comparison is simply to demonstrate the power and flexibility of references in [Elanat](https://github.com/elanatframework/Elanat).


## ASP.NET Core middlewares
Middlewares in ASP.NET Core are components that are placed in the pipeline of requests and can change requests or add something to them and deliver the work to subsequent middlewares to finally send the request to the controller. reach Middleware can perform tasks before and after the next component in the request pipeline has been executed. For example, a middleware can check requests and return the result from the cache if the request is usable from a cache, and forward the request to the next middleware if the request is not available in the cache.

The following link provides a complete description of Middleware in ASP.NET Core:
[https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-7.0](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-7.0)

## Elanat references
The latest version of Elanat is based on ASP.NET Core version 7.0; But Elanat is not built on default cshtml pages and is powered by [CodeBehind](https://github.com/elanatframework/Code_behind) framework. [CodeBehind](https://elanat.net/page_content/code_behind/) is a framework that rides on ASP.NET Core and inherits all the advantages that ASP.NET Core has and gives it more power and flexibility. CodeBehind is based on the MVC pattern and renders aspx files to ASP.NET Core. aspx files are the View section in the MVC pattern.

Thanks to the CodeBehind framework, Elanat references work dynamically. Just as Elanat has created a powerful middleware structure, if you use the CodeBehind framework, you can create a structure where you can add new middleware without rewriting the core of the project.

The most important difference between the Elanat reference and the middleware in ASP.NET Core is that the middleware in .NET Core is static, but the reference in Elanat works dynamically.

There are three types of references in Elanat:

 - Before reference
 - Event reference
 - After reference

**Before load path reference list** checks any selected url before execution and can prevent it from being executed and display the appropriate values in the output.

**Event reference list** in Elanat is mostly added at the end of methods located in model classes and applies the success values that occurred at the end of the request.

**After load path reference list** can execute functions and pages after executing any url that is selected.

The event reference and the post-execution reference are executed simultaneously with the response, but the pre-execution reference controls incoming requests before the Elanat response. Therefore, in this article, we only deal with the reference before implementation.

![Before load path reference list shape](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xdqpgykriva6mgjyhon9.png)

The above figure shows the performance of references before execution in Elanat; References in Elanat are aspx files that are called before routes are executed. These references are added in an XML file at App_Data/before_load_path_reference_list/before_load_path_reference.xml.
This XML file is a list of aspx executables that are executed based on url filters. In this mechanism, it is possible to set a filter on urls based on the path of requests and it allows aspx files to be executed after specific requests.

These filters are based on the following:

- Exist
- Start by
- End by
- Regex match

Each of the aspx files receives HttpContext values and can modify its requests and add the appropriate response and can even leave requests unanswered.

Elanat will prevent the request from continuing if the aspx files return the text response false as the output response.

If there is no false value in the output response of the reference, the next references are checked and if there is no false value in their output response, the request is continued.

Note: You can also call files other than aspx, but you will not have control over the HttpContext.

XML reference tag struct:
```xml
<reference type="url" check_type="page" exist="true" start_by="false" end_by="false" regex_match="false" active="true" reason="reason_message">
    <path_value>/part_of_the_path_string/</path_value>
    <load_value><![CDATA[/middlewares/middleware1/Default.aspx]]></load_value>
</reference>
```

As it is clear in the tags above, the exist attribute is active in the reference tag and the value of the type attribute is url. Enabling the exist attribute means that it checks the existence of input values in the request based on the path_value internal tag. The value of the type attribute can be either url or form. If it is url, the path and query string are checked, and if it is form, the data values of the form are checked; If there is a match, the path of the load_value tag is executed.

## Some examples of before reference in Elanat

### Example 1
Part of the before_load_path_reference.xml file, tags related to content count control.

**Check content count limitation**
```xml
<reference type="form" check_type="page" exist="true" start_by="false" end_by="false" regex_match="false" active="true" reason="content_count_limitation_is_active">
    <path_value>btn_AddContent=</path_value>
    <load_value><![CDATA[/action/system_access/reference/check_content_count_limitation/Default.aspx]]></load_value>
</reference>
```

This reference examines the limitation of the number of content for offensive roles; If the number of user content is equal to or greater than the number specified for the role, the reference writes the value false to the output. In this situation, the response is interrupted and the message of content limit is displayed to the user.

Depending on the system you implement, you can create such references. For example, you can create a reference similar to this reference to limit the number of content per day and hour; You can also set a limit for commenting.

**View**
```html
﻿<%@ Page Controller="Elanat.ActionCheckContentCountLimitationController" %>
```

**Controller**
```csharp
﻿using CodeBehind;
using System.Xml;

namespace Elanat
{
    public partial class ActionCheckContentCountLimitationController : CodeBehindController
    {
        public void PageLoad(HttpContext context)
        {
            CurrentClientObjectClass ccoc = new CurrentClientObjectClass();

            int RoleContentCountLimitation = int.MaxValue;

            XmlDocument doc = new XmlDocument();

            foreach (string Text in ccoc.GetRoleNameList())
            {
                XmlNode node = StaticObject.CurrentRoleLimitationsDocument(Text).SelectSingleNode("limitation_root/limitation_list/limitation[@name='content_count']");

                if (!node.Attributes["active"].Value.TrueFalseToBoolean())
                {
                    Write("true");
                    return;
                }

                if (RoleContentCountLimitation == int.MaxValue)
                    RoleContentCountLimitation = int.Parse(node.Attributes["value"].Value);

                if (RoleContentCountLimitation < int.Parse(node.Attributes["value"].Value))
                    RoleContentCountLimitation = int.Parse(node.Attributes["value"].Value);
            }

            DataUse.Content duc = new DataUse.Content();
            int UserContentCount = duc.GetUserContentCount(ccoc.UserId);

            if(UserContentCount >= RoleContentCountLimitation)
            {
                Write("false");
                return;
            }

            Write("true");
        }
    }
}
```

### Example 2
Part of the before_load_path_reference.xml file, tags related to set install page outside the path access handler.

**Set install page outside the path access handler**
```xml
<reference type="url" check_type="page" exist="false" start_by="true" end_by="false" regex_match="false" active="true" reason="" name="tmp_load_for_install">
	<path_value>/install</path_value>
    <load_value><![CDATA[/action/system_access/reference/set_install_page_outside_the_path_access_handler/Default.aspx]]></load_value>
</reference>
```

In Elanat, there is one group for each user, and each group contains several roles. Each group has a different level of access to the routes; Group and role information is stored in the database; Because there is no access to the database during installation, Elanat uses a reference to output the requested paths to the install directory before checking the access level. This example shows how before access to the install page and the js and css files are checked, they are included in the output. By calling the context.Response.WriteAsync method, which is related to ASP.NET Core, the values of the files are placed in the output.
At the end of the codes, the Write method related to the CodeBehind framework puts the false value in the output to prevent the process from continuing.

Note: In Elanat core, there is not even an additional condition to access the install path, and after the installation process, this reference is disabled.

**View**
```html
﻿<%@ Page Controller="Elanat.ActionSetInstallPageOutsideThePathAccessHandlerController" %>
```

**Controller**
```csharp
﻿using CodeBehind;

namespace Elanat
{
    public partial class ActionSetInstallPageOutsideThePathAccessHandlerController : CodeBehindController
    {
        public void PageLoad(HttpContext context)
        {
            if (string.IsNullOrEmpty(context.Request.Query["path"]))
                return;

            string Path = context.Request.Query["path"].ToString();

            // Check If Database Working
            if (StaticObject.RoleNameNumber.Count > 0)
                return;


            if ((Path == "/install/") || (Path == "/install/Default.aspx"))
                context.Response.WriteAsync(PageLoader.LoadWithServer(StaticObject.SitePath + "install/Default.aspx"));

            if ((Path == "/install/script/install.js"))
            {
                context.Response.WriteAsync(PageLoader.LoadWithText(StaticObject.SitePath + "install/script/install.js"));
                context.Response.ContentType = "text/javascript";
            }

            if ((Path == "/install/style/install.css"))
            {
                context.Response.WriteAsync(PageLoader.LoadWithText(StaticObject.SitePath + "install/style/install.css"));
                context.Response.ContentType= "text/css";
            }


            Write("false");
        }
    }
}
```

## Related links
before_load_path_reference.xml file in Elanat:
[https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/before_load_path_reference_list/before_load_path_reference.xml](https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/before_load_path_reference_list/before_load_path_reference.xml)

event_reference.xml file in Elanat:
[https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/event_reference_list/event_reference.xml](https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/event_reference_list/event_reference.xml)

after_load_path_reference.xml file in Elanat:
[https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/after_load_path_reference_list/after_load_path_reference.xml](https://github.com/elanatframework/Elanat/blob/elanat_framework/wwwroot/App_Data/after_load_path_reference_list/after_load_path_reference.xml)