Knowledge Guardian

Tag: dot net core

Mastering Lambda Expressions in C#

Let’s break it down further with a more detailed exploration of lambda expressions in C#:


Introduction:
Lambda expressions in C# are concise and powerful constructs that enable the creation of inline, anonymous functions. They facilitate functional programming concepts and significantly enhance code readability and maintainability.

Section 1: Understanding Lambda Expressions

Chapter 1: Basics of Lambda Expressions

Definition of Lambda Expressions:
Lambda expressions are compact representations of anonymous functions and follow the syntax (parameters) => expression or statement block. They’re used for defining functions on-the-fly without needing separate method declarations.

Syntax and Structure of Lambda Notation:

Func<int, int, int> add = (x, y) => x + y;

Chapter 2: Advantages of Lambda Expressions

Conciseness and Readability:
Lambda expressions reduce code verbosity, making code more concise and enhancing readability, especially when used for simple functions or predicates.

Functional Programming Paradigm:
They support functional programming principles like higher-order functions, enabling a more expressive coding style.

Usage in LINQ:
Lambda expressions are integral for LINQ (Language Integrated Query) in C#. They allow for the creation of inline predicates and projections, enhancing query expressiveness.

Section 2: Using Lambda Expressions

Chapter 3: Lambda Expressions with Delegates

Example with Func:

Func<int, int, int> multiply = (x, y) => x * y;
int result = multiply(3, 4); // result = 12

Understanding Action and Predicate:
Lambda expressions work seamlessly with other delegate types (Action for void-returning methods, Predicate for boolean-returning methods) in a similar fashion.

Chapter 4: Lambda Expressions in LINQ Queries

Example of Filtering with LINQ:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0);

Exploring OrderBy, Select, and More:
Lambda expressions are used extensively in LINQ for sorting (OrderBy), projection (Select), filtering (Where), and more, offering a fluent and expressive querying syntax.

Section 3: Advanced Lambda Expressions

Chapter 5: Capturing Variables in Lambdas

Understanding Captured Variables:
Lambda expressions can capture variables from their enclosing scope, providing access to outer variables within the lambda body.

Example of Captured Variable:

int factor = 10;
Func<int, int> multiply = x => x * factor;
int result = multiply(5); // result = 50

Chapter 6: Lambda Expressions and Asynchronous Programming

Asynchronous Operations with Lambda:
Lambda expressions are commonly used in asynchronous programming (async and await), allowing for the creation of asynchronous functions inline.

Example of Asynchronous Lambda:

Func<Task<int>> asyncOperation = async () =>
{
    await Task.Delay(1000);
    return 42;
};

Conclusion:

Lambda expressions in C# offer a concise and expressive way to define functions inline, enabling a more functional and elegant coding style. Their integration with delegates, LINQ, captured variables, and asynchronous programming makes them powerful and versatile tools in modern C# development.


Understanding .NET Core appsettings.json File

Let’s delve into an in-depth guide covering the appsettings.json file in .NET Core 3.0 and beyond.


Introduction

The appsettings.json file in .NET Core serves as a configuration file to manage application settings. It allows developers to store various parameters, connection strings, and configurations in a structured JSON format, facilitating easy access and modification.

Structure of appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=...;Database=...;User Id=...;Password=..."
  },
  "AppSettings": {
    "AppTitle": "MyApp",
    "Environment": "Development"
  }
}

Available Options and Values:

  1. Logging Configuration:
  • LogLevel: Sets the default logging level for the application and specific namespaces.
  1. ConnectionStrings:
  • DefaultConnection: Defines database connection strings used in the application.
  1. Custom AppSettings:
  • AppTitle: Represents a custom application title.
  • Environment: Specifies the application environment (e.g., Development, Staging, Production).

