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 :: 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.

 



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Difference Between ReadOnly and Constant in .NET C#

clock April 29, 2024 09:48 by author Peter

Values that cannot be changed at runtime in C# are declared using the readonly and const keywords. However, there are several notable distinctions between these two words.

Constant: Describe It
Const is a compile-time constant, meaning that its value can only be set at compile time and cannot be modified by runtime. Usually, it is used for declaring global constants, such as mathematical constants or other values that aren't expected to change throughout program execution. Const values are intrinsically static and always belong to the class; they are not particular to any one instance of the class. Since they are by nature public, they can also be accessed from anywhere in the code.

public class Constants
{
  public const string CLIENT_ID = "ClientId";
}

ReadOnly:  What Is It?
Conversely, readonly fields are runtime constants, which means that only the class's constructor has the ability to modify them. Their value is predetermined at runtime. Since the readonly fields are instance-level variables, a duplicate of each field exists in each class instance. Additionally, they can be marked as static, indicating that they are part of the class itself rather than a specific class instance. You have to specifically declare the access level because the readonly fields are not inherently public.

public class TestService
{
  private readonly ISomeService _someService;

  public TestService(ISomeService someService)
  {
    _someService = someService;
  }
}


Key distinctions in C# between readonly and constant:
Constants in C# are defined using the readonly and const keywords, although their applications and capabilities differ.

When their values are set is one of the biggest distinctions between readonly and const. Values defined with the const keyword must be set at compile time and will not change at runtime. It implies that const values are decided upon during code compilation rather than execution. Conversely, readonly values are set at runtime and can only have their values assigned within the class constructor.

Const values are also fundamentally different since they are always implicitly static—that is, they are part of the class and not an instance of it. On the other hand, readonly values need to specifically state the access level and can be either instance-level or static.

The following example demonstrates the distinctions between readonly and const:
public class TestClass
{
    public const double PI = 3.14;
    public readonly string Name;

    public TestClass(string name)
    {
        Name = name;
    }
}


In this case, the const value PI was set to 3.14 at compile time. However, Name is a read-only variable that is set in the class's constructor and can only be changed during runtime.

The way that const and readonly are accessible is another distinction between them. Readonly values require the access level to be explicitly specified, whereas const variables are always implicitly public.

While read-only variables are determined at runtime, const values are computed at compile time.
While read-only fields might be instance-level or static and require the access level to be explicitly specified, const values are always static and automatically public.

Readonly fields can only be modified within the class constructor, but const values cannot be altered at runtime.

ReadOnly vs Constant

ReadOnly keyword Const keyword
The readonly keyword in C# can be used to create readonly fields. The const keyword in C# is used to construct constant fields.
The runtime constant ReadOnly. A compile-time constant is called const.
It is possible to modify the readonly field's value. It is not possible to modify the value of the const field.
It can't be declared within the procedure. It may be specified within the procedure.
We can set values in the constructor and declaration sections of read-only fields. We can only assign values to the declaration part of const fields.
The use of static modifiers is possible. Static modifiers are incompatible with its use.

When should you use CONSTANTS versus READONLY?

Utilize constants when the values are absolute, fixed, and do not vary, such as DaysOfWeek, MonthsOfYear, mathematical PI value, and so on. Use readonly when the variables are obtained via user input, configuration files, or any other variable that does not have the same value, such as a database connection string, a secret key, and so on.

We learned the new technique and evolved together.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Extracting Values from PDFs in .NET Core 8 without ASP.NET

clock April 22, 2024 08:38 by author Peter

Within software development, data extraction from PDF files is frequently required for a number of activities, including content indexing, information retrieval, and data analysis. Although ASP.NET Core 8 provides powerful tools for working with PDFs, there are times when developers would rather have other options due to project needs or flexibility concerns. In this post, we'll look at how to use the PdfSharpCore library to extract values from PDF files inside the.NET Core 8 environment without utilizing ASP.NET. We'll present you a detailed how-to and C# examples to show you how to complete this task successfully.

  • Comprehending PdfSharpCore: PdfSharpCore is a well-liked.NET library designed for manipulating PDF documents. It offers tools for adding, editing, and removing material from PDF files. This tutorial will concentrate on using PdfSharpCore to extract text from PDF files.
  • Installing PdfSharpCore: Installing the PdfSharpCore NuGet package is necessary before we can use PdfSharpCore in our.NET Core application. The.NET CLI or the NuGet Package Manager Console can be used for this.

