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 9.0 Hosting - HostForLIFE :: Implement JWT Token in Net Core Api

clock January 16, 2025 07:06 by author Peter

The ASP.NET Core API's JWT (JSON Web Token) authentication provides a safe and effective method for managing user authorization and authentication. A detailed guide to configuring JWT authentication in an ASP.NET Core Web API can be found here.

Install Required NuGet Packages

Configure JWT Authentication
Update Program.cs to configure JWT authentication in the service section and middleware section.

builder.Services.AddAuthentication(opt =>
{
    opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(opt =>
{   // for development only
    opt.RequireHttpsMetadata = false;
    opt.SaveToken = true;
    opt.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["JWT:SecretKey"])),
        ValidateIssuer = true,
        ValidIssuer = builder.Configuration["JWT:Issuer"],
        ValidateAudience = true,
        ValidAudience = builder.Configuration["JWT:Audience"]
    };
});

builder.Services.AddAuthorization();

var app = builder.Build();

// Use authentication and authorization
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();


This configuration sets up the application to authenticate incoming requests using the JWT tokens and validate them based on certain parameters.

Generate the JWT Tokens
public string GenerateJwtToken(string userName, string name, string role)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_configuration["JWT:SecretKey"]);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[]
        {
            new Claim(ClaimTypes.Name, userName),
            new Claim(ClaimTypes.GivenName, name),
            new Claim(ClaimTypes.Role, role)
        }),
        IssuedAt = DateTime.UtcNow,
        Issuer = _configuration["JWT:Issuer"],
        Audience = _configuration["JWT:Audience"],
        Expires = DateTime.UtcNow.AddMinutes(30), // can change exprires time
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    var userToken = tokenHandler.WriteToken(token);

    return userToken;
}

Authenticate Users And Issue The JWT Tokens
[HttpPost("login")]
public IActionResult Login(LoginModel model)
{
    // Authenticate user
    var user = _userService.Authenticate(model.Username, model.Password);

    if (user == null)
        return Unauthorized();

    // Generate JWT token
    var token = _authenticationService.GenerateJwtToken(
        user.userName,
        user.Name,
        user.Role
    );

    return Ok(new { token });
}


Secure Your API Endpoints
Add the [Authorize] attribute to protect API endpoints. Example.
[ApiController]
[Route("api/[controller]")]
public class ProtectedController : ControllerBase
{
    [HttpGet]
    [Authorize]
    public IActionResult GetSecureData()
    {
        return Ok(new { Message = "This is a secure endpoint." });
    }
}


Test Your .NET JWT Authentication
Use a tool like Postman or cURL to test the endpoints.
First, call the /api/auth/login endpoint with valid credentials to get a token.
Use the token in the Authorization header of subsequent requests to protected endpoints:
Authorization: Bearer <your-jwt-token>

JWT token part
A JWT (JSON Web Token) consists of three parts, separated by dots (.): Header, Payload, and Signature. Here's a breakdown of these parts.

Header
The header typically consists of two fields.

  • alg: The signing algorithm used (e.g., HS256 for HMAC-SHA256).
  • typ: The type of the token, usually JWT.

{
"alg": "HS256",
"typ": "JWT"
}


Payload
The payload contains the claims. Claims are statements about the user or additional data. There are three types of claims.

  • Registered claims: Predefined claims like iss (issuer), exp (expiration), sub (subject), and aud (audience).
  • Public claims: Custom claims defined for specific use cases.
  • Private claims: Claims shared between parties that agree on them.

{
"sub": "1234567890",
"name": "peter",
"role": "Admin",
"iat": 1672545600,
"exp": 1672549200
}


Signature

The signature is used to verify the authenticity of the token and ensure that it hasn’t been tampered with.

The signature is created by,

Taking the encoded header and payload.

Concatenating them with a dot (.).
Hashing the result using the specified algorithm and a secret key.
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)


Final Token format

The JWT token is the concatenation of these three parts.
<base64UrlEncodedHeader>.<base64UrlEncodedPayload>.<base64UrlEncodedSignature>

Example
JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6IkFkbWluIiwiaWF0IjoxNjcyNTQ1NjAwLCJleHAiOjE2NzI1NDkyMDB9.DjKU_JB_b9PxwjU_x5U3wwtrLX7ZnZZ0mKXfTi5YYCU

Conclusion
Ultimately, we can say that authorization and authentication in.NET Core are essential to the safety and security of your application, and that using JWT authentication in.NET Core offers a reliable and secure way to authenticate users and safeguard web application resources. Data integrity and confidentiality are prioritized while.NET Core applications obtain scalability, flexibility, and interoperability with the inclusion of JWT authentication. This ensures a smooth user experience. Adopting.NET JWT authentication in.NET Core is still a crucial tactic for protecting private data and bolstering the integrity of contemporary web apps as technology advances.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Mastering [Produces("application/json")] in ASP.NET Core

clock January 10, 2025 06:32 by author Peter

If you're using ASP.NET Core to create reliable APIs, you've probably come across situations where answer format consistency is essential. It [Produces("application/json")] is useful in this situation. Let's examine its operation and the reasons it is revolutionary.

What does [Produces("application/json")] do?
It tells your API to always respond with JSON, regardless of the client’s request headers. No surprises just clean, predictable JSON responses every time.

Where and How to use It?
You can apply it at the controller or action level.
[Produces("application/json")]
[ApiController]
[Route("api/[controller]")]
public class ExampleController : ControllerBase
{
    [HttpGet]
    public IActionResult GetData()
    {
        var data = new { Message = "Hello, JSON!" };
        return Ok(data);
    }
}


What happens here?
Even if the client requests XML, your API says.
“Nope, JSON it is!”

Why use it?

  • Consistency: Ensures your API always speaks the same "language" (JSON).
  • Simplicity: Reduces unexpected behaviour caused by content negotiation.
  • Control: Guarantees the response format, no matter what the client expects.

Pro Tip
Want to support multiple formats (e.g., XML and JSON)? Use [Produces] with a list of content types.
[Produces("application/json", "application/xml")]

When to use It?

  • Use [Produces("application/json")] when.
  • Your API should always output JSON.
  • You want strict control over response formatting.
  • You’re building APIs for front-end frameworks or third-party clients that expect JSON.

In today’s API-driven world, it [Produces("application/json")] is your ally for predictable, reliable, and developer-friendly APIs. Start using it today to level up your API game.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: What Does Minimal API's MapGroup Mean?

clock January 6, 2025 07:58 by author Peter

A lightweight method for creating HTTP APIs is offered by.NET Core's minimal APIs. They were first introduced in.NET 6 and improved in subsequent iterations, enabling you to process HTTP requests and construct routes with less boilerplate. MapGroup is a potent component of Minimal APIs that facilitates effective route organization and structuring.

In this article, we’ll explore.What is MapGroup?

  • Benefits of using MapGroup.
  • Pros and cons.
  • When and why to use MapGroup.
  • A practical example to showcase its use.

What is MapGroup?
MapGroup is a feature in Minimal APIs that allows you to group related endpoints together under a common route prefix and configuration. It helps in organizing endpoints logically, making your codebase more readable and maintainable.

Mapping ground in a Minimal API refers to the process of defining routes and handling requests in a streamlined manner, leveraging the simplicity of .NET's Minimal APIs. This approach allows developers to create lightweight web applications with less boilerplate code, enhancing productivity.
Example: Traditional vs. MapGroup

