European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Using and Exercising the String Builder in.NET C#

clock May 27, 2024 07:04 by author Peter

Once a string type is generated in C#, its contents cannot be changed since the string type is immutable. This suggests that modifying a string-type object after it has been created will cause the object to be constructed again in memory as a new instance. Additionally, changing the string frequently could cause performance problems.


StringBuilder solves this problem because, unlike string, it can dynamically increase its memory to support any kind of manipulation.

How to make a StringBuilder correctly?
It is not too difficult to instantiate a StringBuilder. We can instantiate a class by using the new keyword to create an instance of that class. A StringBuilder also contains other constructors.

Conversion of StringBuilder to String
We can use a StringBuilder for any type of string manipulation. But the StringBuilder does not return a string. Therefore, in order to retrieve a string, we must use the ToString() method.
var sb = new StringBuilder("Peter Scott");

var name = sb.ToString();

The content is first converted to a string and then a StringBuilder is created with a default text.

StringBuilder Techniques

We can work with a StringBuilder's contents in a few different ways. These include Replace(), Insert(), Clean(), Remove(), Append(), AppendLine(), and AppendFormat().

Append
A new string is appended to the end of the existing StringBuilder using the Append() function. The StringBuilder's length can be doubled, and space allocation happens automatically.
var sb = new StringBuilder("Hello, ");
sb.Append("Peter Scott");
var name = sb.ToString();

Console.WriteLine("{0} - {1}", nameof(name), name);

AppendLine
AppendLine() is useful when we want to add a line terminator to our StringBuilder. To accomplish this, we can make a StringBuilder and use the following method.


var sb = new StringBuilder("Hello, ");
sb.Append("Peter Scott");
sb.AppendLine();
sb.AppendLine("How are you?");

Console.WriteLine(sb.ToString());

AppendFormat
AppendFormat() appends a string to the end of StringBuilder in a predetermined format. The conventions of either the chosen culture or the current system culture are revealed in the produced string. The method lets us pass the desired format for our string as an input.
var sb = new StringBuilder("Hello, ");
sb.Append("Peter Scott");
var text = "C# Corner Rank";
var rank = 120;
sb.AppendLine();
sb.AppendFormat("{0} - {1}", text, rank);

Console.WriteLine(sb.ToString());


This method adds, to our StringBuilder object, a string, substring, character array, part of a character array, or the string representation of a primitive data type at a certain place. We may also add the index for our insertion using this method.
var sb = new StringBuilder("Hello");
var name = ", Peter Scott";
sb.Insert(5, name);

Console.WriteLine(sb.ToString());


Replace
Several character occurrences in the StringBuilder object are replaced by this method. The desired character sequence and a new value are entered into the method as inputs.
var sb = new StringBuilder("Hello");
var name = ", Peter Scott";
sb.Insert(5, name);
Console.WriteLine("Orioginal data: {0}", sb.ToString());
Console.WriteLine();

sb.Replace("Lee", "Cooper");

Console.WriteLine("Replace data: {0}", sb.ToString());


Replace
A predetermined amount of characters are removed from the StringBuilder using the Remove() function. The start index and the number of characters to be deleted are the input parameters.

var sb = new StringBuilder("Hello");
sb.Append(", Peter Scott");

Console.WriteLine("Orioginal data: {0}", sb.ToString());
Console.WriteLine();

sb.Remove(0, 7);

Console.WriteLine("Remove data: {0}", sb.ToString());


Remove
The Remove technique eliminates 7 characters starting at index 0.

Clear

The StringBuilder object's characters are all eliminated using this function. This method reduces the length of a StringBuilder to zero.
var sb = new StringBuilder("Hello");
sb.Append(", Peter Scott");

Console.WriteLine("Orioginal data: {0}", sb.ToString());
Console.WriteLine();

sb.Clear();

Console.WriteLine("Clear data: {0}", sb.ToString());


Clear
We learned the new technique and evolved together.
Happy coding!



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: The Issue of Thread Synchronization and It's ResolutionAn Alternative View on Stack Memory in.NET

clock May 20, 2024 09:40 by author Peter

We shall discuss the Stack memory in.NET in this article. The portion of memory in.NET that is assigned to a thread is called the Stack. To put it simply, each thread has a stack—that is, its own memory—that is the last in, first out. Note: Because there is a connection between Stack memory and Heap memory, some parts of the article are explained but do not include Heap memory.