Examples and Usage:

  1. Logging Configuration:
   "Logging": {
     "LogLevel": {
       "Default": "Information",
       "Microsoft": "Warning",
       "MyNamespace.MyClass": "Debug"
     }
   }
  • Set different log levels for different namespaces. For instance, setting Debug for a specific class within a namespace.
  1. ConnectionStrings:
   "ConnectionStrings": {
     "DefaultConnection": "Server=myServerAddress;Database=myDatabase;User Id=myUsername;Password=myPassword;"
   }
  • Store and access database connection strings for various databases.
  1. Custom AppSettings:
   "AppSettings": {
     "AppTitle": "MyAwesomeApp",
     "Environment": "Production"
   }
  • Define custom application settings like titles and environment configurations.

Additional Features and Options:

  1. Array Configuration:
   "AllowedHosts": [
     "localhost",
     "127.0.0.1",
     "::1"
   ]
  • Configure arrays to specify allowed hosts.
  1. Complex Object Configuration:
   "EmailSettings": {
     "SmtpServer": "smtp.gmail.com",
     "Port": 587,
     "Credentials": {
       "Username": "your_email@gmail.com",
       "Password": "your_password"
     }
   }
  • Define complex objects like email settings with nested properties.
  1. Configuration from Environment Variables:
   "ApiKey": "${API_KEY}"
  • Utilize environment variables within the appsettings.json file.

Conclusion

The appsettings.json file in .NET Core serves as a versatile configuration tool, offering a structured approach to manage application settings. It allows for easy customization, abstraction of settings, and facilitates the separation of configuration from code, contributing to a more maintainable and scalable application architecture.

By leveraging the diverse options and values within the appsettings.json file, developers can tailor application configurations to suit various environments and requirements, ensuring flexibility and robustness.


This comprehensive guide covers the various elements and features of the appsettings.json file in .NET Core, providing a detailed overview of its capabilities and usage scenarios.

Deep Dive into Conventional Routing in .NET Core 6 MVC Application

Detailed technical blog post on conventional routing in .NET Core 6 MVC application:


Routing is a fundamental aspect of ASP.NET Core MVC, enabling developers to define URL patterns and direct incoming HTTP requests to the appropriate controllers and actions. In this comprehensive guide, we’ll explore conventional routing, a powerful feature that allows for structured and predictable URL mappings within .NET Core 6 MVC applications.

Understanding Conventional Routing:

What is Conventional Routing?

Conventional routing in ASP.NET Core MVC follows a convention-based approach to define URL patterns and map them to controller actions. It relies on a set of predefined rules to match incoming requests with specific controllers and their actions.

Route Templates:

Route templates define URL patterns that are matched against incoming requests. They consist of placeholders for dynamic segments in the URL.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});
  • {controller} and {action} placeholders represent the controller and action names, respectively.
  • {id?} denotes an optional parameter (? indicates optional).

Controller and Action Naming Conventions:

Conventional routing relies on naming conventions to match controllers and actions.

  • Controllers should have names ending with “Controller” (e.g., HomeController).
  • Action methods should be public and named as per the intended action (e.g., Index, Details, etc.).

Example of Conventional Routing:

Configuration in Program.cs:

Configure routing in the Program.cs file :

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddControllersWithViews();

        var app = builder.Build();

        // Configure the HTTP request pipeline.
        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        app.Run();
    }
}

MapControllerRoute is used to create a single route. The single route is named default route. Most apps with controllers and views use a route template similar to the default route. REST APIs should use attribute routing.

The route template “{controller=Home}/{action=Index}/{id?}”:

Matches a URL path like /Products/Details/5

Extracts the route values { controller = Products, action = Details, id = 5 } by tokenizing the path. The extraction of route values results in a match if the app has a controller named ProductsController and a Details action.

  • The first path segment, {controller=Home}, maps to the controller name.
  • The second segment, {action=Index}, maps to the action name.
  • The third segment, {id?} is used for an optional id. The ? in {id?} makes it optional. id is used to map to a model entity.

Using this default route, the URL path:

  • /Products/List maps to the ProductsController.List action.
  • /Blog/Article/17 maps to BlogController.Article and typically model binds the id parameter to 17