Without MapGroup
var app = builder.Build();

app.MapGet("/users", () => "List of users");
app.MapGet("/users/{id}", (int id) => $"User details for {id}");
app.MapPost("/users", () => "Create a new user");

app.Run();


With MapGroup

var app = builder.Build();
var usersGroup = app.MapGroup("/users");

usersGroup.MapGet("/", () => "List of users");
usersGroup.MapGet("/{id}", (int id) => $"User details for {id}");
usersGroup.MapPost("/", () => "Create a new user");

app.Run();


By using MapGroup, all endpoints under /users are grouped together, improving organization and scalability.

Key Features of MapGroup

  • Route Prefixing: Automatically applies a common prefix to all endpoints within the group.
  • Shared Middleware: Apply middleware like authentication or logging to all endpoints in a group.
  • Logical Organization: Separate concerns by grouping related endpoints (e.g., /users, /orders).

Practical Example
Here’s a complete example of using MapGroup with additional configurations.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Users Group
var usersGroup = app.MapGroup("/users")
                    .RequireAuthorization()
                    .WithOpenApi();

usersGroup.MapGet("/", () => "List of users");
usersGroup.MapGet("/{id:int}", (int id) => $"User details for {id}");
usersGroup.MapPost("/", () => "Create a new user");

// Orders Group
var ordersGroup = app.MapGroup("/orders")
                     .AddEndpointFilter(async (context, next) =>
                     {
                         // Example filter logic
                         Console.WriteLine("Processing order request");
                         return await next(context);
                     });

ordersGroup.MapGet("/", () => "List of orders");
ordersGroup.MapPost("/", () => "Create a new order");

app.Run();

Benefits of MapGroup

  • Clean Code Organization: MapGroup enables logical grouping of related routes, reducing clutter in your Program.cs file.
  • Shared Middleware: Apply middleware like authorization, logging, or custom filters to an entire group instead of individual endpoints.
  • Route Consistency: It automatically adds a common prefix to all routes, avoiding duplication and potential errors.
  • Scalability: As your API grows, you can easily manage and extend endpoint groups without impacting unrelated routes.
  • Enhanced Maintainability: Improves the readability of your codebase, making it easier for teams to collaborate and manage.
  • Simplicity: Minimal APIs reduce the complexity of setting up a web server.
  • Performance: They are lightweight, leading to faster response times.
  • Flexibility: Easy to modify and extend as requirements change.

Pros and Cons

Pros

  • Simplifies route definitions.
  • Reduces code duplication for common configurations.
  • Works seamlessly with middleware and filters.
  • Enhances readability and maintainability.
  • Less code to manage.
  • Quick to set up and deploy.
  • Ideal for microservices and small applications.

Cons

  • Only available in the Minimal API approach.
  • Teams accustomed to traditional controllers may face a learning curve.
  • Misconfiguration in a group could affect multiple endpoints.
  • Limited features compared to full-fledged frameworks.
  • May not be suitable for large applications requiring extensive routing and middleware.

When and Why to Use MapGroup?
When to Use
Consider using Minimal APIs when developing small to medium-sized applications, microservices, or when rapid prototyping is needed. They are particularly beneficial when you want to focus on specific functionalities without the overhead of a traditional MVC framework.

You’re building an API with Minimal APIs and need to manage multiple related routes.
You want to apply common configurations, such as authentication, to a set of routes.
Your project requires scalability, with endpoints logically organized by feature or resource.

Why Use

  • To keep your Program.cs file manageable as your API grows.
  • To improve the readability and structure of your Minimal API.
  • To enforce consistency in route prefixes and middleware usage.

mapping ground in Minimal API is a powerful approach for developers looking to create efficient and straightforward web applications in .NET.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Unit Testing in .NET Core with xUnit

clock December 17, 2024 07:24 by author Peter

Unit testing is a key component of software testing that developers can handle on their own. It is used to test the smallest components of your code. As you write your code, you may use unit tests to make sure it is working as expected or yielding the desired outcomes.

All developers benefit from testing the code before submitting it to source control. NUnit, xUnit, and other frameworks are among the many available for unit testing. We shall examine the unit testing procedure in this article.

initiative for the Net Web API. Here, we are utilizing the xUnit framework, which is a free and open-source tool, to achieve the same goal. web development. Here, we'll start by addressing the most basic functions.

Creating a Testing Project
At last, we reach the stage where our tests will require the creation of a new project. We will take advantage of the handy xUnit testing project template that comes with Visual Studio 2022 when we use it.

An open-source unit testing tool for the.NET framework called xUnit makes testing easier and frees up more time to concentrate on creating tests:

In order to inject the IEmployeeService interface into our controller during testing, we now need to construct our fictitious implementation of the interface. We are going to populate its in-memory collection with our fictitious data.
public class EmployeeServiceFake : IEmployeeService
{
    public readonly Dictionary<Guid, Employee> _employees;

    public EmployeeServiceFake()
    {
        _employees = new Dictionary<Guid, Employee>
        {
            {
                new Guid("503df499-cabb-4699-8381-d76917365a9d"),
                new Employee
                {
                    Id = new Guid("503df499-cabb-4699-8381-d76917365a9d"),
                    Name = "Name1",
                    Mno = "1234567890",
                    Salary = 36000,
                    Type = EmployeeType.Permanent
                }
            },
            {
                new Guid("77cf78a6-d6e8-4d50-afeb-39eae4567c62"),
                new Employee
                {
                    Id = new Guid("77cf78a6-d6e8-4d50-afeb-39eae4567c62"),
                    Name = "Name2",
                    Mno = "1234567890",
                    Salary = 24000,
                    Type = EmployeeType.Temporary
                }
            }
        };
    }
    public bool Exists(Guid id)
    {
        return _employees.ContainsKey(id);
    }
    public Guid Create(Employee employee)
    {
        _employees.Add(employee.Id, employee);
        return employee.Id;
    }
    public void Delete(Guid id)
    {
        _employees.Remove(id);
    }
    public List<Employee> GetAll()
    {
        return _employees.Values.ToList();
    }
    public Employee GetById(Guid id)
    {
        if (!_employees.ContainsKey(id))
        {
            return null;
        }
        return _employees[id];
    }
    public Guid Update(Employee employee)
    {
        var emp = _employees[employee.Id];
        emp.Mno = employee.Mno;
        emp.Name = employee.Name;
        emp.Type = employee.Type;
        emp.Salary = employee.Salary;
        _employees[employee.Id] = emp;
        return employee.Id;
    }
}


Write some unit tests, please! We are now prepared to write tests for our EmpController's first GetAll method.

The xUnit framework uses the [Fact] attribute, which we will use to decorate test methods to identify them as the real testing methods. In the test class, in addition to the test methods, we can have an infinite number of helper methods.

The AAA principle (Arrange, Act, and Assert) is typically followed when writing unit tests.

  • Arrange: this is the part where you usually get everything ready for the test or put another way, you get the scene ready for the test (making the objects and arranging them as needed).
  • Act: Here is where the procedure that we are testing is carried out.
  • Assert: In this last section of the test, we contrast the actual outcome of the test method's execution with our expectations.

Testing Our Actions
We will want to confirm the following in the Get method, which is the first method we are testing.

  • Whether the method yields the OkObjectResult, a response code of 200 for an HTTP request.
  • Whether the returned object includes every item in our list of Emps.

