Basic programming, .NET technology.

Azure Service Bus

 1. Overview

  • Message broker
  • Can decouple applications and services
  • Some common scenarios:
    • Messaging: Transfer business data
    • Decouple application: client and server don’t have to be online at the same time.
    • Topic and subscriptions: enable  1:n relationships between publisher and subscriber.
    • Message session: implement workflows that require message ordering or message deferral.
2. Queue
  • FIFO
  • Use case: point to point communication




3. Topic
  • Topic and subscription: subscription as a virtual queue of a topic. Each subscription receive a copy message


4. Receive Mode
  • Default is PeekLock mode
  • Receive mode: ReceiveAndDelete  and PeekLock
    • ReceiveAndDelete:
      • Service bus mark message as being consumed
      • The application can tolerate not processing a message if a failure occurs  
    • PeekLock
      • two-stage
      • it possible for the application cannot tolerate missing messages.
      • when Bus receives the request, it locks the message
      • after processing -> call CompleteAsync
      • some error occur -> call AbandonAsync
5. Security:

- Using Shared Access Signature
  • With Azure Portal -> use can define Share Access Policies for Namespaces, queues, topics, and their subscriptions
  • There are three policy rules:
    • Send
    • Listen
    • Manage
  • SAS can be applied on the namespace, entity (queue, topic), HTTP level, or  AMQP level
  • Use SAS Authorization
    • Connection string contains a rule name (SharedAccessKeyName) and rule key (SharedAccessKey) => when we pass it to any constructor or factory,  the SAS token provider is automatically created and populated.
  • Application usecase: => avoid use default Share Access Signature
    • Grant role/claims for the client as their responsibility


References:
Share:

7. ASP .Net core - Fundamentals - Logs

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

The log is one of the approaches to troubleshoot the application. So, Don't forget to implement the logs for your application.

Which kind of log provider is best: built-in or third party???
If your app integrates with Azure or deploys on Azure => use Application Insight
If your app deploys on-premise => use a structured log third party, for example, NLog

  1. Log level

LogLevelValueMethodDescription
Trace0LogTraceContain the most detailed messages. These messages may contain sensitive app data. These messages are disabled by default and should not be enabled in production.
Debug1LogDebugFor debugging and development. Use caution in production due to the high volume.
Information2LogInformationTracks the general flow of the app. May have long-term value.
Warning3LogWarningFor abnormal or unexpected events. Typically includes errors or conditions that don't cause the app to fail.
Error4LogErrorFor errors and exceptions that cannot be handled. These messages indicate a failure in the current operation or request, not an app-wide failure.
Critical5LogCriticalFor failures that require immediate attention. Examples: data loss scenarios, out of disk space.
None6
Specifies that a logging category should not write any messages.
  1. Built-in logging provider

  1. Third-party logging provider
    • NLog
    • Serilog

  1. How to use AppInsight and Telemetry
a. step 1: Enable .net core API use AppInsight
    • Create an AppInsight resource via Azure Portal.
    • Get the information of instrumentation key or connection string
b. step 2: Configure something of AppInsight in .net core API
    • Add Nuget package
      • Microsoft.ApplicationInsights.AspNetCore
    • ConfigureService
public void ConfigureServices(IServiceCollection services)
{
...
services.AddApplicationInsightsTelemetry(Configuration["ApplicationInsights:ConnectionString"]);
}
    • Important: some Azure region requires a connection string instead of  Instrumentation key
    • Note: You can also configure AppInsight following these recommendations
It's best practice to have an extension method to do the configuration, see:
public static IServiceCollection AddTelemetry(this IServiceCollection services, IConfiguration configuration)
{
services.AddApplicationInsightsTelemetry(options =>
{
var appSettings =configuration.GetAppSettings();
options.InstrumentationKey = appSettings.AIKey;
//we want to know when the worker stops
options.EnableHeartbeat = true;
options.EnableAdaptiveSampling = false;
});
services.AddTelemetryService(configuration.GetAppSettings());
return services;
}

c. step 3 raise custom metric in AppInsight
    • Use TelemetryClient
TelemetryClient _telemetryClient;
...
[HttpGet]
public string Get()
{
_telemetryClient.TrackMetric("CustomMetricExample22", 1, new Dictionary<string, string> { { "Value", "22" } });
...
}
      • The best practice is to create a wrapper class for TelemetryClient

References:

Share:

8. [Updated] ASP .Net core - Fundamentals - Error Handling

This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

There are some ways to handle exceptions while we working with Asp .net core

1. Use try-catch block
a. Best practice when using "throw"
    • Throw ex: loose stack trace on downstream layer
      • For example, an exception has occurred in the Data layer, Business layer catch this exception and use 'Throw Ex', at API layer will lose stack trace
      • Shouldn't use like this
    • Throw: keep stack trace on downstream layer
      • For example, an exception has occurred in the Data layer, Business layer catch this exception and use 'Throw', at API layer will get a stack trace in detail
      • Should use like this
    • Throw new Exception: it will make downstream layer losing stack trace in detail
      • Only use at a lower level, the downstream level should use "Throw", we will keep stack trace on the downstream level


3. Validation DDD
There are 4 possible ways to implement validation.

  • IsValid method: transition an entity to a state (potentially invalid) and ask it to validate itself.
  • Validation in application services.
  • TryExecute pattern.
  • Execute / CanExecute pattern.
There are two major types of validation.

  • Task-based where you don’t need to map validation errors to UI elements.
  • CRUD-y where you do need to do that.
The Execute / TryExecute pattern works best for task-based scenarios. For CRUD scenarios, you need to choose between Execute / TryExecute and validation in application services. The choice comes down to purity versus ease of implementation.

4. Centralize exception handling with IExceptionFilter
  • Implement an ExceptionFilter class


  • Add to the configuration method


  • Throw an exception when needed.


5. [From ASP.NET Core 8] - Use IExceptionHandler

The built-in exception handler middleware uses IExceptionHandler implementations to handle exceptions.

This interface has only one TryHandleAsync method.
  • If Exception can handle => return true;
  • If Not => return false
  • Can implement a custom logic in the method
Basic usage:

Implement of IExceptionHandler

public class GlobalExceptionHandler : IExceptionHandler
    {
        private readonly ILogger<GlobalExceptionHandler> logger;

        public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
        {
            this.logger = logger;
        }

        public async ValueTask<bool> TryHandleAsync(
            HttpContext httpContext,
            Exception exception,
            CancellationToken cancellationToken)
        {
            this.logger.LogError(exception, "Exception occurred: {Message}", exception.Message);

            var problemDetails = new ProblemDetails
            {
                Status = StatusCodes.Status500InternalServerError,
                Title = "Server error -- apply IExceptionHandler for Global"
            };

            httpContext.Response.StatusCode = problemDetails.Status.Value;

            await httpContext.Response
                .WriteAsJsonAsync(problemDetails, cancellationToken);

            return true;
        }
    }


Use the handler in Program file

// User Exception Handler
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();

Exception Handler in new way (sample)


References:

[Microsoft Learn] - Handle errors in ASP.NET Core

Share:

9. [Updated] - ASP .Net core - Fundamentals - Routing

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

  • Routing is responsible for matching incoming HTTP requests and dispatching those requests to the app's executable endpoints
  • How to use - [From ASP. Net Core 3.0]
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();

    // Add the EndpointRoutingMiddleware
    app.UseRouting();

    // All middleware between UseRouting and UseEndpoints will know which endpoint will be invoked
    // can be benerfits from it to do some logical checks
    // For instances:
    app.UseCors();
    app.UseAuthentication();
    app.UseAuthorization();

    // Execute the endpoint selected by the routing middleware
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}


From "UseRouting" to "UseEndpoints" is called Routing zone, some highlighted points:
  • The endpoint is always null before UseRouting is called.
  • If a match is found, the endpoint is non-null between UseRouting and UseEndpoints.
  • The UseEndpoints middleware is terminal when a match is found.
  • The middleware after UseEndpoints execute only when no match is found.

  • Endpoint routing
            You can attach metadata to endpoints so intermediate middleware (e.g. Authorization, CORS) can know what will be eventually executed For example: MapHealthChecks

app.UseAuthentication();
app.UseAuthorization();

app.MapHealthChecks("/healthz").RequireAuthorization();


How to create a endpoint routing aware:
  • Write an extension method on IEndpointRouteBuilder.
  • Create a nested middleware pipeline using CreateApplicationBuilder.
  • Attach the middleware to the new pipeline.
  • Build the middleware pipeline into a RequestDelegate.
  • Call Map and provide the new middleware pipeline.
  • Return the builder object provided by Map from the extension method.

References:
Share:

10. ASP .Net core - Fundamentals - Make an HTTP request

This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

This part shows us some ways to make an HTTP request against a web service/ web api.

1. Issues when using HttpClient:

  • Socket exhaustion
  • DNS changes not reflecting
To get more information concerning these issues, you can read this article.

2. Solution in .NET Core is:
  • use IHttpClientFactory
  • Some consumption patterns:
    2.1 Basic usage:
            - Add HttpClient to the services container
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.

            - Use Dependency Injection to use IHttpClientFactory.CreateClient()
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
....
var client = _clientFactory.CreateClient();

    2.2. Named clients:

            - Add HttpClient to services:
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});

            - Create clients
var client = _clientFactory.CreateClient("github");

    2.3. Typed Client:
      • It's similar to create a new service class that wraps HttpClient
    2.4. Generated clients: used in combination with the third party

3. Configure HttpMessageHandler
    • Can be used in case you want to control the configuration of  the inner HttpMessageHandler
      • An example is to bypass SSL Server Certificate
    • Use the extension method: ConfigurePrimaryHttpMessageHandler to create and configure
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});

services.AddHttpClient(ONPREMISEHTTPCLIENT)
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (_, __, ___, ____) => true
};
});

  • Header propagation

References:
https://www.rahulpnath.com/blog/are-you-using-httpclient-in-the-right-way/

Share:

11. Asp .Net core - Fundamentals - Static files

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 12: Authentication and Authorization.

Part 13: CORS.


There is how to use static files in Asp .net core:


  • Serve file in wwwroot:
app.UseStaticFiles();

  • Serve file outside wwwroot:

// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});

  • Static file authorization
    • Actually, UseStaticFiles middleware is called before UseAuthorization. Most apps follow this pattern => No authorization when static file served.
    • If you want authentication before serving a static file, should do:
// Configure method
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});

AND: // ConfigureService method
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});

  • Direct browsing
  • Fileserver configuration

References:
Share:

12 - [Updated] - Security - Authentication/ Authorization

This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 13: CORS.


1. Knowledge and basic usages:

  • Authentication is the way you enter space (server/ database/resource..)
    • Authentication with google (example )
    • Authentication with Azure Active Directory
    • Authentication with Twitter
    • Authentication with Linked...

  • Authorization is actions that you can do in those space
    • Role-based:
      • Adding role check: We can apply role check on controller level or action level as we want.
[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
}

a. Multiple roles: OR condition. It means the current user is HRManager or Finance
[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
}

b. Multiple roles: AND condition. It mean current user are both PowerUser and ControlPanelUser
[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
}

    • Policy-based role check
      • Add Policy in a startup file
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole",
policy => policy.RequireRole("Administrator"));
});
}
    • Use the policy to check authorization at controller level or action level by using Policy property on Authorize attribute
[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown()
{
return View();
}

    • Claim based
      • A claim is a name value pair that represents what the subject is, not what the subject can do.
      • Add claim check
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("EmployeeOnly", policy =>
policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
});
}


Using:

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
public ActionResult VacationBalance()
{
}
}



2. [Updated][ASP .NET Core 8 +] - Using IAuthorizationRequirementData

Scenarios may be useful:
- Using an external service to provide policy evaluation.
- Using a large range of policies, so it doesn't make sense to add each individual authorization policy with an AuthorizationOptions.AddPolicy call.
- Creating policies at runtime based on information in an external data source (like a database) or determining authorization requirements dynamically through another mechanism.

My code sample

References:


Share:

13 - Security - CORS

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.


CORS: Cross origin resource sharing

  • How to allow CORS
    • AddCors in ConfigureServices method
    • UseCors in Configure method
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
///....
}
}

References:
Share:

5. ASP .Net core - Fundamentals - Configuration

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: DI.

Part 3: Middleware.

Part 4: Host and Servers.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.


This part shows how to use configuration and how to use Options patterns.

    1. Default configuration
a. ChaninedConfigurationProvider
b. appsettings.json
c. appsettings.[environment].json
d. app secrets
e. environment variables
f. command-line arguments.

Configuration providers that are added later override the previous key setting.

    • JsonConfigurationProvider loads configuration in the following order:
      • appsettings.json
      • appsetings.{Environment}.json
=>  appsetings.{Environment}.json values override keys in appsettings.json

private readonly IConfiguration _configuration;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration)
{
......
}