Controller and Actions:

Create controllers and actions following the naming conventions:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

URL Generation:

Use Url.Action or Html.ActionLink to generate URLs based on route templates.

<a asp-controller="Home" asp-action="Index">Home</a>

Multiple conventional routes

We can define multiple conventional routes. There is no restriction to how many MapControllerRoute we call in Program.cs. We use this to add convention based routing for different style of endpoints

app.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");

The route for the  blog in the example above is called a dedicated conventional route. It’s called a dedicated conventional route because:

  • It uses conventional routing.
  • It’s dedicated to a specific action.

Because controller and action don’t appear in the route template "blog/{*article}" as parameters:

  • They can only have the default values { controller = "Blog", action = "Article" }.
  • This route always maps to the action BlogController.Article.

/Blog/Blog/Article, and /Blog/{any-string} are the only URL paths that match the blog route.

The preceding example:

  • blog route has a higher priority for matches than the default route because it is added first.
  • Is an example of slug style routing where it’s typical to have an article name as part of the URL.

Deep Dive Analysis:

Flexibility and Predictability:

Conventional routing offers a balance between flexibility and predictability, allowing developers to define URL patterns logically while adhering to naming conventions.

Convention over Configuration:

By following conventions, developers can avoid explicit route configuration in most cases, promoting a standardized structure across the application.

Parameter Binding:

Conventional routing automatically binds URL segments to action method parameters, simplifying data retrieval from requests.

Conclusion:

Conventional routing in .NET Core 6 MVC applications streamlines URL mapping by leveraging naming conventions and route templates. Understanding this routing mechanism is essential for building scalable, maintainable, and predictable web applications in ASP.NET Core MVC.

By harnessing the power of conventional routing, developers can create structured and consistent URL patterns, enhancing the overall architecture and usability of their applications.


.NET Core: Understanding Routing, Middleware and Endpoints?

This blog post will take a deep dive in the world of .NET Core Routing. It will try to enhance your understanding of how routing works. What role middleware and endpoints play.

.NET Core provides a powerful framework for building web applications, offering robust features like routing, middleware, and endpoints. These components play crucial roles in managing incoming HTTP requests, processing them, and generating responses.

What is Routing?

Routing refers to the process of matching incoming HTTP requests to specific endpoints or actions within the application. It determines which code should handle a particular request based on the URL pattern.

Apps can configure routing using:

  • Controllers
  • Razor Pages
  • SignalR
  • gRPC Services
  • Endpoint-enabled middleware.
  • Delegates and lambdas registered with routing.

What is a Middleware?

Middleware’s are software code, it is injected into the .NET Core app pipeline to handle requests and responses. In almost all cases they are not the final destination of the request, instead they are used to do some pre-tasks before the request can be passed on to the Action.

  1. Each of these component has a choice if it wants to pass on the control to the next middleware in the pipeline.
  2. These can perform action before and after the next component in the pipeline.

Web Application pipeline using middleware

What are Endpoints?

For each app the smallest unit of code or a method which can be directly hit by an HTTP request is called Endpoints. These URL based addresses can carry relevant data which are parsed and sent to the Method being requested by the endpoint.

Basic Routing.

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

As you may have guessed that this is the basic form of routing, we have mapped the HTTP GET call to the root URL to a anonymous function which writes Hello World on the HTTP response. This is the simplest form of middleware.

Let us modify the code a bit more to show how to use custom middleware in the pipeline which runs before the URL is mapped .

app.Use(async (context, next) =>
{
    // ...
    await next(context);
});

app.UseRouting();

app.MapGet("/", () => "Hello World extended!");

app.Run();

The code above does the following

  • app.Use registers a custom middleware that should run at the beginning of the pipeline.
  • UseRouting  makes sure that the custom middleware euns before the route matching middleware.
  • MapGet registers the endpoint which runs at the end of the pipeline.