Testing the Get Method
public class EmployeeControllerTest
{
    private readonly EmployeeController _employeeController;
    private readonly IEmployeeService _employeeService;

    public EmployeeControllerTest()
    {
        _employeeService = new EmployeeServiceFake();
        _employeeController = new EmployeeController(_employeeService);
    }
    [Fact]
    public void Get_WhenCalled_ReturnsOkResult()
    {
        // Act
        var response = _employeeController.GetAll();
        // Assert
        Assert.IsType<OkObjectResult>(response as OkObjectResult);
    }
    [Fact]
    public void Get_WhenCalled_ReturnsAllItems()
    {
        // Act
        var response = _employeeController.GetAll() as OkObjectResult;
        // Assert
        var result = Assert.IsType<List<Employee>>(response.Value);
        Assert.Equal(2, result.Count);
    }
}


The class we wish to test is the one in which we create an instance of the EmployeeController object. It's crucial to remember that this constructor is called before every test method, which implies that the test is always run on a new object and the controller state is always reset.

This is crucial because, regardless of how often or in what order we run the tests, the test methods ought to be independent of one another and should yield consistent testing outcomes.

Testing the GetById Method
[Fact]
public void GetById_FakeGuidPassed_ReturnsNotFound()
{
    // Arrange
    var empId = Guid.NewGuid();
    // Act
    var response = _employeeController.GetById(empId);
    // Assert
    Assert.IsType<NotFoundResult>(response);
}
[Fact]
public void GetById_ValidGuidPassed_ReturnsOk()
{
    // Arrange
    var empId = new Guid("503df499-cabb-4699-8381-d76917365a9d");
    // Act
    var response = _employeeController.GetById(empId);
    // Assert
    Assert.IsType<OkObjectResult>(response);
}
[Fact]
public void GetById_ValidGuidPassed_ReturnsEmp()
{
    // Arrange
    var empId = new Guid("503df499-cabb-4699-8381-d76917365a9d");
    // Act
    var response = _employeeController.GetById(empId) as OkObjectResult;
    // Assert
    Assert.IsType<Employee>(response.Value);
    Assert.Equal(empId, (response.Value as Employee).Id);
}

Testing the Create Method
[Fact]
public void Create_Invalid_ReturnsBadRequest()
{
    // Arrange
    Employee? employee = null;
    // Act
    var response = _employeeController.Create(employee);
    // Assert
    Assert.IsType<BadRequestResult>(response);
}
[Fact]
public void Create_AlreadyExists_ReturnsBadRequest()
{
    // Arrange
    var employee = new Employee
    {
        Id = new Guid("503df499-cabb-4699-8381-d76917365a9d"),
        Name = "Name1",
        Mno = "1234567890",
        Salary = 36000,
        Type = EmployeeType.Permanent
    };
    // Act
    var response = _employeeController.Create(employee);
    // Assert
    Assert.IsType<BadRequestResult>(response);
}
[Fact]
public void Create_ValidEmployee_ReturnsOk()
{
    // Arrange
    var employee = new Employee
    {
        Id = Guid.NewGuid(),
        Name = "Name1",
        Mno = "1234567890",
        Salary = 36000,
        Type = EmployeeType.Permanent
    };
    // Act
    var response = _employeeController.Create(employee);
    // Assert
    Assert.IsType<CreatedAtActionResult>(response);
}
[Fact]
public void Create_ValidEmployee_ReturnsResponseItem()
{
    // Arrange
    var employee = new Employee
    {
        Id = Guid.NewGuid(),
        Name = "Name1",
        Mno = "1234567890",
        Salary = 36000,
        Type = EmployeeType.Permanent
    };
    // Act
    var response = _employeeController.Create(employee) as CreatedAtActionResult;
    var emp = response.Value as Employee;
    // Assert
    Assert.IsType<Employee>(emp);
    Assert.Equal(emp.Id, employee.Id);
}

In brief
The test scenarios for our EmployeeController are now complete, and we would like to briefly review some general unit testing guidelines. When writing unit tests, there are a few standards or best practices you should aim for. It will undoubtedly make your life easier and the life of your fellow developers if you respect these practices.

  • Readability is a must for unit tests: Nobody wants to waste time attempting to decipher the purpose of your test. Ideally, it should be evident from the test name alone.
  • Maintainability is a must for unit tests: It is our goal to write our tests so that even small modifications to the code shouldn't require us to rewrite them all. We should treat our test code the same as the production code in this situation, adhering to the DRY (don't repeat yourself) principle. This lessens the likelihood that someone will eventually reach a point where it is too difficult for them to maintain all of our tests, and they must comment them out.
  • Unit sets ought to be quick: People are likely to run tests less frequently if they take too long to complete. That is undoubtedly undesirable, as nobody wants to have to wait around for tests to finish.
  • Dependencies shouldn't exist in unit tests: It is crucial that test execution be possible for everyone involved in the project without requiring access to an outside database or system. Testing must be done in complete isolation.
  • Make tests reliable instead of just focusing on code coverage: We should feel confident that we can find errors before they are introduced into the production system thanks to well-designed tests. It is simple to write tests that pass and have more code coverage by omitting certain assertions. However, there's no use in doing that. When it comes time to modify the code, we should make an effort to test the appropriate things so that we can rely on them.

In summary
This article has taught us the definition of unit testing and how to set up an xUnit project for unit testing. The fundamental scenarios for testing the controller logic on a few CRUD operations have also been taught to us. You should find these examples to be a great place to start when creating your own unit tests and testing larger, more intricate projects. Thank you for reading, and hopefully, this post will help you understand ASP.NET Core unit testing and concepts a little bit better. We learned the new technique and evolved together. Happy coding!



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Processing Invoices and Payments with Stripe in.NET

clock December 9, 2024 07:04 by author Peter

Stripe is one of the online and in-person payment processing systems. Its not open source. In below sample, we are using test version. We can do operations like create a customer, charge, invoices, refund, webook, etc.


In the below sample, I have used the Stripe.net package for Stripe payment processing in dotnet and Stripe REST API's.

The Card Tokenization with Angular 15 and various payment-related functionalities using tokens generated by Card tokenization will be covered in the upcoming article.

In this article, we will look at an operation.

  • Stripe Account Setup
  • Creation of Customer
  • Payment method and payment intent
  • Invoices and invoice line items
  • Charge
  • Refund

Stripe Account Setup
To begin using Stripe for payment integration, the first step is to create a Stripe account.

  • Step 1. Navigate to Stripe register.
  • Step 2. Fill out the required fields, such as email, full name, and password, country.
  • Step 3. After creating your account, Stripe will ask you for some business details (or personal details if you're using it as an individual) to complete the setup.

Stripe operates in both test mode and live mode. In test mode, you can simulate transactions without actually charging cards. Once everything is working as expected, you can switch to live mode to begin processing real payments.

Note. Stripe uses test mode by default. You can toggle to live mode from the dashboard once you're ready.

Customer
Install a stripe.net package from nuget manager to our project.


Create Customer
The customer is the main object which will hold multiple payment methods, invoices, and billing info. we can create customer for individual or business organization.

Code Sample
// Configures the Stripe SDK with the secret key for API communication
private void ConfigureStripe()
{
    // Retrieve the secret key from the configuration settings
    string? stripeSecretKey = _configuration.GetValue<string>("SecretKey");

    // Check if the secret key is null or empty; throw an exception if validation fails
    if (string.IsNullOrEmpty(stripeSecretKey))
    {
        throw new Exception("Stripe secret key is null or empty");
    }

    // Set the Stripe secret key to the SDK's global configuration
    StripeConfiguration.ApiKey = stripeSecretKey;
}

// Creates a new customer in the Stripe system using provided customer details
public Customer CreateCustomer(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a Stripe customer
        var options = new CustomerCreateOptions
        {
            Email = stripeCustomerRequest.Email,        // Customer's email address
            Name = stripeCustomerRequest.Name,          // Customer's full name
            Phone = stripeCustomerRequest.Phone,        // Customer's phone number
            Description = stripeCustomerRequest.Description // Description for the customer (e.g., reason for account creation)
        };

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Create and return the new customer by making an API call to Stripe
        return service.Create(options);
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create customer", ex);
    }
}


