Introduction
WebForms Core is a bold redefinition of traditional server-side UI models that, by leveraging modern concepts such as:
- Statelessness
- Granular Command Transfer
- Optimal and controlled SSR and CSR combination
- Lightweight and compact semantic protocol
- Command/Execution Abstraction Layer
It attempts to introduce a new standard for web development that both preserves the simplicity of the backend developer and ensures the efficiency and interactivity of the frontend.
WebForms Core vs CodeBehind
WebForms Core is a revolutionary server technology for managing DOM elements in HTML. CodeBehind is a back-end framework under .NET that incorporates WebForms Core technology into its core (with this technology it is full-stack). WebForms Core and CodeBehind both belong to Elanat.
Usually Elanat first develops WebForms Core technology simultaneously with CodeBehind framework and then releases new versions of WebForms classes in other server programming languages. So version 4.3 of CodeBehind framework is released simultaneously with version 1.9 of WebForms Core technology.
Version 1.9 of WebForms Core technology is exactly the same as the previous version, a version with new features. In the future, we will also release version 2.0 with new and diverse features so that WebForms Core technology can achieve a tangible advantage over front-end frameworks. The next versions will also have new features, however, our main focus at Elanat will be to improve the structure of this technology.
New features in CodeBehind version 4.3:
View only in GET method
Version 4.3 comes with a new and useful feature to prevent View submission. In this new feature, when the request is not GET (other methods such as POST and PUT), the View is ignored, but the responses written to the page are included in the server response. This is a structure compatible with WebForms Core technology or front-end frameworks.
This feature is disabled by default and to enable it, you need to set the value of "end_view_only_in_get_method" in the options file located in the "code_behind" directory to "true".
options.ini
[CodeBehind options]; do not change order
view_path=wwwroot
move_view_from_wwwroot=true
rewrite_aspx_file_to_directory=true
...
max_web_socket_connections_per_client=3
web_socket_buffer_size=4096
+send_view_only_in_get_method=false
In this case, there is no need to disable View and Model as well as Layout, because any request that is not a GET method will ignore View and Layout.
Write(form.Response());
-IgnoreLayout = true;
-IgnoreViewAndModel = true;
Write method in View
Although it is easy to display data in the View, however, when the View only in GET method feature is enabled, it is no longer possible to write a response to the output with a View page (you need to add a Controller or Model); to solve this new problem, we have enabled the ability to write data to the View page. The View only in GET method feature considers the data that is written to the page outside the View and these responses are sent.
From now on, you can also write to the output in the View using the "Write" method!
Ignore Layout For PostBack
In this version, we have added the ability to prevent Layout submission to have a powerful structure for building a SPA system. To support this feature, just call the new method "IgnoreLayoutForPostBack". The "IgnoreLayoutForPostBack" method is available in all three parts of the Controller, Model, and View.
As you know, requests in WebForms Core technology are requested with the "Post-Back" header with the value "true"; the function of the "IgnoreLayoutForPostBack" method is that if this header is present, it will not resubmit the Layout. This is a great mechanism to prevent resubmitting the HTML structure template.
IgnoreLayoutForPostBack(context.Request.Headers);
Example
In this example, if the about page is requested for the first time, the HTML is fully generated, but if the same page is requested using the WebForms Core structure (based on SPA links, explained below), the Layout is disabled. Suppose we first call the contact page and then request the about page under WebForms Core, the current Layout remains and the about page without Layout is replaced by the contact page.
Layout ("/layout.aspx")
@page
@islayout
<!DOCTYPE html>
<html>
<head>
<title>@WebSiteName - @ViewData.GetValue("title") page</title>
<script type="text/javascript" src="/script/web-forms.js"></script>
<meta charset="utf-8" />
</head>
<body>
<h1>@WebSiteName - @ViewData.GetValue("title")</h1>
<main>
@PageReturnValue
</main>
</body>
</html>
View
@page
@controller AboutController
@layout "/layout.aspx"
@{
ViewData.Add("title","About");
}
<p>
We are a passionate team dedicated to delivering high-quality digital solutions. Our mission is to help businesses grow by providing innovative web design, software development, and content creation services.
</p>
<p>
With a focus on creativity, integrity, and customer satisfaction, we strive to build long-lasting relationships and create meaningful experiences for our clients.
</p>
In this case you need to include a provision to change the HTML title and also in this example the h1 tag. In this example we are sending two Action Control commands by specifying a simple condition.
Controller (AboutController)
using CodeBehind;
public partial class AboutController : CodeBehindController
{
public void PageLoad(HttpContext context)
{
IgnoreLayoutForPostBack(context.Request.Headers);
if (IgnoreLayout == true) // Note: is {public bool? IgnoreLayout = null;} and {if (IgnoreLayout)} get compiler error
{
WebForms form = new WebForms();
// Consider WebSiteName as a global variable
form.SetHeadTitle($"{WebSiteName} - About");
form.SetText("<h1>", $"{WebSiteName} - About");
Write(form.ExportToWebFormsTag());
}
}
}
Please note that in WebForms Core technology, any data that is not Action Controls (does not have "[web-forms]" at the beginning of the text) is placed in the response location section; the response location is body by default, so since we want the pages to be placed in the "main" tag, we need to change the setting from body to "main" tag. To do this, we need to include the following setting in the WebFormsJS configuration section:
WebFormsJS option section
var PostBackOptions = new Object();
PostBackOptions.UseProgressBar = true;
...
PostBackOptions.UseSPALink = true;
...
function cb_GetResponseLocation()
{
- return document.body;
+ return document.getElementsByTagName("main")[0];
}
New features in WebForms Core version 1.9:
Transient DOM
Transient DOM is a powerful feature added in this release. We promised to add this feature earlier and now we have delivered on our promise.
In Transient DOM, changes are collected and applied once, reducing flicker and reflection. This new feature is created using the Clone feature in JavaScript and makes DOM changes as smooth as virtual DOM in front-end frameworks.
While front-end frameworks like React use Virtual DOM and Angular use Incremental DOM, WebForms Core provides the Transient DOM feature to avoid executing Action Control code hierarchy and minimize direct DOM operations by creating a temporary Clone to hold multiple commands and then apply them to the HTML page.
Example
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Article Page</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/webforms-core/Web_forms/web-forms.js"></script>
</head>
<body>
<p>My Website ...</p>
<div class="container">
<h1>Impact of Artificial Intelligence on Daily Life</h1>
<p><strong>Category:</strong> Technology</p>
<p><strong>Date:</strong> October 2, 2025</p>
<p>
Artificial Intelligence is rapidly transforming the way we interact with technology. From voice assistants to self-driving cars, AI is entering various aspects of our daily lives and creating new opportunities to improve quality of life.
</p>
</div>
</body>
</html>
To use Transient DOM, we first call the "StartTransientDOM" method and we need to set the InputPlace. In this example, the div tag with the class container is selected. Please note that from here on, we only need to manipulate the elements inside the container tag and we do not have access to the outside of the container tag and the root is placed here as container. After writing the commands, we call the "EndTransientDOM" method.
Server code
...
form.StartTransientDOM("{container}");
form.SetBackgroundColor("<h1>", "pink");
form.SetFontSize("<strong>1", 24);
form.SetWidth("<p>2", 300);
form.SetFontName("<p>2", "Tahoma");
form.AddStyle("<p>2", "line-height: 1.5;");
form.EndTransientDOM();
...
Note: In this example, if we do not use the Transient DOM feature, calling the
form.SetWidth("<p>2", 300);
method will cause the width of the third p tag (including the date) of the page to be set!
In this case, to access and manage the main tag (here <div class="container">
), we added a new InputPlace type.
WebForms form = new WebForms();
form.StartTransientDOM("{container}");
form.SetBackgroundColor("<h1>", "pink");
form.SetFontSize("<strong>", 24);
form.SetWidth("<p>2", 300);
form.SetFontName("<p>2", "Tahoma");
form.AddStyle("<p>2", "line-height: 1.5;");
+form.SetBackgroundColor(InputPlace.Root, "lightgreen");
// or form.SetBackgroundColor("~", "lightgreen");
form.EndTransientDOM();
SPA mode
This version has advanced features for state management, including back and forward buttons, and state for storing data such as title, vertical and horizontal position of the page, and changing the URL in the browser, all automatically.
A new option has also been added to the WebFormsJS library settings section to enable SPA links (enabled by default). Enabling this setting will cause all internal links without a target or with a target of type "_self" to automatically work based on the "GetBack" method only.
WebFormsJS option section
var PostBackOptions = new Object();
PostBackOptions.UseProgressBar = true;
...
PostBackOptions.AddLog = true;
PostBackOptions.AddLogForWebSockets = true;
+PostBackOptions.UseSPALink = true;
These features make applications built with WebForms Core have an experience similar to modern SPA applications, without the complexities of heavy frameworks like React or Angular.
In the past, it might have been hard to believe that a server-side technology could have SPA capabilities, but Elanat has proven that it is entirely possible and logical. When SPA first came into being, it was mostly associated with client-side frameworks like React, Angular, or Vue, but now technologies like WebForms Core from Elanat have shown that even server-side architectures can deliver an SPA-like experience with smart design. Advancements in the WebForms Core framework allow for interactions without a full page refresh, and intelligent management of browser state and history creates a smooth and modern experience. This is an amazing transformation.
Note: We will teach SPA feature in a separate article in the future.
Faithful to RESTful
REST (Representational State Transfer) architecture is a design style for web services that uses the HTTP protocol to communicate between a client and a server. In this architecture, resources are identified by URLs and operations such as GET, POST, PUT, and DELETE are used to interact with them. REST is simple, scalable, and platform-independent, and has become very popular due to its clear structure and use of web standards.
In version 1.9 we added several new methods to fully support the REST architecture.
In addition to the PostBack (by sending the POST header) and GetBack (by sending the GET header), the following methods have been added in this version:
- "PutBack" by sending the PUT header
- "PatchBack" by sending the PATCH header
- "DeleteBack" by sending the DELETE header
- "HeadBack" by sending the HEAD header
- "OptionsBack" by sending the OPTIONS header
- "TraceBack" by sending the TRACE header
- "ConnectBack" by sending the CONNECT header
WebForms Core technology now operates completely based on the core principles of the RESTful architecture. This evolution has turned WebForms Core into a powerful platform that is fully compliant with modern web standards.
- Client/Server: The WebForms Core architecture is completely decoupled; communication between the client (WebFormsJS) and the server (WebForms Class) is done through a defined interface.
-
Stateless: Requests are sent via
XMLHttpRequest
and responses are returned as small commands (INI format), independent of the client's previous state. - Cache: For caching, you can use either the SetCache method in the WebForms class on the server or the server's own cache.
- Uniform interface: Interaction with the DOM is done through Action Controls and a specific structure that is considered a uniform interface.
- Layered system: From the perspective of this technology, it makes no difference whether the request reaches a proxy in the middle of the way, is intercepted by an additional layer, or is cached; therefore, it continues to function regardless of the presence or absence of the middle layer.
- Code on demand (optional): The server can send logic to the client in the form of commands to be executed in WebFormsJS, which is completely based on this principle.
Please Note: Interestingly, the server is Stateless but just as powerful as a Stateful server. Also WebForms Core explicitly defines the Code on Demand restriction in REST as optional; the server sends "code" (here INI commands) to the client, which is executed in WebFormsJS. So it implements this restriction in an even stronger way than REST.
Example
Server command
form.SetDeleteEvent("<button>", "onclick", "/products/1");
Handle the request on the server
using CodeBehind;
public partial class ProductsController : CodeBehindController
{
public void PageLoad(HttpContext context)
{
if (context.Request.Method == "DELETE")
{
string Id = Section.GetValue(0);
// Delete in Database
// ...
WebForms form = new WebForms();
form.Delete(InputPlace.Target); // or form.Delete("!");
Write(form.Response());
IgnoreLayout = true;
IgnoreViewAndModel = true;
return;
}
if (context.Request.Method == "PUT")
{
// ...
}
}
}
In this example, the SetDeleteEvent
method on the server side defines that when the user clicks on a button, a DELETE
request should be sent to the /products/1
path. This means that the client (WebFormsJS) is RESTful and performs the deletion of the resource using the appropriate method.
On the server side, the ProductsController
controller checks if the request method is DELETE
. If so:
- The product ID is extracted from the request.
- The delete operation is performed from the database.
- Then, using the
WebForms
class, the DOM deletion command is issued on the client (for example, deleting the button or the associated element). - The response is sent to the client as an INI to be executed in WebFormsJS.
This example shows how the DELETE
method can be implemented in a completely RESTful manner using WebForms Core and the execution logic can be moved from the server to the client.
Conditional features for status control
The most important feature of this version is the support for conditions and async and sync functionality for conditions. From now on, commands can be executed or stopped depending on conditions. We have also added the ability to create conditions based on duration to the WebForms Core technology.
Example
In this example, after executing the Confirm command, the dependent commands are executed in Async mode and the dependent commands are executed in Sync mode (and therefore earlier).
Server commands
form.ConfirmIsTrueAccept("Are youe want show success message?");
form.Message("You are accept to show this success message", "success");
We can add customization options to Confirm.
The arguments to the "ConfirmIsTrueAccept" method are:
- The Confirm text.
- The type that determines the color of the Confirm and changes the color to red, yellow, blue, green, and gray with the words warning, problem, help, success, and none (the default is none).
- The Confirm title.
- The word or phrase of the confirmation button.
- Word or phrase Cancel button.
- Interval (default is 100 milliseconds)
Server commands
form.ConfirmIsTrueAccept("Are youe want show three success message?");
form.StartBracket();
form.Message("You are accept to show this success message1", "success");
form.Message("You are accept to show this success message2", "success");
form.Message("You are accept to show this success message3", "success");
form.EndBracket();
Dependent Commands
Dependent commands operate according to conditions in programming languages. If the "StartBracket" method is executed after the conditional feature, if the condition is met, the commands will be executed until they end with the "EndBracket" method, and if the condition is not met, none of them will be executed; therefore, dependent commands in this case are placed between the "StartBracket" method and the "EndBracket" method. If the "StartBracket" method is not used, only the next command is the dependent command.
In addition to Confirm, we can use several other conditional properties, these properties are listed below:
- ConfirmIsTrueAccept - Executes dependent commands after the user clicks the Confirm button
- ConfirmIsFalseAccept - Executes dependent commands after the user clicks the Cancel button
- IsTrue - Executes dependent commands if they are true
- IsFalse - Executes dependent commands if they are not true
- IsGreaterThan - Executes dependent commands if the first data is greater than the second data
- IsLessThan - Executes dependent commands if the first data is less than the second data
- IsEqualTo - Executes dependent commands if the first and second data are equal
- IsRegexMatch - Executes dependent commands if the data is based on a Regex pattern
- IsRegexNoneMatch - Executes dependent commands if the data is not based on a Regex pattern
Apart from Confirm, other conditional properties include Interval for checking The feature is executed sequentially based on the specified time intervals. The Break command is also added in this version and if executed, it prevents the continuation of the Action Control commands.
The function of the "ConfirmIsFalseAccept" method is similar to the "ConfirmIsTrueAccept" method, except that it allows the execution of dependent commands in the event that the user clicks the Cancel button.
Example
In this example, the IsEqualTo function checks whether the generated random number is equal to the desired value, and does this check within a specified time interval (for example, 100 milliseconds). If the condition is met, a success message is displayed using Message to indicate that the random function test was performed correctly. Please note that if we enable Interval, the dependent commands are executed async.
Server commands
form.IsEqualTo(Fetch.Random(0, 100), "1", 100);
form.Message("IsTrue work fine in Random method", "success");
Example
In the following example, we temporarily store the text of the textarea and then use the IsTrue method to check whether the stored data has a value or not. If successful, the background color of the textarea will turn green.
Server commands
form.SaveValue("Textarea1", "my-key");
form.IsTrue(Fetch.Saved("my-key"), 100);
form.SetBackgroundColor("Textarea1", "lightgreen");
Confirm in events
In this version, the ability to add Confirm to events has been added, which leads to continuing or preventing events. To use this new feature, we must first add events to the tag and then add the "AssignConfirmEvent" method. Currently, the ability to add Confirm is enabled only on internal tag events. In future versions, we will also add a mechanism to support Confirm in Event Listeners.
Example
In this example, after clicking the Button, the Confirm content is displayed; if the user clicks the Confirm button, the event is executed, otherwise the event is not executed.
Server commands
form.SetGetEvent("Button1", HtmlEvent.OnClick, "?button_click");
form.AssignConfirmEvent("Button1", HtmlEvent.OnClick, "Are you sure?", "warning");
We can add customization options to Confirm.
The arguments to the "AssignConfirmEvent" method are:
- Input place
- HTML event
- The Confirm text.
- The type that determines the color of the Confirm and changes the color to red, yellow, blue, green, and gray with the words warning, problem, help, success, and none (the default is none).
- The Confirm title.
- The word or phrase of the confirmation button.
- Word or phrase Cancel button.
We can also remove the Confirm from the button by calling the "RemoveConfirmEvent" method.
form.RemoveConfirmEvent("Button1", HtmlEvent.OnClick);
Calling WebAssembly methods
The ability to call WebAssembly methods is a new feature added in this release. WebAssembly enables fast, near-native execution in the browser (without the need to install a plugin), and also provides high security and usability in limited browser environments.
In this release, we support all programming languages that have stable status in creating WebAssembly.
You can see these in the list below:
- C/C++
- C#
- Rust
- JAVA
- AssemblyScript
- GO
The important point is that the WebAssembly calling structure in WebForms Core technology can have both a string input argument and a string output in an advanced and automatic way.
Example
This is an example of calling a WebAssembly created in the GO programming language. The method name is add and it adds two input arguments and returns the result.
HTML
<b>WASM Result: </b>
Server commands
form.CacheWasmMethodResult(WasmLanguage.GO ,"/web-assembly/hello_world_bg.wasm", "add", ["5000", "3"]);
form.AddText("<b>", Fetch.Cache());
form.AssignDelay(.1f); // By seconds
Result
HTML
<b>WASM Result: 5003</b>
You can also use the word "go" instead of "WasmLanguage.GO".
form.CacheWasmMethodResult("go" ,"/web-assembly/hello_world_bg.wasm", "add", ["5000", "3"]);
In this example, we first call the WASM method and then cache the output of the method, then add the cached output of the method to the b tag with a delay of 100 milliseconds. Please note that WebAssembly calls are done async in browsers and if the method execution speed is slow, you should use a while condition to continuously check the cache until the output is cached and then the insertion operation is performed in the content.
The "CacheWasmMethodResult" method permanently stores the output of a WASM method. You can also use the "SaveWasmMethodResult" method to temporarily store the data only while the browser is active.
The arguments to these two methods are:
- The name of the programming language, which includes "c" (for C/C++), "rust", "csharp", "go", "java" and "as" (for AssemblyScript).
- The path to the WASM file
- The name of the WASM method
- The input arguments to the method
- The name of the Key
Please note that you must choose a name for cache or save to avoid conflicts with other storage behaviors.
Example
Server commands
form.SaveWasmMethodResult(WasmLanguage.GO ,"/web-assembly/hello_world_bg.wasm", "add", ["5000", "3"], "my-wasm-key");
form.AddText("<b>", Fetch.Saved("my-wasm-key"));
form.AssignDelay(.1f); // By seconds
Note: Unlike JavaScript, WebAssembly does not run independently and requires a host to provide the necessary interfaces to interact with it.
Note: We will soon be adding how to create WebAssembly to the list of supported programming languages in a separate article.
Call methods
The CallMethod method has been added in this version for more advanced calling of JavaScript methods.
Example
HTML
<p>Your name is </p>
Server command
form.AddText("<p>", Fetch.CallMethod("prompt", ["Please enter the name", "Your name"]));
Result
HTML
<p>Your name is Jonathan</p>
Upper feature
As promised earlier, we have added the Upper feature using the dash character "-" to select the upper InputPlace. This reduces the bandwidth from the server to the client.
Using
// Pattern
// InputPlace.Upper
// -
// Example
form.AddOptionTag(InputPlace.Tag("select"), "Text1", "Value1");
form.AddOptionTag(InputPlace.Upper, "Text2", "Value2");
// Or Use
form.AddOptionTag("<select>", "Text1", "Value1");
form.AddOptionTag("-", "Text2", "Value2");
Result
When we using Upper
[web-forms]
ao<select>=Value1|Text1
ao-=Value2|Text2
When we not using Upper
[web-forms]
ao<select>=Value1|Text1
ao<select>=Value2|Text2
In this example, the dash character "-" is used instead of the string <select>
in the second Action Control. As you can see, this reduces the bandwidth from the server to the client. WebForms Core allows us to use multiple dashes "-" in a row.
Added Message and Alert
With the addition of Message and Alert, you no longer need to create templates or create complex Action Controls for these tasks. You can display Message and Alert to users by calling WebForms methods on the server.
Example
Alert
form.Alert("My alert 1");
form.Alert("My alert 2", "help", "Alert Title", "Yes");
Alert appears in the center of the screen and darkens the space on the side.
As you can see, we added customization options to the second Alert.
The arguments to the Alert method are:
- The Alert text.
- The type that determines the color of the Alert and changes the color to red, yellow, blue, green, and gray with the words warning, problem, help, success, and none (the default is none).
- The Alert title.
- The word or phrase of the confirmation button.
Message
form.Message("My message 1");
form.Message("My message 2", "warning", 2000);
Message appears in the center and top of the screen.
As you can see, we added customization options to the second Message.
The arguments of the Message method are:
- The Message text.
- The type that determines the color of the Message and changes the color to red, yellow, blue, green, and gray with the words warning, problem, help, success, and none (the default is none).
- The duration of the Message display (in milliseconds and is automatically deleted after the specified period).
Possibility of swapping two tags
In this version, the ability to swap two tags (i.e., change their positions) has been added with the guarantee of preserving state and preserving the Event Listener.
Example
<div>
<b>Bold text one</b>
<b>Bold text two</b>
<b>Bold text three</b>
<b>Bold text four</b>
<b>Bold text five</b>
</div>
<div>
<i>Italic text one</i>
<i>Italic text two</i>
<i>Italic text three</i>
<i>Italic text four</i>
<i>Italic text five</i>
</div>
The below code refers to swapping the 4th <b>
tag (index starts at 0, so <b>3
is the fourth one) with the 2nd <i>
tag (<i>1
).
form.SwapTag("<b>3", "<i>1");
Result
The swap is positional, meaning the two elements trade places in their respective parent <div>
containers.
<div>
<b>Bold text one</b>
<b>Bold text two</b>
<b>Bold text three</b>
<i>Italic text two</i>
<b>Bold text five</b>
</div>
<div>
<i>Italic text one</i>
<b>Bold text four</b>
<i>Italic text three</i>
<i>Italic text four</i>
<i>Italic text five</i>
</div>
Note: Please note that the index starts at [0]!
Added access to the head section
From version 1.9 onwards you will also have access to the head section. In the example below using InputPlace.Head
we define the head section and add a style tag to this section. Below we define the new style.
form.AddTag(InputPlace.Head, "style", "Style1");
form.AddText("Style1", "body{margin: 20px;}");
Instead of InputPlace.Head
we can use the ^
character.
form.AddTag("^", "style");
form.AddText("^<style>", "body{margin: 20px;}");
Added ability to change title
To set the title you can use the SetHeadTitle
method instead of accessing the head section.
form.SetHeadTitle("New title");
Allowing modular development of WebFormsJS
This version has a new feature to allow developers to develop modular WebFormsJS. We have added a section called Extension at the end of the WebFormsJS library and included several methods for extending the WebForms Core technology.
Note: We will teach this new feature in a separate article in the future.
Calling internal scripts
In this version, we also provided the function of calling scripts when tags and URL content are added so that we can call pages that have script tags in the best possible way.
A series of minor features and improvements
In this version, parts of the WebFormsJS library were rewritten and many parts were improved. Some methods of the WebForms class on the server were also rewritten to make the Action Control structure perform faster.
The problems that were solved in this version
- The issue requiring the action attribute in the form tag has been resolved.
- The issue fetching random in WebFormsJS has been resolved.
Version 4.3.1
A name-matching issue occurred in Action Control between alert and label, which was fixed in version 4.3.1.
The "EndTransientDOM" and "CallMethod" methods have also been modified.
And the problem with the IsTrue and IsFalse methods has been solved.
We also found it necessary to add the "IsRegexNoneMatch" conditional attribute.
Top comments (0)