DEV Community

Cover image for CodeBehind framework is faster than ASP.NET Core
elanatframework
elanatframework

Posted on

CodeBehind framework is faster than ASP.NET Core

Based on tests conducted by Elanat Framework, the CodeBehind framework is faster than the default cshtml structure in ASP.NET Core.

In this performance test, we examine the performance of the default ASP.NET Core structure compared to CodeBehind. This review was done on .NET Core version 7.0 and CodeBehind version 1.5.2. This review is only focused on view section in MVC; In version 1.5.2 of CodeBehind, we need to specify the Controller class in the view section.

Classes and codes of the examined frameworks

ASP.NET Core

cshtml

@page
@{
    Random rand = new Random();
}

<div>
    <h1>@rand.Next(1000000)</h1>
</div>
Enter fullscreen mode Exit fullscreen mode

The above codes are repeated in 10 pages (page1, page2, page3, ..., page10)

Program.cs class

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

app.MapRazorPages();

app.Run();
Enter fullscreen mode Exit fullscreen mode

CodeBehind

aspx

<%@ Page Controller="PerformanceTestCodeBehind.DefaultController" %>
<%Random rand = new Random();%>

<div>
    <h1><%=rand.Next(1000000)%></h1>
</div>
Enter fullscreen mode Exit fullscreen mode

The above codes are repeated in 10 pages (page1.aspx, page2.aspx, page3.aspx, ..., page10.aspx)

Controller

using CodeBehind;

namespace PerformanceTestCodeBehind
{
    public partial class DefaultController : CodeBehindController
    {
        public void PageLoad(HttpContext context)
        {

        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Note: Controller is required in CodeBehind framework version 1.5.2

Program.cs class

using CodeBehind;
using SetCodeBehind;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

CodeBehindCompiler.Initialization(true);

app.Run(async context =>
{
    CodeBehindExecute execute = new CodeBehindExecute();
    await context.Response.WriteAsync(execute.Run(context));
});

app.Run();
Enter fullscreen mode Exit fullscreen mode

Test methods

  • Almost 2 minutes before running the tests, we checked the systems installed on the web server at least once to make sure that the systems are not sleeping.
  • In this test, we also checked the number of answers in a fixed time and the elapsed time for the number of fixed answers.

Performance test based on the time elapsed after 10,000 responses

using CodeBehind;

namespace PerformanceTestCsHtmlVSCodeBehind
{
    public partial class DefaultController : CodeBehindController
    {
        public void PageLoad(HttpContext context)
        {
            DateTime startTime = DateTime.Now;
            Random rand = new Random();
            HttpClient webClient = new HttpClient();

            string DataValue = "";

            for (int i = 0; i < 10000; i++)
            {
+                DataValue = webClient.GetStringAsync("http://192.168.1.4/page" + rand.Next(1,10) + ".aspx").Result; // CodeBehind aspx
+                DataValue = webClient.GetStringAsync("http://192.168.56.1/page" + rand.Next(1,10)).Result; // ASP.NET Core Defualt cshtml
            }

            DateTime endTime = DateTime.Now;
            TimeSpan duration = endTime.Subtract(startTime);

            Write("Duration: " + duration.TotalMilliseconds + " ms - LastDataValue: " + DataValue);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Please note that each line of code specified in the class above has been tested separately.

Performance table by miliseconds (Lower is better)

10,000 responses
Performance table by miliseconds - 10,000 responses

CodeBehind is 3.64% better

Average for 20,000 responses
Performance table by miliseconds - 20,000 responses

CodeBehind is 8.1% better

Performance test based on the number of responses after 10 seconds

using CodeBehind;

namespace PerformanceTestCsHtmlVSCodeBehind
{
    public partial class DefaultController : CodeBehindController
    {
        public void PageLoad(HttpContext context)
        {
            DateTime startTime = DateTime.Now;
            Random rand = new Random();
            HttpClient webClient = new HttpClient();

            string DataValue = "";
            int i = 0;

            while ((DateTime.Now - startTime).TotalMilliseconds < 10000)
            {
+                DataValue = webClient.GetStringAsync("http://192.168.1.4/page" + rand.Next(1, 10) + ".aspx").Result; // CodeBehind
+                DataValue = webClient.GetStringAsync("http://192.168.56.1/page" + rand.Next(1,10)).Result; // ASP.NET Core Defualt

                i++;
            }

            Write("RunCount: " + i + " - LastDataValue: " + DataValue);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Please note that each line of code specified in the class above has been tested separately.

Performance table by number of responses (Higher is better)

10 seconds
Performance table by number of responses - 10 seconds

CodeBehind is 6.78% better

Average for 20 seconds
Performance table by number of responses - 20 seconds

CodeBehind is 7.54% better

Conclusion

As it turns out, CodeBehind outperforms the default ASP.NET Core architecture.

Interestingly, the superiority of CodeBehind over the default structure of ASP.NET Core is not a linear graph, and the higher the number of requests over time, the greater the graph of superiority is drawn towards CodeBehind.

Related links

CodeBehind on GitHub:
https://github.com/elanatframework/Code_behind

Get CodeBehind from NuGet:
https://www.nuget.org/packages/CodeBehind/

Top comments (2)

Collapse
 
elanatframework profile image
elanatframework • Edited

This issue has already been tested

HttpClient is definitely slow, which is probably why async becomes pointless. If you can think of another way to test, please let me know.

Edit: Of course, I must add that in this test, Result is used at the end of the GetStringAsync method; At first glance, it is not clear in the test code and requires horizontal scrolling.

According to the change in the test, all the return values are added to the output respectively and nothing is forgotten!

while ((DateTime.Now - startTime).TotalMilliseconds < 2000)
{

+   DataValue += i + webClient.GetStringAsync("http://192.168.1.3/page" + rand.Next(1, 10) + ".aspx").Result; // CodeBehind
+   DataValue += i + webClient.GetStringAsync("http://192.168.56.1/page" + rand.Next(1, 10)).Result; // ASP.NET Core Defualt

    i++;
}
Enter fullscreen mode Exit fullscreen mode
RunCount: 2930 - LastDataValue: 0
<div>
    <h1>83977</h1>
</div>1
<div>
    <h1>189718</h1>
</div>2
<div>
    <h1>716868</h1>
</div>3
...
...
...
</div>2929
<div>
    <h1>701236</h1>
</div>
Enter fullscreen mode Exit fullscreen mode

and for 10 seconds

Test in 10 seconds

Even if your case happens in practice, nothing changes and still CodeBehind is faster than default cshtml pages in ASP.NET Core.

Edit: I mean that even if CodeBehind superior results are obtained in async conditions, the results are still reliable because CodeBehind accepts more requests.

Thank you for your attention.

Collapse
 
vahidn profile image
Vahid Nasiri

Just calling the webClient.GetStringAsync() method without an await, means fire and forget. It won't wait to return anything and you are not measuring anything correctly. Also using a new instance of HttpClient each time here, will saturate the connection pool very quickly.