Create customers with tokenization
Creates a new customer in the Stripe system, associating a payment source; basically, it will create a customer after getting card info from users.

Code Sample
// Creates a new customer in the Stripe system, associating a payment source (e.g., tokenized card)
public Customer CreateCustomerWithToken(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a Stripe customer with a payment source
        var options = new CustomerCreateOptions
        {
            Email = stripeCustomerRequest.Email,                 // Customer's email address
            Name = stripeCustomerRequest.Name,                   // Customer's full name
            Phone = stripeCustomerRequest.Phone,                 // Customer's phone number
            Description = stripeCustomerRequest.Description,     // Description for the customer
            Source = stripeCustomerRequest.SourceID              // Token representing a payment source (e.g., card details)
        };

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Create and return the new customer by making an API call to Stripe
        return service.Create(options);
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create customer with token", ex);
    }
}

Update Customer
We can update existing customers using customer ID. We can update the info like email, phone, description, source ID, etc.

Code Sample
// Updates an existing customer in the Stripe system with the provided customer details.
public Customer UpdateCustomer(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Create an instance of CustomerUpdateOptions to define the fields to update
        var options = new CustomerUpdateOptions
        {
            Email = stripeCustomerRequest.Email,        // Update customer's email address
            Name = stripeCustomerRequest.Name,          // Update customer's full name
            Phone = stripeCustomerRequest.Phone,        // Update customer's phone number
            Description = stripeCustomerRequest.Description // Update description (e.g., reason for the update)
        };

        // If SourceID is provided, add it to the options to update the payment method (e.g., a new token)
        if (!string.IsNullOrEmpty(stripeCustomerRequest.SourceID))
        {
            options.Source = stripeCustomerRequest.SourceID; // Update the payment source for the customer
        }

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Update the customer by calling the Update method with the customer ID and the update options
        return service.Update(stripeCustomerRequest.CustomerID, options);
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to update customer", ex);
    }
}


Stripe Customer Request Class
public class StripeCustomerRequest
{
    public string Email { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string CustomerID { get; set; }
    public string Description { get; set; }
    public string SourceID { get; set; }
}


Payment Method
A payment method is a way that customers pay for a product or service. In a brick-and-mortar store, accepted payment methods may include cash, a gift card, credit cards, prepaid cards, debit cards, or mobile payments.

Stripe will support various cards, debit, wallets, real-time transfers, bank transfers, etc.

In this sample, we are using a credit card as a payment method.

Create payment method

Code Sample
// Creates a new payment method (credit card) in Stripe
public PaymentMethod CreatePaymentMethod(CreatePaymentMethodRequest createPaymentMethodRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a payment method (credit card)
        var paymentMethodOptions = new PaymentMethodCreateOptions
        {
            Type = "card", // Specifies that the payment method is a credit card
            Card = new PaymentMethodCardOptions
            {
                Number = createPaymentMethodRequest.Number,    // Card number
                ExpMonth = createPaymentMethodRequest.ExpMonth, // Expiration month
                ExpYear = createPaymentMethodRequest.ExpYear,   // Expiration year
                Cvc = createPaymentMethodRequest.Cvc            // Card security code (CVC)
            }
        };

        // Instantiate the PaymentMethodService to interact with Stripe's API
        var paymentMethodService = new PaymentMethodService();

        // Create the payment method by calling the Create method from the service
        PaymentMethod paymentMethod = paymentMethodService.Create(paymentMethodOptions);

        // Return the created payment method
        return paymentMethod;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment method", ex);
    }
}

// Request class for creating a payment method
public class CreatePaymentMethodRequest
{
    public string Number { get; set; }
    public string Cvc { get; set; }
    public int ExpMonth { get; set; }
    public int ExpYear { get; set; }
}


Attach Payment Method
Move the payment method to the customer.

code sample
// Attaches an existing payment method to a customer
public bool AttachPaymentMethod(AttachPaymentMethodRequest attachPaymentMethodRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for attaching the payment method to the customer
        var attachOptions = new PaymentMethodAttachOptions
        {
            Customer = attachPaymentMethodRequest.CustomerId // The ID of the customer to attach the payment method to
        };

        // Instantiate the PaymentMethodService to interact with Stripe's API
        var paymentMethodService = new PaymentMethodService();

        // Attach the payment method to the customer
        paymentMethodService.Attach(attachPaymentMethodRequest.PaymentMethodId, attachOptions);

        // Return true if the attachment is successful
        return true;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to attach payment method", ex);
    }
}

// Class representing the request for attaching a payment method
public class AttachPaymentMethodRequest
{
    public string CustomerId { get; set; }
    public string PaymentMethodId { get; set; }
}

Delete payment method
Remove the payment method from the customer using the Stripe customer ID and payment method ID.

Code sample
// Deletes (detaches) a payment method from a customer
public async Task<PaymentMethod?> DeleteCard(string customerId, string cardId)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();
        // Instantiate the PaymentMethodService to interact with Stripe's API
        var service = new PaymentMethodService();
        // Detach the payment method (card) from the customer using the card ID
        var paymentMethod = await service.DetachAsync(cardId);
        // Return the detached payment method
        return paymentMethod;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to delete payment method", ex);
    }
}

Payment Intent
The PaymentInten defines how the customer wants to pay for the service or business, and has details about the transaction, such as the supported payment methods, the amount to collect, and the desired currency.
Create Payment Intent with a Payment Method

Code Sample

// Creates a PaymentIntent for a specific payment
public PaymentIntent CreatePaymentIntent(CreatePaymentIntentRequest createPaymentIntentRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a payment intent
        var paymentIntentOptions = new PaymentIntentCreateOptions
        {
            Amount = createPaymentIntentRequest.Amount * 100, // Convert the amount to cents (Stripe expects the amount in the smallest currency unit)
            Currency = "usd", // Specify the currency for the payment
            Customer = createPaymentIntentRequest.CustomerId, // The Stripe customer ID associated with the payment
            PaymentMethod = createPaymentIntentRequest.PaymentMethodId, // The payment method to be used
            PaymentMethodTypes = new List<string> { "card" }, // Type of payment method (e.g., "card")
            OffSession = createPaymentIntentRequest.OffSession, // Indicates if the payment is happening off-session (e.g., without user interaction)
            Confirm = true // Automatically confirms the payment when created
        };

        // Instantiate the PaymentIntentService to interact with Stripe's API
        var paymentIntentService = new PaymentIntentService();

        // Create the payment intent using the defined options
        PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions);

        // Return the created payment intent
        return paymentIntent;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment intent", ex);
    }
}