Using the NuGet Package Manager Console
Install-Package PdfSharpCore

Using the .NET CLI
dotnet add package PdfSharpCore

Extracting Text from PDFs in C#: Now that we have PdfSharpCore installed, let's dive into how we can extract text from PDF files using C#.
using PdfSharpCore.Pdf;
using PdfSharpCore.Pdf.IO;
using System;

public class PdfTextExtractor
{
    public static string ExtractTextFromPdf(string filePath)
    {
        using (PdfDocument document = PdfReader.Open(filePath, PdfDocumentOpenMode.Import))
        {
            string text = "";
            foreach (PdfPage page in document.Pages)
            {
                text += page.GetText();
            }
            return text;
        }
    }

    // Example usage:
    public static void Main(string[] args)
    {
        string pdfText = ExtractTextFromPdf("sample.pdf");
        Console.WriteLine(pdfText);
    }
}

The extracted text is returned by the static method ExtractTextFromPdf, which we have implemented in this example. It accepts the file path of the PDF as input and returns the retrieved text. Within the procedure, we access the PDF file using PdfSharpCore, loop through its pages, and extract text from each one. The extracted text is then concatenated and sent back.

Conclusion
By leveraging PdfSharpCore in .NET Core 8, developers have access to a powerful and efficient tool for extracting text from PDF files. Without relying on ASP.NET, PdfSharpCore provides a straightforward solution for handling PDF documents within the .NET Core ecosystem. Whether you're building data processing pipelines, content management systems, or document parsing utilities, PdfSharpCore empowers developers to accomplish PDF manipulation tasks effectively and seamlessly.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: C# &.NET: Experimental Attribute

clock April 16, 2024 08:45 by author Peter

You can add the Experimental property to your types, methods, or assemblies to designate that a feature is experimental using the new Experimental attribute in C# 12. When someone tries to use the method or the type after you've done this, the compiler will throw an error. I describe how to use this functionality in this article.


I used Visual Studio 2022 Preview to construct a console application with.NET 8 and run it for demonstration purposes. Use of the Preview version is required until the article's date. This feature will not function otherwise.

The System.Diagnostics.CodeAnalysis namespace is where the Experimental attribute originates. You can see an example of a class with this attribute in the code below:

using System.Diagnostics.CodeAnalysis;

namespace DotNet8Examples
{
    [Experimental(diagnosticId: "Test001")]
    public class ExperimentalAttributeDemo
    {
        public void Print()
        {
            Console.WriteLine("Hello Experimental Attribute");
        }
    }
}


On line 1, there is the namespace for the Experimental attribute.
On line 5, there is the Experimental attribute, with the diagnosticId. For the diagnosticId, you can specify an Id, which will be used by the compiler, to report a usage of the API the attribute applies to.
On line 8, there is a method for this class.

Now, if you try to create an instance of this class, the compiler will complain about it:
var experimentalAttributeDemo = new ExperimentalAttributeDemo();

It should be noted that the Experimental property can be used in both the method and the class. You can use the NoWarn property in the.csproj file to use this class and ignore this error; this will work on a global level, so each time you try to use the class or method, you won't have to suppress the error; alternatively, you can suppress it directly on the code, which will require you to do so each time you need to use the class or method.

I'm directly suppressing the error Test001 in the code in the example below. In order to do it, you must add your code in between the #pragma warning disable Test001 and the #pragma warning restore Test001:



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Using Identity for NET API Login and Registration

clock April 2, 2024 08:18 by author Peter

Creating reliable and secure online apps requires careful consideration of authentication and authorization. Microsoft Identity offers a strong foundation for implementing authorization and authentication features with ease in the.NET ecosystem. In this post, we'll look at how to use Microsoft Identity in conjunction with controllers to efficiently handle user registration and login functions in a.NET API.