public WeatherForecast Get()
{
var a = new WeatherForecast
{
// Get value from configureation
Name = _configuration["Name"],
NickName = _configuration["NickName"]
};
return a;
}

  1. Options pattern to read a related configuration
public class PositionOptions
{
public string Title { get; set; }
public string Name { get; set; }
}
...
var positionOptions = new PositionOptions();
Configuration.GetSection("JsonKeySection").Bind(positionOptions);

OR:
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();

  1. Combining service collection
a. How to register configures option in ConfigureServices method
    • step 0: create Option class
    • step 1: create extension method:
      • first param: IServiveCollection
      • second param: IConfiguration/ or Action<OptionClass>
      • Use: services.Configure method to register configuration
    • step 2: use extension method to register the service.
services.Configure<PositionOptions>( config.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>( config.GetSection(ColorOptions.Color));

b. How to get value of Option at another places
    • Method 1: Use: IServiceProvider serviceProvider to get option value,
Name = _serviceProvider.GetRequiredService<IOptions<PositionOption>>().Value.Name,
NickName = _serviceProvider.GetRequiredService<IOptions<PositionOption>>().Value.Position


    • Method 2:
IOptions<PositionOption> _optionDelegate;
....
// Get value from Option
Name = _optionDelegate.Value.Name,
NickName = _optionDelegate.Value.Position

  1. File configuration provider
  • Json configuration provider
    • use: config.AddJsonFile("MyConfig.json", optional: true, reloadOnChange: true)
      • to add custom config json file
      • This file override settings in the default configuration providers (include environment vars and command-line)
  • XML configuration provider
    • use: AddXmlFile

  1. Others config
a. launchsetting.json
b. web.config


A sample of applying options pattern


References:
Share:

4. ASP .Net core - Fundamentals - Host and Server

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.

Part 1: Startup file.

Part 2: Dependency injection.

Part 3: Middleware.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

In this part, I  got some knowledge about Host and Servers in ASP .Net core

4.1 Host

  • Generic host
  • Web host

- Host is an object that encapsulates:
  • DI
  • Logging
  • Configuration
  • IHostedService implementations
- How to set up a host: Program, Main, CreateHostBuilder
- Default builder setting:
  • CreateDefaultBuilder: content root, host configs, app configs, add logging providers
  • ConfigureWebHostDefault: host configs, set kestrel server....
- Host configuration: how to do? =>  ConfigureHostConfiguration
- App configuration: how to do? => ConfigurAppConfiguration

4.2 Server
  • Kestrel
  • Http.sys
  • Hosting model:
    • in-process hosting
    • out-of-process hosting

References:
Share:

3. Asp.net core - fundamentals - Middleware

 This series is a collection of knowledge about ASP .NET Core. It just is my notes.


Part 1: Startup file.

Part 2: Dependency Injection.

Part 4: Host and Servers.

Part 5: Configurations.

Part 6: Environment.

Part 7: Logs.

Part 8: Error Handling.

Part 9: Routing.

Part 10: Make an HTTP Request.

Part 11: Static files.

Part 12: Authentication and Authorization.

Part 13: CORS.

This part is to summarise some knowledge concerning the Middleware in Asp .net core.

a. What is middleware
  • Middleware is software added to the pipeline to process requests and responses.
  • When a request comes, it goes through one by one middleware (you can think that all middleware do the common process for each request, response)
  • To use middleware in IApplicationBuilder, use:
    • Run: param: context
    • Use: param: context, next -> to invoke next middleware
    • Map: to branch middleware
  • We have some built-in middleware, we can use them in configure method.
  • Of course, we can also create custom middleware.
b. Order of middleware



--> Endpoint middleware to turn the request into an action method in the controller.



c. How to create a custom middleware
  • step 1: Encapsulate custom middleware in class
    • Convention: {Name}Middleware
    • Include:
      • a constructor with parameter type is "ContextDelegate".
      • A public method is named Invoke or InvokeAsync. This method must:
    • For example:
public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
// IMyScopedService is injected into Invoke
public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
{
svc.MyProperty = 1000;
await _next(httpContext);
}
}

  • step 2: create a middleware extension method through IApplicationBuilder:
    • Name convention: Use{MiddlewareName}
using Microsoft.AspNetCore.Builder;
namespace Culture
{
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}

  • step 3: Call middleware in Configure method
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRequestCulture();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}


References:

Share:

Featured Posts

Data type 3 - string type