// Request class for creating a PaymentIntent
public class CreatePaymentIntentRequest
{
    public string CustomerId { get; set; }
    public string PaymentMethodId { get; set; }
    public long Amount { get; set; } // Amount in cents
    public bool OffSession { get; set; } // Set true if charging without customer present (e.g., subscription)
}

Create payment intent without a payment method
It's like a direct one-time payment.

Code Sample

// Creates a PaymentIntent without specifying a payment method upfront (automatic payment methods enabled)
public Task<PaymentIntent> CreatePaymentIntentWithOutPaymentMethod(PaymentRequest request)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();
        // Define the options for creating a payment intent without a specified payment method
        var options = new PaymentIntentCreateOptions
        {
            Amount = request.Amount * 100, // Convert the amount to cents (Stripe expects the amount in the smallest currency unit)
            Currency = "usd", // Specify the currency for the payment
            AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
            {
                Enabled = true, // Automatically enable supported payment methods (e.g., card)
            },
        };

        // Instantiate the PaymentIntentService to interact with Stripe's API
        var service = new PaymentIntentService();

        // Asynchronously create the payment intent using the defined options
        var paymentIntent = service.CreateAsync(options);

        // Return the task of the payment intent creation
        return paymentIntent;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment intent", ex);
    }
}

Invoices
Invoices hold detailed information about the service provided, the due amount collected from the customer, and the customer's payment method.

Generate Invoice
// Generates and sends an invoice for a customer in Stripe
public Stripe.Invoice? GenerateInvoice(Invoice invoice)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Create invoice item options to specify the product/service being invoiced
        var invoiceItemOptions = new InvoiceItemCreateOptions
        {
            Customer = invoice.CustomerId.ToString(), // Customer ID for the invoice
            Amount = invoice.TotalAmount, // Total amount to be invoiced (in cents)
            Currency = "usd", // Currency for the invoice
            Description = "Product or Service Description", // Description of the product/service
        };

        // Create the invoice item (add a line item to the invoice)
        var invoiceItemService = new InvoiceItemService();
        var invoiceItem = invoiceItemService.Create(invoiceItemOptions); // This creates the invoice item

        // Define invoice options to create the actual invoice for the customer
        var invoiceOptions = new InvoiceCreateOptions
        {
            Customer = invoice.CustomerId, // Customer ID for the invoice
            AutoAdvance = true // Automatically finalize and send the invoice when it's created
        };

        // Create the invoice
        var invoiceService = new InvoiceService();
        var invoice1 = invoiceService.Create(invoiceOptions); // Create the invoice

        // Finalize the invoice (making it ready for payment)
        invoiceService.FinalizeInvoice(invoice1.Id);

        // Send the invoice to the customer
        var sendInvoiceOptions = new InvoiceSendOptions();
        invoiceService.SendInvoice(invoice1.Id, sendInvoiceOptions);

        // Return the generated invoice
        return invoice1;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to generate invoice", ex);
    }
}

public class Invoice
{
    public int InvoiceId { get; set; }
    public DateTime InvoiceDate { get; set; }
    public string CustomerId { get; set; }
    public long TotalAmount { get; set; }
    public List<InvoiceLineItem> LineItems { get; set; }
}

public class InvoiceLineItem
{
    public int InvoiceLineItemId { get; set; }
    public int InvoiceId { get; set; }
    public string Description { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal LineTotal => Quantity * UnitPrice;
    public Invoice Invoice { get; set; }
}


Pay Invoice
Customers can pay the invoice later, with the preferred payment method.
// Pays an invoice using a specified payment method
public Stripe.Invoice? PayInvoice(string paymentMethodID, string invoiceID)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Initialize the InvoiceService to interact with Stripe's invoice system
        var invoiceService = new InvoiceService();

        // Create options for paying the invoice, including the payment method ID
        var payInvoiceOptions = new InvoicePayOptions
        {
            PaymentMethod = paymentMethodID,  // Payment method ID (obtained from the customer or frontend)
        };

        // Attempt to pay the invoice using the provided payment method
        var paidInvoice = invoiceService.Pay(invoiceID, payInvoiceOptions);

        // Return the paid invoice object
        return paidInvoice;
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to pay invoice", ex);
    }
}

Refund Customer
Refund plays a key role in the payment processing system; we can refund the amount when the amount was deducted wrong.
// Processes a refund for a specific charge made by a customer
public Stripe.Refund? Refund(string customerID, long amount)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Initialize the RefundService to interact with Stripe's refund system
        var refunds = new RefundService();

        // Create options for the refund, including the amount and the charge ID
        var options = new RefundCreateOptions
        {
            Amount = amount,  // The amount to refund (in cents, e.g., $50.00 is 5000)
            Charge = customerID // The ID of the charge to refund (associated with the customer)
        };

        // Attempt to create the refund using the provided options
        var payment = refunds.Create(options);

        // Return the refund object containing the details of the refund
        return payment;
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to refund amount", ex);
    }
}

Conclusion
This approach enables the creation of a robust payment system integrated with Stripe, giving you the ability to scale and manage payments efficiently within your application.
Attached is the sample code.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Dependency Injection (DI) in .NET Core

clock December 3, 2024 08:08 by author Peter

By controlling the dependencies between classes, Dependency Injection (DI), a key idea in.NET Core, encourages loose coupling and testability. It is an application of the Inversion of Control (IoC) principle, which states that dependencies be supplied to objects rather than being constructed internally.

Key Concepts

  1. Dependency: A class or interface that another class relies on.
  2. Dependency Injection: The process of providing these dependencies to a class from an external source rather than the class creating them itself.
  3. Service Container: A component responsible for managing the lifecycle of objects and resolving dependencies.

Use Dependency Injection
1. Define the Service Interface and Implementation.
Create an interface and its implementation for the service you want to inject.

public interface IGreetingService
{
    string GetGreeting();
}

public class GreetingService : IGreetingService
{
    public string GetGreeting()
    {
        return "Hello, Dependency Injection!";
    }
}


2. Register the Service in the Dependency Injection Container.
In the Program.cs file (or Startup.cs in older versions), register your service in the DI container.
var builder = WebApplication.CreateBuilder(args);

// Add services to the DI container
builder.Services.AddTransient<IGreetingService, GreetingService>();

var app = builder.Build();


3. Inject the Service Where Needed.
In an ASP.NET Core application, inject the service into a controller via its constructor.

public class HomeController : Controller
{
    private readonly IGreetingService _greetingService;

    public HomeController(IGreetingService greetingService)
    {
        _greetingService = greetingService;
    }

    public IActionResult Index()
    {
        var message = _greetingService.GetGreeting();
        return Content(message);
    }
}


Service Lifetime in .NET Core


Benefits of Dependency Injection

  • Loose Coupling: Reduces dependencies between components, making the system modular.
  • Testability: Facilitates unit testing by allowing mock dependencies.
  • Centralized Configuration: All dependencies are managed in a single place.
  • Improved Maintainability: Adding, updating, or replacing services becomes easier.


European ASP.NET Core 9.0 Hosting - HostForLIFE :: Working with JSON in .NET Core: Newtonsoft.Json, NetJSON, and System.Text.Json

clock November 25, 2024 06:22 by author Peter