Important aspect of this code is that UseRouting is responsible for the custom middleware running before the route matching middleware.

Middleware use the following statements to handle routing Run,Map and Use.

Run,Map and Use Middleware

Run Method

This can be called as terminal middleware. A terminal middleware doesnot call the next component in the pipeline. It is advised that these type of middleware is placed at the end of the pipeline.

Use Method

This middleware can be used for configuration and is designed to call the next middleware in the pipeline and wait for it to complete before continuing further. Use method may be forced to become a terminal component like Run but it isnt advised. If you look at .NET MVC you will see USE is by far the most used middleware.

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

This is an example of the components used by .NET Core MVC.

Lets try and see how the flow of Use and Run works. In the following code we will see that the Use Middleware after running the initial logic waits for the next to finish and then continues to finish its logic.

app.Use(async (ctx, nxt) =>
{
    await ctx.Response.WriteAsync("Middleware 1 Fired \n");
    await nxt();
    await ctx.Response.WriteAsync("Middleware 1 Ends \n");
});

app.Use(async (ctx, nxt) =>
{
    await ctx.Response.WriteAsync("Middleware 2 Fired\n");
    await nxt();
    await ctx.Response.WriteAsync("Middleware 2 Ends \n");
});

app.Run(async (ctx ) =>
{
    await ctx.Response.WriteAsync("Middleware RUN 1 Fired\n");
});


app.Run(async (ctx) =>
{
    await ctx.Response.WriteAsync("Middleware RUN 2 Fired \n");
});

The out put looks something like this.

As you can see in the output the second RUN is never called because the RUN middleware is a terminal component and each USE middleware waits for the next component to finish. The flow looks something like this.

Map Method

As the name suggests this method maps the request URL to a predefined action. They try to match the request path to the paths defined in the app.

app.Map("/path1", appVar =>
{
    appVar.Run(async context =>
    {
        await context.Response.WriteAsync("PATH1 RUN FIRED");
    });
});
app.Map("/path2", appVar2 =>
{
    appVar2.Run(async context =>
    {
        await context.Response.WriteAsync("PATH2 RUN FIRED");
    });
});
app.Map("/path3", appVar3 =>
{
    appVar3.Run(async context =>
    {
        await context.Response.WriteAsync("PATH3 RUN FIRED");
    });

});



app.Run(async (context) =>
{
    await context.Response.WriteAsync("Default Path Fired By RUN");
});

app.Run();



In the preceding code we are mapping different Paths/Endpoints to our anonymous methods. The output is something like this

Writing Custom Middleware

.NET Core gives you an option that you can create your own custom middleware. Middleware is generally a class which is exposed through an extension method.

  • This class must have a public contructor which accepts a RequestDelegate
  • A public method named Invoke or InvokeAsync. This method must:
    • Return a Task.
    • Accept a first parameter of type HttpContext.

Following code shows a sample class which sets the culture for the current request. The culture info is passed through the URL. https://localhost:5001/?culture=es-es.

public class RequestCultureMiddleware
{
    private readonly RequestDelegate _next;

    public RequestCultureMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var cultureQuery = context.Request.Query["culture"];
        if (!string.IsNullOrWhiteSpace(cultureQuery))
        {
            var culture = new CultureInfo(cultureQuery);

            CultureInfo.CurrentCulture = culture;
            CultureInfo.CurrentUICulture = culture;
        }

        // Call the next delegate/middleware in the pipeline.
        await _next(context);
    }
}

public static class RequestCultureMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestCulture(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestCultureMiddleware>();
    }
}

it can be used later as app.UseRequestCulture();

Conclusion

Routing, middleware, and endpoints form the backbone of request handling in ASP.NET Core applications. Understanding how routing directs incoming requests, how middleware processes them, and how endpoints define response generation is crucial for building robust and efficient web applications.

By leveraging these components effectively, developers can design scalable and maintainable applications in .NET Core, catering to various HTTP request-response scenarios.

Powered by WordPress & Theme by Anders Norén