Memory Stack
Computer memory architecture is where the idea of a memory stack first appeared. Its essence also affects the various programming languages. After all, in any computer system, a programming language is a form of abstraction or communication. Many programming languages are forced to adopt it as a result.
So, even the CPU has push-and-pop instructions for providing thread (stack) execution and other things. Well, without further confusion, let’s continue our look at .NET and their use of Stack memory.

Nearly all developers are aware that a data structure is referred to as a "stack." There are two general strategies for the stack data structure: FIFO and LIFO. We employ the LIFO (last in first out) method to operate our stack memory. Moreover, distinguish between stack memory and the stack data structure. Because stack memory makes use of the stack data structure technology, names are the same. There are two different kinds of memory in.NET; a heap and a stack, both of which are found in RAM. Method calls, return addresses, arguments/parameters, and local variables are all tracked by the stack. However, reference-type objects are stored in Heap (this is a topic for another article).

To put it simply, every thread has a memory location of its own. This is the stack, which represents each thread's local memory. Thus, during method execution, threads define a local variable, retrieve the result, and then call another method, and so on. It is these actions that require stack memory. Furthermore take note that just one thread of execution uses the stack memory. Conversely, a heap is shared memory used by multiple threads, the extent of which is specified by the operating system process.

Allocation of Stacks
Stack allocation, to put it simply, is a memory allocation technique that makes use of the stack, a section of memory. The most recently allocated memory is the first to be deallocated because, as I previously explained, the stack uses the LIFO (last in first out) method of operation. There are two types in.NET. A reference type is one, and a value type is the other. Thus, the value of the type is saved immediately when allocating a value type in a stack. However, when dealing with reference types that reside in heaps, it stores the heap's reference address, also known as the object's pointer. Generally speaking, it means that a stack only contains values (a reference address is a type of value, but we'll talk about that in another article).

The figure above illustrates how two declared variables are present in a separate stack frame within the thread stack: a flag (int32, value type) and a pInst, instance of the Person class. We won't talk about the heap, but the picture demonstrates that it has the flag's value of 1, as well as the reference address of pInst. The address for the stack that refers the heap object—an object with data and methods stored on the heap—is what is meant to be used in the reference type. In .NET, Stack memory has a fixed size which a 1-MB stack is allocated when a thread is created. This size is predefined once the program starts, providing a consistent amount of stack memory available for function calls and local variable storage. However, the fixed nature of the stack means that it can only hold a limited amount of data. In addition, the speed of stack memory operations is a key advantage based on the simplicity of the stack’s push and pop mechanisms.

So, almost everyone wonders why the Stack memory is fast.

  • Firstly, stack memory uses static memory allocation, meaning that memory is given and taken away in a predictable way. This removes the need for complicated memory management, making operations quick and efficient.
  • Secondly, as I said above the stack has a fixed size, which avoids the overhead of finding available memory space, unlike heap memory. The simple push-and-pop operations also make it faster. These operations just adjust the stack pointer, which is very fast compared to the more complex operations needed for heap memory.
  • Thirdly, modern CPUs have special instructions for stack operations, like pushing and popping data, which are made to be very fast. The CPU also uses a dedicated register, the stack pointer, to efficiently manage the stack’s top position. In addition, stack memory often gets loaded into the CPU cache. This happens because stack data is frequently accessed in a straight line, making it more friendly to the cache. In contrast, accessing heap memory is indirect and can involve more cache misses, making it slower. This direct hardware support and cache efficiency ensure that stack operations have very little overhead.

Stack Frame/Call Stack

A stack frame, also known as an activation record, is a section of the stack memory allocated for a single function/method call. When a function/method is called, a new stack frame is allocated, and when the function/method returns, its stack frame is deallocated.

Basically, a stack frame contains.

  • Function/Method Arguments: The values passed to the function/method.
  • Local Variables: Variables that are declared inside the function/method.
  • Return Address: The location in the code to return to after the function/method completes.


Let’s start the explanation with a code example.
public void Calculate()
{
    int a = 1;
    int b = 10;
    int c = a + b;

    Write(c);
    Console.WriteLine("Finished");
}

public void Write(int number)
{
    Console.WriteLine(number);
}


As you can see, there is a method named Calculate that declares 3 variables and is also called the Write method it.

Assume that, a thread calls the Calculate method, how would this be visualized?

As you can see from the image above, the first stack frame belongs to the Calculate method which stores 3 variables, one of which is the result of the sum of two variables. The second stack frame belongs to the Write method which stores the argument and return address (line 9 just for understanding, in fact, it contains different values).

So when the Write method completes the execution, the second stack frame is deallocated and the thread returns to the first stack frame that belongs to the Calculate method, through the return address it will execute from that address line and complete the execution of the Calculate method. In this way, the call stack loop that was called in this thread will continue to execute (in our case, execution is completed).

StackOverflowException

As I mentioned before, the stack size is limited, and for this reason, when any function/method is called in an unlimited and nested way, a “StackOverflowException” occurs.

Assume that we have some function/method that is using recursion but there is not any limitation. It means the method has some calculation in which there is no return state. So, in this case, we will get “StackOverFlowException”.

Let’s take a look at a code example.

public class Program
{
    public static void Main()
    {
        Calculate(2, 3);
    }

    public static void Calculate(int a, int b)
    {
        int c = a + b;
        Calculate(c, c * c);
    }
}


When you execute this code, you will get “StackOverFlowException” because recursion provides the call itself and there is no return state or limit in this function/method. With this technique, every call to the function/method creates new stack frames and when the stack limit is exceeded, we get a “StackOverFlowException”.

If you would like to learn more, stay tuned!



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: The Issue of Thread Synchronization and It's Resolution

clock May 14, 2024 06:53 by author Peter

Overview of synchronization issues

  • Assume that our shared count variable has a starting value of 0.
  • We wish to use this variable for two simultaneous activities.

Using Thread 1, add 1 to 100 to this variable.
Using Thread 2, subtract 1 to 100 from this value.

  • Print the variable's count at the end. It should ideally print 0. but it won't Because working on the same variable simultaneously by many threads can have unexpected outcomes.

When does the synchronization problem happen?
Critical Section
When more than one threads try to access the same code segment that segment is known as the critical section.
So, when more than one thread is there in the critical section at the same time, it can lead to unexpected results and synchronization problem.

Race Condition
If more than one thread tries to enter inside the critical section at the same time then it might lead to the synchronization problem.

Preemption
Preemption is the ability of the operating system to preempt(that is stop or pause) a currently scheduled task in favor of a higher priority task.
A program that is inside the critical section and CPU preempts then it can lead to the synchronization problem.

Solutions to the synchronization problem

In C#, there are several ways to synchronize access to shared resources to ensure thread safety and prevent race conditions.

Using lock keyword
The lock keyword provides a convenient way to create a synchronized block of code. It internally uses the Monitor class to achieve synchronization. The lock keyword ensures that only one thread can execute the locked code block at a time.

Example
private static object syncObject = new object();
private void Increment()
{
lock(syncObject)
{
    // Critical section: Access shared resource
}
}


Using Monitor Class
Instead of using the lock keyword, we can directly use methods of the Monitor class for synchronization.

Example
private static object syncObject = new object();
private void Increment()
{
Monitor.Enter(syncObject);
try
{
    // Critical section: Access shared resource
}
finally
{
    Monitor.Exit(syncObject);
}
}


Using Mutex
A mutex is a synchronization primitive that allows only one thread to acquire it at a time. It's typically used for inter-process synchronization to synchronize threads within the same process.

Example
private static Mutex mutex = new Mutex();
private void Increment()
{
mutex.WaitOne();
try
{
    // Critical section: Access shared resource
}
finally
{
    mutex.ReleaseMutex();
}
}

Using Semaphore
A semaphore is a synchronization primitive that allows a specified number of threads to enter a critical section simultaneously. It's useful when we want to limit the number of threads accessing a resource.

Example
private static Semaphore semaphore = new Semaphore(1, 1); // Limits access to one thread
private void Increment()
{
semaphore.WaitOne();
try
{
    // Critical section: Access shared resource
}
finally
{
    semaphore.Release();
}
}


Using Interlocked Class
The Interlocked class provides atomic operations for variables that are shared between threads. It's useful for performing simple operations like incrementing a counter without the need for locking.

Example
private int counter = 0;
public void Increment()
{
Interlocked.Increment(ref counter);
}

Properties of a good solution to the synchronization problem

Mutual Exclusion: Only one thread should be allowed inside the critical section at any point in time.
Progress: Overall system should keep on making progress. There shouldn't be a deadlock condition.
Bounded waiting: No thread should wait outside the critical section infinitely. There should be some bound on the waiting time.
No Busy Waiting: If a thread has to continuously check if they can enter inside the critical section or not is Busy Waiting.
    while(!allowed to enter critical section)

    {
        checking(); // <---- This is the busy waiting.
    }


There shouldn't be Busy waiting as it can have several consequences like

  • Inefficient use of CPU resources and wasted energy.
  • Reduced performance.
  • Increased power consumption.
  • Potential deadlocks and etc.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Comprehending.NET Core Garbage Collection

clock May 6, 2024 08:07 by author Peter

A key component of memory management in contemporary programming languages like C# is garbage collection (GC). The GC system is essential to.NET Core because it automatically recovers memory that is no longer in use, eliminating memory leaks and guaranteeing effective memory use. The purpose of this article is to examine the techniques and the parts that make up the garbage collection system in .NET Core.

Comprehending Trash Collection
Effective memory management is essential for developing strong applications, especially with C# and.NET Core. Garbage Collection (GC) is a key component of this ecosystem's automated memory management system, effectively managing memory deallocation and allocation. The process of automatically recovering memory used by objects that an application no longer needs is known as garbage collection. This is accomplished in.NET Core via a highly developed garbage collector that operates in the background, regularly searching the managed heap for things that have not been referenced and recovering their memory. Fundamentally, managed heap memory—the memory used by C# applications to store instantiated objects—is allocated and released by Garbage Collection in.NET Core.

Garbage Collection Components in.NET Core

  • Managed Heap: The managed heap is a section of memory set aside for the purpose of storing application-created objects by the Common Language Runtime (CLR). The managed heap in.NET Core is separated into three generations: Gen0, Gen1, and Gen2. Initially assigned to Gen0, objects are promoted to higher generations as long as they survive garbage collection cycles.
  • Garbage Collector: In.NET Core, the garbage collector is the main element in charge of memory reclamation. It runs in the background, periodically scanning the managed heap to locate and retrieve things that the application can no longer access. To maximize collection efficiency and reduce interference with application performance, the garbage collector employs a variety of algorithms and heuristics.
  • Finalization Queue: Finalization is supported by.NET Core, enabling objects to carry out cleanup operations prior to being picked up by garbage collectors. The finalization queue is a dedicated queue for objects that need to be finalized. In order to guarantee that their finalizers are called prior to their reclamation, objects in the finalization queue are handled independently during garbage collection.
  • Large Object Heap (LOH): In.NET Core, large objects (usually those greater than 85,000 bytes) are stored in the Large Object Heap, a separate section of the managed heap. Large items are treated differently by the trash collector due to their size in order to reduce fragmentation and enhance performance.

Three basic steps are involved in the operation of this automated process:

  • Marking: To determine which objects are still in use, the GC begins by iterating through all object references, beginning at the roots.
  • Relocating: The GC compacts the heap by moving active objects closer to one another after detecting them, improving speed and memory layout. It modifies references in parallel to take into account the updated memory addresses.
  • Clearing: The last phase involves the GC freeing up memory that has been occupied by objects that are no longer referenced, freeing up resources for new allocations.

Including Future Generations to Increase Efficiency
Generational memory management is one of the main techniques that.NET GC uses to increase efficiency. The managed heap is divided into three generations, each of which serves different object categories:

  • Gen 0: This segment accommodates short-lived objects, which typically have a transient lifespan within the application. As a result, a significant portion of memory reclamation occurs in this generation.
  • Gen 1: Positioned as a buffer between short-lived and long-lived objects, Generation 1 serves to segregate objects based on their longevity. Objects surviving multiple garbage collections in Gen 0 are promoted to Gen 1.
  • Gen 2: Comprising long-lived objects, Generation 2 hosts entities expected to persist throughout the application's lifecycle. Garbage collections within this segment are less frequent due to the enduring nature of its occupants.

Conclusion

Within the.NET Core ecosystem, garbage collection is a fundamental component of memory management because it provides an automated solution to the challenges associated with memory allocation and deallocation. Through an understanding of GC's inner workings and an embrace of generational memory management, developers may create apps that are more resilient to changing workloads and perform better overall. The finalization queue, managed heap, garbage collector, and other parts of.NET Core integrate flawlessly to automate memory management and offer a dependable execution environment for.NET Core programs.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Using.NET Aspire App to Deploy.NET 8 Core Web API in the Cloud

clock May 2, 2024 07:43 by author Peter

A cloud-ready, opinionated stack for developing distributed, observable, production-ready applications is.NET Aspire. Delivery of.NET Aspire occurs via a group of NuGet packages that address particular cloud-native issues. Microservices, which are tiny, interconnected units of code, are frequently used in place of a single, large code base in cloud-native applications. Typically, cloud-native applications use a lot of resources, including messaging, databases, and caching.

Overview
A cloud-ready toolset for creating contemporary distributed applications is called.NET Aspire. Its main goal is to assist developers in building observable, scalable microservices. .NET Aspire makes it easier to deploy.NET Core APIs and enables you to rapidly create cloud-native applications with a set of NuGet packages. Rather to having a single, massive code base, these applications usually comprise of smaller, connected components. For their operations to be successful in a cloud setting, they frequently depend on services like messaging, databases, and caching.

Starting a New Visual Studio 2022 Project
Starting a New Visual Studio 2022 Project An overview Launch the Visual Studio application, then choose "Create a new project."

The chosen application's project structure will be created by Visual Studio 2022. Since we're utilizing the ASP.Net Core Web API in this example, we can either utilize the pre-existing controller or construct a new one to write the code. You can enter the code there and use it to create or run the program.

To create a .NET Aspire Application, follow these steps.

  • Right-click on the Solution section in Visual Studio.
  • Select "Add" > "New Project."
  • Choose "Create a new project."
  • Find and select ".NET Aspire Application" from the list of project templates.

The .NET Aspire Application is a basic starter template that includes only the AppHost and ServiceDefaults projects. This template is designed to only provide the essentials for you to build off of

The .NET Aspire Application is a basic starter template that includes only the AppHost and ServiceDefaults projects. This template is designed to provide the essentials to build upon.

Project Structure

  • WEB: This is an ASP.NET Core API project, This project depends on the shared AspireCloud.ServiceDefaults project.
  • AspireCloud.AppHost: This is an orchestrator project designed to connect and configure the different projects and services of your app. This project handles running all of the projects that are part of the .NET Aspire application. The orchestrator should be set as the Startup project, and it depends on the WEBThis is the project responsible for running the applications inside of this solution.
  • AspireCloud.ServiceDefaults: This is a.NET Aspire shared project to manage configurations that are reused across the projects in your solution related to resilience, service discovery, and telemetry. This project ensures that all dependent services share the same resilience, service discovery, and OpenTelemetry configuration.

In the Program.cs file on the AppHost project, you can see the following code.
var builder = DistributedApplication.CreateBuilder(args);
var RESTAPI = builder.AddProject<Projects.WEB>("RESTAPI");
builder.Build().Run();

WEB .NET core API program.cs file configured in Aspire.ServiceDefaults.
builder.AddServiceDefaults();

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

//cloud configuration:

builder.AddServiceDefaults();

var app = builder.Build();

// Configure the HTTP request pipeline.

if (app.Environment.IsDevelopment())

{
    app.UseSwagger();

    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

On the Extensions. cs file, you can find some extension methods such as:

  • AddServiceDefaults: used to add default functionality.
  • ConfigureOpenTelemetry: used to configure OpenTelemetry metrics and tracing
  • AddDefaultHealthChecks: adds default health checks endpoints
  • MapDefaultEndpoints: maps the health check endpoint to /health and the liveness endpoint to alive.

Dashboard
Start the project with AspireCloud.AppHost is the Starter project (this project knows how to run the whole distributed application), and the following page will be opened in your browser with this nice dashboard.

In this dashboard, you can monitor various parts of your app, such as,

  • Projects: Displays information about your .NET projects in your .NET Aspire app, such as the app state, endpoints, and environment variables.
  • Containers: Displays information about your app containers, such as state, image tag, and port number (you should also see the Redis container you added for output caching with the name you provided.
  • Executables: Displays the running executables used by your app.
  • Logs: In this section, you can see the output logs for the projects, containers, and executables, and can also see the logs in a table format (structured).
  • Traces: displays the traces for your application, providing information about the requests.
  • Metrics: Displays various instruments and meters that are exposed and their corresponding dimensions for your app.

The Traces for your APIs.

 



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in