I'll go over three widely used approaches to handle JSON in.NET in this post. JavaScript Object Notation, or JSON, is a text-based, lightweight format that is frequently used for data interchange. There are various ways to work with JSON in.NET, each with advantages of its own and appropriate for particular situations. You can select from a variety of libraries, each designed to meet specific needs. Here are three well-liked choices: NetJSON, System.Text.Json, and Newtonsoft.Json, as well as code samples to get you started.

Working With Json in ASP.NET

  • Using Newtonsoft.Json (Json.NET)
  • Using System.Text.Json (Built-in .NET Core Library)
  • Using NetJSON (High-Performance JSON Library)

Let's create an employee class and prepare data to work with different JSON parsing libraries.
public class Employee
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public string? Department { get; set; }
}


Now, prepare the data with a list of employees.
static List<Employee> Getemployees()
{
    var employees = new List<Employee>
        {
            new Employee { Id = 1, Name = "John Doe", Department = "HR" },
            new Employee { Id = 2, Name = "Jane Smith", Department = "IT" },
            new Employee { Id = 3, Name = "Mike Johnson", Department = "Finance" }
        };
    return employees;
}

Using Newtonsoft.Json (Json.NET)
How do you install the Newtonsoft.Json package using the Manage NuGet Packages feature?

Install Newtonsoft.Json package
Search for the Newtonsoft.Json package in the NuGet package list as shown below.

Search package and install package
Let's look at an example where we serialize a list of employees into a JSON string and then deserialize the JSON string back into a list of employees.
static void JsonUsingNewtonsoft(List<Employee> employees)
{
    // Serialize to JSON
    string json = JsonConvert.SerializeObject(employees);
    Console.WriteLine("Serialized JSON (Newtonsoft.Json):");
    Console.WriteLine(json);

    // Deserialize back to Employee object
    List<Employee> employeeList = JsonConvert.DeserializeObject<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee:");
    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
    Console.ReadLine();
}

The snippet above shows the output of the code using the Newtonsoft.Json package.

Using System.Text.Json (Built-in .NET Core Library)

System.Text.Json, introduced in .NET Core 3.0, is the default and highly efficient library for processing JSON in .NET. It offers powerful features for serialization, deserialization, and parsing JSON documents.
static void JsonUsingSystemTextJson(List<Employee> employees)
{
    // Serialize to JSON using System.Text.Json
    string json = JsonSerializer.Serialize(employees);
    Console.WriteLine("Serialized JSON (System.Text.Json):");
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(json);

    // Deserialize back to Employee object using System.Text.Json
    List<Employee> employeeList = JsonSerializer.Deserialize<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee (System.Text.Json):");

    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
}

The snippet above shows the output of the code using the

Using NetJSON (High-Performance JSON Library)

NetJSON is a high-performance, lightweight JSON library for .NET, designed for speed and minimal memory usage. It is ideal for performance-critical scenarios, such as processing large datasets, high-throughput applications, or real-time systems. While it lacks the extensive customization options of libraries like Newtonsoft.Json, it stands out for its simplicity and exceptional performance.

Install NetJSON Package from NuGet Package Manager
Here’s an example demonstrating the use of the NetJSON package to serialize a list of employees into a JSON string and then deserialize the JSON string back into a list of employees.
static void JsonUsingNetJSON(List<Employee> employees)
{
    // Serialize to JSON using NetJSON
    string json = NetJSON.NetJSON.Serialize(employees);
    Console.WriteLine("Serialized JSON (NetJSON):");
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(json);

    // Deserialize back to Employee object using NetJSON
    List<Employee> employeeList = NetJSON.NetJSON.Deserialize<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee (NetJSON):");

    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
}

The snippet above shows the output of the code using the NetJSON package.

Let's put all methods together in a single class.
using JsonExample;
using Newtonsoft.Json;
using JsonSerializer = System.Text.Json.JsonSerializer;

var employeeList = Getemployees();

// Using Newtonsoft.Json
JsonUsingNewtonsoft(employeeList);

// Using System.Text.Json .Net Core built-in library
JsonUsingSystemTextJson(employeeList);

// Using NetJSON
JsonUsingNetJSON(employeeList);

Console.ReadLine();

static List<Employee> Getemployees()
{
    var employees = new List<Employee>
    {
        new Employee { Id = 1, Name = "John Doe", Department = "HR" },
        new Employee { Id = 2, Name = "Jane Smith", Department = "IT" },
        new Employee { Id = 3, Name = "Mike Johnson", Department = "Finance" }
    };
    return employees;
}

static void JsonUsingNewtonsoft(List<Employee> employees)
{
    // Serialize to JSON
    string json = JsonConvert.SerializeObject(employees);
    Console.WriteLine("Serialized JSON (Newtonsoft.Json):");
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(json);

    // Deserialize back to Employee object
    List<Employee> employeeList = JsonConvert.DeserializeObject<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee:");
    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
}

static void JsonUsingSystemTextJson(List<Employee> employees)
{
    // Serialize to JSON using System.Text.Json
    string json = JsonSerializer.Serialize(employees);
    Console.WriteLine("Serialized JSON (System.Text.Json):");
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(json);

    // Deserialize back to Employee object using System.Text.Json
    List<Employee> employeeList = JsonSerializer.Deserialize<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee (System.Text.Json):");
    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
}

static void JsonUsingNetJSON(List<Employee> employees)
{
    // Serialize to JSON using NetJSON
    string json = NetJSON.NetJSON.Serialize(employees);
    Console.WriteLine("Serialized JSON (NetJSON):");
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(json);

    // Deserialize back to Employee object using NetJSON
    List<Employee> employeeList = NetJSON.NetJSON.Deserialize<List<Employee>>(json);
    Console.WriteLine("\nDeserialized Employee (NetJSON):");
    foreach (Employee employee in employeeList)
    {
        Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}, Department: {employee.Department}");
    }
}


Recommendation. Choosing the Right JSON Library in the Real-time Project.

  • System.Text.Json: Best suited for modern .NET projects due to its performance and native integration.
  • Newtonsoft.Json: Ideal for projects requiring compatibility or advanced customization features.
  • NetJSON: Recommended for performance-critical scenarios such as real-time systems or large-scale data processing.

Note. Each approach serves different needs, and your choice depends on project requirements and performance considerations

Summary

This article covers three popular methods for working with JSON in .NET, highlighting their unique advantages and ideal use cases. JSON is a lightweight, text-based format commonly used for data exchange, and .NET provides versatile tools to handle it effectively. Note. I have provided a working solution compatible with Visual Studio 2022, which you can download from the top left corner of the article. Simply click the download icon to get the .zip file.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: .NET 9 : Task.WhenEach

clock November 19, 2024 07:15 by author Peter

In .NET 9, a new method, Task.WhenEach, has been introduced to streamline asynchronous programming. This method allows you to process tasks as they complete, rather than waiting for all tasks to finish. This is particularly useful in scenarios where tasks have varying completion times and you want to act on each one as soon as it's done.


Step 1. Create a function named PrintWithDelay
async Task<int> PrintWithDelay(int delay)
{
await Task.Delay(delay);
return delay;
}


This code defines an asynchronous method named PrintWithDelay that takes an integer delay as input and returns an integer.

async Task<int>

  • async: This keyword indicates that the method is asynchronous, meaning it can yield execution to other tasks while waiting for I/O operations or other asynchronous operations to complete.
  • Task<int>: This specifies the return type of the method. It will return a Task object that, when awaited, will yield the integer result.