Required conditions

Make sure you have installed the following prerequisites before continuing:

  • The.NET SDK (at least version 5)
  • Visual Studio Code (optional) or Visual Studio


Establishing the Project
Let's start by making a new.NET Web API project:

dotnet new webapi -n YourProjectName
cd YourProjectName


Adding Identity to the Project
To add Identity to your project, run the following commands:
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

This adds the necessary packages to your project for using Identity and Entity Framework Core with SQL Server.

Scaffold Identity

Next, scaffold Identity into your project:
dotnet aspnet-codegenerator identity -dc YourDbContext

Replace YourDbContext with the name of your application's DbContext.
Implementing Registration and Login Controllers:

Now, let's implement controllers for user registration and login.

1. Registration Controller

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using YourProjectName.Models;

namespace YourProjectName.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RegisterController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> _userManager;

        public RegisterController(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }

        [HttpPost]
        public async Task<IActionResult> Register(RegisterModel model)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await _userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                return Ok("Registration successful");
            }
            return BadRequest(result.Errors);
        }
    }
}

2. Login Controller
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using YourProjectName.Models;

namespace YourProjectName.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class LoginController : ControllerBase
    {
        private readonly SignInManager<ApplicationUser> _signInManager;

        public LoginController(SignInManager<ApplicationUser> signInManager)
        {
            _signInManager = signInManager;
        }

        [HttpPost]
        public async Task<IActionResult> Login(LoginModel model)
        {
            var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);
            if (result.Succeeded)
            {
                return Ok("Login successful");
            }
            return Unauthorized("Invalid email or password");
        }
    }
}

Models
Ensure you have the necessary models for registration and login:
namespace YourProjectName.Models
{
    public class RegisterModel
    {
        public string Email { get; set; }
        public string Password { get; set; }
    }

    public class LoginModel
    {
        public string Email { get; set; }
        public string Password { get; set; }
    }
}


Configuring Startup
Finally, add Identity services to the ConfigureServices method in Startup.cs:
services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<YourDbContext>()
    .AddDefaultTokenProviders();

Happy coding!



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Razor Syntax in ASP.NET

clock March 25, 2024 10:23 by author Peter

ASP.NET is a reliable platform for web development, allowing developers to easily create dynamic and resilient web applications. At the heart of ASP.NET is Razor, a powerful templating engine that transforms the way developers create server-side code. Razor syntax provides a concise and easy way to combine server-side code and HTML, increasing productivity and maintainability. Let's go deeper into Razor syntax and see how it can improve your ASP.NET programming experience.

Understanding Razor syntax
Razor syntax seamlessly integrates server-side code into HTML markup, resulting in cleaner and more understandable code than typical ASP.NET Web Forms. Its lightweight and fluid design allows developers to seamlessly switch between HTML and server-side code, resulting in a more efficient development process.

Razor syntax uses a set of special characters (@) to represent server-side code blocks in HTML markup. These code blocks can include C# or VB.NET code, allowing developers to execute logic, get data from databases, modify objects, and conduct a variety of other operations right within the markup.