await Task.Delay(delay)

  • Task.Delay(delay): This creates a new task that will complete after the specified delay milliseconds.
  • await: This keyword pauses the execution of the current method until the Task.Delay task completes. While waiting, the thread can be used by other tasks.

return delay
Once the delay has elapsed, the method resumes execution and returns the original delay value.

Step 2. Create a list of tasks that will each execute the PrintWithDelay method with different delay values.
List<Task<int>> printTasks = [
PrintWithDelay(4000),
PrintWithDelay(6000),
PrintWithDelay(2000)
];

  • This declares a list named printTasks to store tasks. Each task in this list will return an integer.
  • There are three calls to the PrintWithDelay method, each with a different delay value (4000, 6000, and 2000 milliseconds, respectively).
  • Each call returns a Task<int>, representing an asynchronous operation that will eventually return an integer.
  • These tasks are added to the printTasks list.

Step 3. Utilize Task.WhenEach in .NET 9.

Task.WhenEach yields an IAsyncEnumerable, allowing asynchronous processing of tasks as they complete.
await foreach (var task in Task.WhenEach(printTasks))
{
Console.WriteLine(await task);
}

Task.WhenEach(printTasks)

  • This part takes a collection of Task<int> objects (stored in printTasks).
  • It returns an IAsyncEnumerable<Task<int>>. This enumerable represents a sequence of tasks that will complete over time.

await foreach (var task in Task.WhenEach(printTasks))

  • This is an asynchronous foreach loop that iterates over the IAsyncEnumerable returned by Task.WhenEach.
  • The await keyword signifies that the loop will pause execution until the next task in the sequence completes.

In short, the code does the following

  • Schedules Tasks: The printTasks are scheduled to run asynchronously.
  • Processes Completed Tasks: As each task completes, it is yielded from the Task.WhenEach enumerable.
  • Logs Task Completion: The await foreach loop iterates over these completed tasks, and for each one, it logs a message to the console, which includes the task's status and result.

Output


By leveraging Task.WhenEach, you can write more efficient and responsive asynchronous code in .NET 9. Happy Coding!



European ASP.NET Core 9.0 Hosting - HostForLIFE :: A Beginner's Guide to.NET Core 8 Web API CRUD Operations

clock November 13, 2024 07:59 by author Peter

Because it enables the development of applications that expand and adapt to the requirements of various services and platforms, web API development is a crucial part of the current development scenario. CRUD actions, which enable the fundamental interface with the application's data, are one of the cornerstone procedures in the development of APIs. Starting with CRUD operations makes perfect sense if you are "green" with.NET Core because it teaches you the basics of creating a Web API and handling data.

The creation of a.NET Core 8 Web API project and the specification of the endpoints for each CRUD operation will be covered in this tutorial. Effective data handling techniques are outlined by the Entity Framework Core, an ORM system made to communicate with.NET databases. By the end of this article, you will have mastered the fundamentals of RESTful design in.NET Core and developed a functional Web API that can manipulate data.

This tutorial is intended for both a novice front-end developer looking to hone their skills and an aspiring backend developer with experience in.NET Core 8 API development. Therefore, you will undoubtedly learn how to begin creating APIs in.NET Core 8 if you fit into either of the two categories. Let's go over this initial phase.

Open Visual Studio 2022 and Choose "Create a new project".

On the Create a new project page, search for "Web API" on the search bar, select the project template and press the "next" button.

On the configuration of the project, enter the Project Name and choose the check box to keep the solution file and project in the same directory.

To configure the Framework version, tick the boxes according to the screenshot, and click "create" on the project's additional details page. To get things started, it will generate the project using the default files.

Initially, the project folder structure looked like this.

First, we need to install the packages required for the ORM to interact with the Database. To install the packages, Right click on the solution and choose "Manage NuGet Packages... "

On the NuGet page, search for the below two packages and install the versions above 8.
Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.SqlServer

Then, Right-click on the solution. Create a new Class file named Employee.cs and paste the code.
namespace EmployeePortal.Models.Entities
{
    public class Employee
    {
        public Guid Id { get; set; }
        public required string Name { get; set; }
        public required string Email { get; set; }
        public required string PhoneNumber { get; set; }
        public decimal Salary { get; set; }
    }
}


Then, we need to create a DB Context file for the application that holds the configuration for the ORM and its Entities. Create a file named ApplicationDbContext.cs and paste the below code.
using EmployeePortal.Models.Entities;
using Microsoft.EntityFrameworkCore;
namespace EmployeePortal
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
        public DbSet<Employee> Employees { get; set; }
    }
}

Then, we need to add a DB connection string to the appsettings.json file.
"ConnectionStrings": {
  "DefaultConnection": "Server=your_server_name;Database=your_database_name;User Id=your_username;Password=your_password;TrustServerCertificate=True;"
}


Then, we need to add the SQL Server services to our Program.cs file and add the below code to the program file under the services, which tells the application to use the SQL server from the connection string.
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(
    builder.Configuration.GetConnectionString("DefaultConnection")));


Now, we add a migration to create a snapshot of our entities from the application because we are using the Code First Approach in EF. So, we need to specify the entities and their relationships, and then we run the migration which will create a Database and tables based on the relationship of the entities.

Open the package manager console and run the following commands.

  • add-migration "initial one": generates a migration file based on the current state of your data models compared to the database schema.
  • update-database: applies the migration to your database, creating or altering tables, columns, or relationships as defined in the migration file.

Now, If you open the SQL server, you can see the database and the tables.


We need to create a Web API controller to fetch the data from the database through the endpoints. Right-click on the controller's folder and choose to add a new Web API Controller.


You can request the endpoints using the necessary information.

Endpoints and their use cases with return types

  • Get All Employees: it is GET api/employees. Method: GetEmployees(). Purpose: Fetches all the employees from the store. Response: Returns an Ok (HTTP 200) status with the body, which contains the list of employees.
  • Get Employee by ID: it is GET api/employees/{id}. Method: GetEmployeeById(Guid id). Purpose: Use unique IDs to retrieve an employee. Response: Returns an Ok (HTTP 200) status and data about an employee when such is available, however, there is a risk that if no such employees can be traced then one will be returned as NotFound (HTTP 404).
  • Add a New Employee: it is POST api/employees. Method: AddEmployee(EmployeeDto employees). Purpose: Whenever an employee Dto record is transmitted to the application, the application updates the defined employees in the store. Response: Returned 201 Created status whenever an employer is successfully added.
  • Update Employee: it is PUT api/employees/{id}. Method: UpdateEmployee(Guid id, UpdateEmployeeDto employeeDto). Purpose: One has to search the employee by the unique ID and change his information. Response: If the updates work effectively, they return an Ok (HTTP 200) status, while the NotFound (HTTP 404) will be resolved in situations where no suitable culprit persons are available.
  • Delete Employee: it is DELETE api/employees/{id}. Method: DeleteEmployee(Guid id). Purpose: When databases are directed to delete certain profiles, the corresponding unique ID numbers are used. Response: If it works, returns NoContent (HTTP 204) in situations where the deletion was successful, whereas NotFound (HTTP 404) if no matching employee is found.