Benefits of Razor Syntax

  • Readable and Maintainable Code: Razor syntax promotes code readability by minimizing the clutter typically associated with embedding server-side logic within HTML. The clean and concise syntax enhances code maintainability, making it easier for developers to understand and modify code segments as needed.
  • Seamless Integration: Unlike traditional ASP.NET Web Forms, which often necessitate a clear demarcation between server-side and client-side code, Razor syntax seamlessly integrates server-side logic with HTML markup. This cohesive approach simplifies development and fosters a more fluid coding experience.
  • Enhanced Productivity: By streamlining the process of writing server-side code within HTML, Razor syntax boosts developer productivity significantly. Its intuitive nature reduces cognitive overhead, allowing developers to focus on implementing business logic rather than wrestling with cumbersome syntax.
  • Code Reusability: Razor syntax facilitates code reusability by enabling developers to encapsulate common functionality within reusable components known as partial views. These partial views can be invoked from multiple pages, promoting a modular and DRY (Don't Repeat Yourself) coding approach.
  • IntelliSense Support: Integrated development environments (IDEs) such as Visual Studio provide robust IntelliSense support for Razor syntax, offering real-time suggestions and auto-completion for server-side code blocks. This feature enhances code efficiency and reduces the likelihood of syntax errors.

Example of Razor Syntax

<!DOCTYPE html>
<html>
<head>
    <title>ASP.NET Razor Syntax</title>
</head>
<body>
    <div>
        <h1>Welcome, @Model.Name!</h1>
        <p>Your account balance is: [email protected]</p>
        @if (Model.IsPremium)
        {
            <p>Congratulations! You are a premium member.</p>
        }
        else
        {
            <p>Upgrade to premium for exclusive benefits.</p>
        }
    </div>
</body>
</html>

In this example, Razor syntax is used to embed server-side code within an HTML document. The @Model directive accesses properties of the model passed to the view, allowing dynamic content to be rendered based on the provided data.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: How to Understanding Deadlocks in C# and .NET Core?

clock March 19, 2024 08:58 by author Peter

Deadlocks are a prevalent problem in concurrent programs, and they can be especially troublesome for programs written in C# and running on.NET Core. A deadlock arises when two or more threads are waiting for each other to release resources that are required to proceed. This can lead to all threads becoming stuck and unable to progress, causing the program to freeze. Many distinct conditions can result in deadlocks, and developers must be aware of them in order to avoid or reduce the danger of deadlocks.

For example, one common circumstance is that two threads each have a resource that the other thread requires. Another instance is when one thread is waiting for a lock to be released while another thread holds that lock and waits for the first thread to release a different lock. These circumstances can be difficult to identify and resolve, but with careful analysis and development techniques, deadlocks can be avoided or reduced.

What is a deadlock?

A deadlock occurs when two or more threads are stalled indefinitely, each waiting for the other to relinquish a resource that it requires to move forward. Deadlocks are characterized by a circular waiting pattern in which no thread can continue, resulting in a stalemate.

using System;
using System.Threading;

class Program
{
static object ResourceA = new object();
static object ResourceB = new object();

static void Thread1()
{
    lock (ResourceA)
    {
        Console.WriteLine("Thread1 acquired ResourceA");
        Thread.Sleep(100); // Simulating some work

        lock (ResourceB)
        {
            Console.WriteLine("Thread1 acquired ResourceB");
        }
    }
}

static void Thread2()
{
    lock (ResourceB)
    {
        Console.WriteLine("Thread2 acquired ResourceB");
        Thread.Sleep(100); // Simulating some work

        lock (ResourceA)
        {
            Console.WriteLine("Thread2 acquired ResourceA");
        }
    }
}

static void Main(string[] args)
{
    Thread t1 = new Thread(Thread1);
    Thread t2 = new Thread(Thread2);

    t1.Start();
    t2.Start();

    t1.Join();
    t2.Join();

    Console.WriteLine("Program completed successfully.");
}
}


Understanding The Deadlock
In this case, Thread1 locks ResourceA first and then attempts to lock ResourceB, whereas Thread2 locks ResourceB first and then attempts to lock ResourceA. If Thread1 obtains ResourceA while Thread2 obtains ResourceB, they will both be waiting for the other resource, resulting in a stalemate.

Preventing Deadlocks

To prevent deadlocks, you can employ various strategies:

  • Lock Ordering: Always acquire locks in a consistent order to prevent circular dependencies.
  • Lock Timeout: Use Monitor.TryEnter or Mutex.WaitOne with a timeout to avoid indefinite blocking.
  • Lock Hierarchy: Establish a lock hierarchy and always acquire locks in the same order within that hierarchy.
  • Avoid Nested Locks: Minimize the use of nested locks to reduce the risk of deadlocks.

Conclusion
Deadlocks can be challenging to debug and resolve, but understanding their causes and employing preventive measures can help mitigate their occurrence. In C# and .NET Core, careful design and coding practices, along with thorough testing, are essential for creating robust and reliable concurrent applications. By following best practices and being mindful of potential deadlock scenarios, developers can ensure the smooth execution of their multithreaded code.



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