Conclusion
In this article, we explored a basic implementation of CRUD operations for managing employee data in a .NET Core Web API. By following these steps, we created endpoints to add, retrieve, update, and delete employees, using DTOs to encapsulate and simplify data transfer. This approach helps establish a solid foundation for building RESTful APIs and managing data flow in a secure and organized manner.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Explaning IExceptionFilter in .NET Core

clock November 4, 2024 12:50 by author Peter

So, Let's get started.


Exception Filter in ASP.NET Core
Exception Filter allows us to handle unhandled exceptions that occur while processing an HTTP request within our application. Exception Filters in ASP.NET Core Applications are used for tasks such as Logging Exceptions, Returning Custom Error Responses, and Performing any other necessary action when an exception occurs.

Exception Filter also provides a way to centralize the exception-handling logic and keep it separate from our controller or from the business and data access logic, making our code more organized and maintainable.

IExceptionFilter

  • IExceptionFilter is an interface in ASP.NET Core that provides a mechanism for handling exceptions that occur during the processing of a request. By implementing IExceptionFilter, you can write custom logic to handle exceptions globally or per-controller.
  • Advantages of IExceptionFilter
  • Centralized Exception Handling: You can manage all your exceptions in a single place, making it easier to maintain and modify your exception-handling strategy.
  • Separation of Concerns: By handling exceptions separately, you keep the error-handling logic away from your business logic, improving code readability and maintainability.
  • Consistent Error Responses: It allows you to standardize the way errors are reported back to the client, which can improve the API's usability. You can return consistent model formats, error codes, and messages.
  • Access to HttpContext: Since filters have access to the `HttpContext`, you can easily log errors, modify responses, or perform any other operation based on the context of the request.
  • Interception of All Exceptions: It can catch exceptions that aren't handled anywhere else, ensuring that your application can respond gracefully to unexpected errors.
  • Custom Logic: You can implement any custom logic needed for exception handling, such as logging specific exceptions differently.

Disadvantages of IExceptionFilter

  • Global Scope: When implemented globally, all exceptions will be handled by the same filter. This might not be desirable if different controllers or actions require different handling strategies.
  • Complex Error Handling Logic: If you have complex error-handling needs, managing too many unique cases in a single filter could lead to convoluted code.
  • Performance Concerns: Introducing additional logic in exception handling can potentially add overhead, especially if the handling involves extensive processing or logging.
  • Limited to Web Context: Unlike middleware, exception filters are limited in scope to the MVC pipeline. They cannot handle exceptions that occur outside of the controller actions, such as in middleware.
  • Difficulty in Testing: Since exception filters are tied to the ASP.NET injection system, they can introduce complexity when writing unit tests, particularly if they depend on the HttpContext.

Implementing IExceptionFilter
Implementing IExceptionFilter can greatly benefit your ASP.NET Core applications by providing structured and centralized exception handling. However, balance must be struck in how it's used to avoid complexity, ensure performance, and maintain flexibility. Choosing the right approach to exception handling may also involve combining it with other options like middleware, custom error pages, or even using logged service responses as needed.
public class HandleExceptionFilter : IExceptionFilter
    {
      private readonly ILogger<HandleExceptionFilter> _logger;
      public HandleExceptionFilter(ILogger<HandleExceptionFilter> logger)
        {
            _logger = logger;
        }

      public override void OnException(ExceptionContext filterContext)
        {
            bool isAjaxCall = filterContext.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest";
            filterContext.HttpContext.Session.Clear();

            if (isAjaxCall)
            {
                filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                var data = new
                {
                    filterContext.Exception.Message,
                    filterContext.Exception.StackTrace
                };
                filterContext.Result = new JsonResult(data);
                filterContext.ExceptionHandled = true;
            }

            if (!isAjaxCall)
            {
                filterContext.Result = new RedirectResult("/Error/Error");
            }

            _logger.LogError(GetExceptionDetails(filterContext.Exception));

            filterContext.ExceptionHandled = true;
            base.OnException(filterContext);

        }

       private string GetExceptionDetails(Exception exception)
        {
            var properties = exception.GetType()
                .GetProperties();
            var fields = properties
                .Select(property => new
                {
                    Name = property.Name,
                    Value = property.GetValue(exception, null)
                })
                .Select(x => $"{x.Name} = {(x.Value != null ? x.Value.ToString() : String.Empty)}");
            return String.Join("\n", fields);
        }
    }


// Register the filter in Startup.cs

public void ConfigureServices(IServiceCollection services)
  {
    services.AddControllers(options =>
     {
         options.Filters.Add<HandleExceptionFilter>();
     });
  }

// Above .net 6

builder.Services.AddScoped<HandleExceptionFilter>();

Then, add the name as EmployeesController.cs and paste the code below.
using EmployeeAdminPortal.Data;
using EmployeeAdminPortal.DTO;
using EmployeeAdminPortal.Models.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace EmployeeAdminPortal.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeesController : ControllerBase
    {
        private readonly ApplicationDbContext _dbContext;

        public EmployeesController(ApplicationDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        [HttpGet]
        public IActionResult GetEmployees()
        {
            return Ok(_dbContext.Employees);
        }

        [HttpGet]
        [Route("{id:guid}")]
        public IActionResult GetEmployeeById(Guid id)
        {
            var employee = _dbContext.Employees.Find(id);
            if (employee == null)
            {
                return NotFound();
            }
            return Ok(employee);
        }

        [HttpPost]
        public IActionResult AddEmployee(EmployeeDto employeeDto)
        {
            var employee = new Employee
            {
                Name = employeeDto.Name,
                Email = employeeDto.Email,
                PhoneNumber = employeeDto.PhoneNumber,
                Salary = employeeDto.Salary
            };
            _dbContext.Employees.Add(employee);
            _dbContext.SaveChanges();
            return StatusCode(StatusCodes.Status201Created);
        }

        [HttpPut]
        [Route("{id:guid}")]
        public IActionResult UpdateEmployee(Guid id, UpdateEmployeeDto employeeDto)
        {
            var employee = _dbContext.Employees.Find(id);
            if (employee == null)
            {
                return NotFound();
            }
            employee.Name = employeeDto.Name;
            employee.Email = employeeDto.Email;
            employee.PhoneNumber = employeeDto.PhoneNumber;
            employee.Salary = employeeDto.Salary;
            _dbContext.SaveChanges();
            return Ok(employee);
        }

        [HttpDelete]
        [Route("{id:guid}")]
        public IActionResult DeleteEmployee(Guid id)
        {
            var employee = _dbContext.Employees.Find(id);
            if (employee == null)
            {
                return NotFound();
            }
            _dbContext.Employees.Remove(employee);
            _dbContext.SaveChanges();
            return NoContent();
        }
    }
}


Also, you need to create a new folder for DTO(Data Transfer Objects), which is used to transfer data between layers or services within an application.
Create two DTO files named EmployeeDto.cs and UpdateEmployeeDto.cs.
// Employee DTO
namespace EmployeePortal.DTO
{
    public class EmployeeDto
    {
        public required string Name { get; set; }
        public required string Email { get; set; }
        public required string PhoneNumber { get; set; }
        public decimal Salary { get; set; }
    }
}

UpdateEmployeeDto.cs
// Update Employee DTO
namespace EmployeePortal.DTO
{
    public class UpdateEmployeeDto
    {
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? PhoneNumber { get; set; }
        public decimal Salary { get; set; }
    }
}

Then, build and run your application. You can able to see the endpoints of our application on the chrome with the help of Swagger.



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