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 :: Versioning the API and Turning on Authorization in the Swagger UI for.NET Core

clock September 26, 2024 07:18 by author Peter

API Versioning
The process of creating different versions of an API to coexist at the same time is called API versioning. By employing this method, we may allow new features and enhancements for clients that are more recent while preserving backward compatibility with older clients. Your application may require breaking updates to your API as it develops. Managing these changes in a way that doesn't affect current users who are dependent on previous API versions is helpful.

There are various ways to implement API versioning in .NET Core web API. The most common ways to implement API versioning are:

  • URL versioning: This is the most common approach to implementing API versioning. In this technique, the version is part of the endpoint itself.
  • For Example: /api/v1/purchaseOrders
  • Query String Versioning: In this technique, the version is passed as a query parameter. This approach maintains the same URL path, with the version indicated by an additional query parameter.
  • For Example: /api/purchaseOrders?api-version=1.0
  • Header Versioning: In this technique, the version is passed in a custom request header. The version is included in the request headers rather than the URL.
  • For Example

GET /api/purchaseOrders

  • Headers: x-api-version: 1.0Media Type Versioning (Accept Header Versioning): In this technique, the version is passed via content negotiation. The version is included in the Accept header with a custom media type. The client requests a specific version of the API by setting the Accept header to a custom MIME type.
  • For Example
    GET /api/purchaseOrder
  • Headers: Accept: application/vnd.companyname.v1+json
How to implement API versioning?
How to implement API versioning using URL versioning and enable the token authorization option in Swagger step by step. For this, I am using .NET Core 8.

Create a web API: Create a .NET Core web API and name it "APIVersioingPOC".
Add required packages: Add the below-required packages for API versioning using the Nuget package manager.

Install-Package Asp.Versioning.Mvc
Install-Package Asp.Versioning.Mvc.ApiExplorer


Create Entity Class: Create a folder with the name "Entity" and add an entity class named "PurchaseDetails"
namespace APIVersioingPOC.Entity
{
    public class PurchaseDetails
    {
        public string ProductName { get; set; }
        public int Rate { get; set; }
        public int Qty { get; set; }
        public int Amount { get; set; }
    }
}


Create Service: Create a folder with the name "Service" and add an interface with the name "IPurchaseOrderService" and a service class with the name "PurchaseOrderService" as below.

using APIVersioingPOC.Entity;

namespace APIVersioingPOC.Service
{
    public interface IPurchaseOrderService
    {
        List<PurchaseDetails> GetPurchaseOrders();
    }
}


using APIVersioingPOC.Entity;

namespace APIVersioingPOC.Service
{
    public class PurchaseOrderService: IPurchaseOrderService
    {
        public List<PurchaseDetails> GetPurchaseOrders()
        {
            return new List<PurchaseDetails>
            {
               new PurchaseDetails { ProductName="Laptop", Rate=80000, Qty=2, Amount=160000},
               new PurchaseDetails { ProductName="Dekstop", Rate=40000, Qty=1, Amount=40000},
               new PurchaseDetails { ProductName="Hard Disk", Rate=4000, Qty=10, Amount=40000},
               new PurchaseDetails { ProductName="Pen Drive", Rate=600, Qty=10, Amount=6000},
            };
        }
    }
}

To resolve the dependency, register the service in Program.cs as below.
// Add custom services
builder.Services.AddScoped<IPurchaseOrderService, PurchaseOrderService>();

Configure the versioning: In Program.cs file, add the below code.
var builder = WebApplication.CreateBuilder(args);

// Add API Explorer that provides information about the versions available
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0); // Default API version (v1.0)
    options.AssumeDefaultVersionWhenUnspecified = true; // Assume the default version if not specified
    options.ReportApiVersions = true; // Report API versions in response headers
    options.ApiVersionReader = new UrlSegmentApiVersionReader(); // Use URL segment versioning (e.g., /api/v1/resource)

}).AddApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

builder.Services.AddSwaggerGen();

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(options =>
{
    var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();

    foreach (var description in provider.ApiVersionDescriptions)
    {
        options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
    }
});

ConfigureSwaggerOptions: Create a folder with the name "OpenApi" and add the ConfigureSwaggerOptions class to configure swagger options.
using Asp.Versioning.ApiExplorer;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace APIVersioingPOC.OpenApi
{
    public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
    {
        private readonly IApiVersionDescriptionProvider _provider;

        public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider)
        {
            _provider = provider;
        }

        public void Configure(SwaggerGenOptions options)
        {
            foreach (var description in _provider.ApiVersionDescriptions)
            {
                options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
            }

            // Add token authentication option to pass bearer token
            options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                In = ParameterLocation.Header,
                Description = "Please enter token",
                Name = "Authorization",
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            });

            // Add security scheme
            options.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                    },
                    new string[] { }
                }
            });
        }

        private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription apiVersionDescription)
        {
            var info = new OpenApiInfo
            {
                Title = "API Versioning",
                Version = apiVersionDescription.ApiVersion.ToString(),
                Description = "Swagger document for API Versioning.",
            };

            // Add deprecated API description
            if (apiVersionDescription.IsDeprecated)
            {
                info.Description += " This API version has been deprecated.";
            }

            return info;
        }
    }
}


Add the code below to the Program.cs

// Add custom services
builder.Services.AddSingleton<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();


Create Controller: Create a controller with the name "PurchaseOrderController". For demo purposes, I have created two versions of the same API endpoint.
using APIVersioingPOC.Service;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace APIVersioingPOC.Controllers
{
    [ApiController]
    [Route("api/v{version:apiVersion}/[controller]")]
    [ApiVersion("1.0")]
    [ApiVersion("2.0")]
    [Authorize]
    public class PurchaseOrderController : ControllerBase
    {
        private readonly IPurchaseOrderService _purchaseOrderService;

        public PurchaseOrderController(IPurchaseOrderService purchaseOrderService)
        {
            _purchaseOrderService = purchaseOrderService;
        }

        [HttpGet("GetPurchaseOrders")]
        [MapToApiVersion("1.0")]
        public IActionResult GetPurchaseOrders()
        {
            var users = _purchaseOrderService.GetPurchaseOrders();
            return Ok(users);
        }

        [HttpGet("GetPurchaseOrders")]
        [MapToApiVersion("2.0")]
        public IActionResult GetPurchaseOrdersV2()
        {
            var purchaseDetails = _purchaseOrderService.GetPurchaseOrders();
            return Ok(purchaseDetails);
        }
    }
}


Let's run the project

For default version V1 you will get the swagger document as below.

When you use the V2 option in the "Select a Definition" dropdown box, the swagger document will appear as seen below.


You can pass the authentication token as below and click on the Authorize button.

In this way, we learned how to implement API versioning and enable authorization in Swagger UI.

Happy Learning!



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Cache Profiles for Response Caching in.NET Core 8

clock September 23, 2024 08:10 by author Peter

Response caching is the technique by which a browser or other client stores a server's response in memory. As a result, requests for the same resources will be processed more quickly in the future. Additionally, this will spare the server from processing and producing the same response over and over again.

ASP.NET Core uses the ResponseCache property to set the response caching headers. Moreover, we can use the Response Caching Middleware to control the caching behavior from the server side. Once we've configured clients and other proxies to determine how to cache the server response, they can read the response caching headers. The HTTP 1.1 Response Cache Specification stipulates that browsers, clients, and proxies need to have caching headers.

Profiles in Cache
Instead of repeating the response cache settings on various controller action methods, we can create cache profiles and use them across the application. After it is configured, the application can utilize the cache profile's values as defaults for the ResponseCache attribute. Obviously, we can override the defaults by declaring the characteristics on the attribute.

A cache profile can be defined in the Program class.

builder.Services.AddControllers(options =>
{
    options.CacheProfiles.Add("Default", new CacheProfile
    {
        Duration = 60,
        Location = ResponseCacheLocation.Any
    });
});


Here, we define a new cache profile named Default, whose location is set to public and whose duration is set to two minutes.

This cache profile can now be applied to any controller or endpoint.
[HttpGet("default")]
[ResponseCache(CacheProfileName = "Default")]
public IActionResult Default()
{
    return Ok($"Default response was generated, {DateTime.Now}");
}


This will cause the response's defined cache-control settings to be applied.
cache-control: public,max-age=60

We can define multiple cache profiles in the app settings file and make the response cache settings configurable, avoiding hard-coding the cache settings in the Program class.

"CacheProfiles": {
  "Cache5Mins": {
    "Duration": 600,
    "Location": "Any"
  },
  "CacheVaryByHeader": {
    "Duration": 60,
    "Location": "Any",
    "VaryByHeader": "User-Agent"
  }
}


The ConfigurationManager class can then be used to read the cache profiles in the Program class.

builder.Services.AddControllers(options =>
{
    var cacheProfiles = builder.Configuration
            .GetSection("CacheProfiles")
            .GetChildren();

    foreach (var cacheProfile in cacheProfiles)
    {
        options.CacheProfiles
        .Add(cacheProfile.Key, cacheProfile.Get<CacheProfile>());
    }
});


This approach to defining cache profiles is far superior, particularly if our application requires the definition of multiple cache profiles. Let’s run the application and validate the response cache.

 

The above screenshot is for the default response cache profile; the default value is 60 (1 min) until that response is the same; after that duration, the response is changed.

The cache vary by header response cache profile shown in the above example has a default value of 60 (1 minute), and the vary by header property value is User-Agent up until the point at which the answer changes.

Remember that while Response Caching can significantly improve your application's speed, it may not be suitable in all circumstances. Caching can cause unwanted or inappropriate behavior when user-specific data is served that shouldn't be cached, or when information is changing quickly.

Together, we developed and mastered the new method.

Have fun with coding!



European ASP.NET Core 9.0 Hosting - HostForLIFE :: In-Memory Databases- Unit Testing With C#, EFCore and XUnit

clock September 19, 2024 08:31 by author Peter

We occasionally find it difficult to unit test our repositories because of the process of establishing a record in the database. However, with the EF-Core In-Memory Database, testing your repository is now simple. To show you the same, we have made a little dummy project.

In-Memory Database

A lightweight, quick database that runs exclusively in memory is called an in-memory database. Because it lets you imitate database operations without the overhead of an actual database, it's especially helpful for unit testing. You can test your data access code using the In-Memory Database service offered by EF Core.

Use these instructions to build up in-memory databases and unit testing using xUnit, EF Core, and C#.

Set Up Your Project

  • Ensure you have the necessary NuGet packages installed.
    • `Microsoft.EntityFrameworkCore.InMemory`
    • `xUnit`
    • `xUnit.runner.visualstudio`
    • `Microsoft.NET.Test.Sdk`
  • Configure In-Memory Database: In your test project, configure the in-memory database in your DbContext options. This allows you to use an in-memory database for testing purposes.
  • Create Your DbContext: Define your DbContext class as you would for any EF Core application.
  • Write Unit Tests: Use xUnit to write your unit tests. You can create a test class and use the [Fact] attribute to define individual test methods.
  • Initialize the In-Memory Database in Tests: In your test methods, initialize the in-memory database and seed it with test data if necessary.
  • Run Your Tests: Use the xUnit test runner to execute your tests and verify the behavior of your code.

Here’s a high-level overview of the process.

Install Packages
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
dotnet add package Microsoft.NET.Test.Sdk


Configure DbContext
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
    public DbSet<User> Users { get; set; }
}


Write Unit Tests
public class UserRepositoryTests
{
    [Fact]
    public void Create_ShouldReturnSuccess_WhenDataGiven()
    {
        int expectedUserId = 1;
        string expectedUserName = “Test”;

        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: new Guid.NewGuid().ToString())
            .Options;

        using (var context = new ApplicationDbContext(options))
        {
            // Arrange: Seed data into the context
            context.Users.Add(new User { Id = expectedUserId, Name = expectedUserName });
            context.SaveChanges();

            // Act: Perform the action to be tested
            var actualUser  = context.Users.FirstOrDefault(e => e.Id == expectedUserId);

            // Assert: Verify the result
            Assert.NotNull(result);
            Assert.Equal(expectedUserName, actualUser.Name);
        }
    }
}


This setup allows you to test your EF Core code using an in-memory database, ensuring your tests are fast and isolated from your production database.

Output

Benefits and Limitations
Benefits

  • Speed: In-memory databases are faster than real databases.
  • Isolation: Tests are isolated from each other, ensuring no side effects.
  • Simplicity: Easy to set up and use.

Limitations
Not a Real Database: It doesn’t enforce all constraints (e.g., foreign keys) like a real relational database.
Limited Features: Some database-specific features may not be supported.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: Protecting ASP.NET Core Web API from XSS Attacks

clock September 10, 2024 07:50 by author Peter

One of the most frequent vulnerabilities discovered in web applications is cross-site scripting (XSS). It happens when a victim's browser executes malicious scripts that have been injected into online sites or APIs, possibly compromising sensitive data. This post will describe how to use security best practices, sanitize inputs, and encode outputs to prevent XSS attacks in an ASP.NET Core Web API.

XSS: What is it?
When harmful scripts are injected into content that is given to users without the necessary validation or encoding, it is known as an XSS attack. When it comes to Web APIs, the fact that the API can process user input and then provide it to clients (browsers or other consumers) raises the possibility of criminal activity and script execution.

Example of an XSS Attack
Imagine a Web API that accepts user input, such as a name, and returns it back to the client.

{
    "name": "<script>alert('XSS Attack!');</script>"
}


If the API does not sanitize this input, the malicious JavaScript (<script>alert('XSS Attack!');</script>) will be executed in the client’s browser.

Types of XSS Attacks

  • Stored XSS: Malicious scripts are stored in the database or file system and executed when the victim visits the page that retrieves and displays the data.
  • Reflected XSS: Malicious scripts are embedded in the URL and executed when the victim clicks the link.
  • DOM-Based XSS: The vulnerability is within the client-side JavaScript itself.

Preventing XSS in ASP.NET Core Web API
Here’s a step-by-step guide to protect your API from XSS attacks.

1. Input Validation and Data Annotations

The first line of defense against XSS is to validate user inputs using model validation and constraints.
In ASP.NET Core, you can use Data Annotations to specify validation rules for models. For example, a user registration API might look like this:
public class UserInput
{
    [Required]
    [MaxLength(50)]
    [RegularExpression(@"^[a-zA-Z0-9]*$", ErrorMessage = "Invalid characters in name")]
    public string Name { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }
}


By applying these annotations, the API ensures that only valid data is accepted and limits the possibility of malicious scripts getting through.

Example API Controller
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    [HttpPost]
    [Route("create")]
    public IActionResult CreateUser([FromBody] UserInput userInput)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        return Ok(new { Message = "User created successfully!" });
    }
}


In the above example, the input Name is restricted to alphanumeric characters, which limits the possibility of script injection.

2. Sanitizing User Input

Even with validation in place, you should sanitize inputs that could potentially be harmful. ASP.NET Core provides various ways to sanitize and encode user inputs.
Using the HtmlEncoder Class: You can use the HtmlEncoder class to encode dangerous characters before processing the input.
    using System.Text.Encodings.Web;
    public string SanitizeInput(string input)
    {
        return HtmlEncoder.Default.Encode(input);
    }


This encodes any special characters like <, >, or & that could be used for XSS attacks.

Example Usage in API
[HttpPost]
[Route("sanitize")]
public IActionResult SanitizeUserInput([FromBody] string userInput)
{
    var sanitizedInput = HtmlEncoder.Default.Encode(userInput);
    return Ok(new { SanitizedInput = sanitizedInput });
}


3. Using a Third-Party Library for Sanitization
For more complex scenarios, you can use a third-party library like Ganss.XSS, which allows for advanced HTML sanitization.
Install the NuGet Package
Install-Package Ganss.XSS


Example Code
using Ganss.XSS;
public string SanitizeHtml(string input)
{
    var sanitizer = new HtmlSanitizer();
    return sanitizer.Sanitize(input);
}


4. Content Security Policy (CSP)
A Content Security Policy (CSP) is a security header that helps prevent XSS by controlling which resources (scripts, images, styles) can be loaded by the browser.
You can add CSP headers in ASP.NET Core like this.

public void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; script-src 'self'");
        await next();
    });

}


This policy restricts the loading of scripts to only those from the same domain, making it much harder for attackers to load malicious external scripts.

5. HTTP-Only and Secure Cookies

If your Web API works with cookies (e.g., for authentication), always mark them as HttpOnly and Secure to prevent client-side scripts from accessing them.
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;


6. Sanitize Data from Third-Party APIs
If your API consumes data from third-party services, it's important to sanitize that data before returning it to your clients. Even trusted APIs could be compromised, so always validate and sanitize the data.

Example
public IActionResult FetchDataFromExternalApi()
{
    var externalApiData = GetExternalApiData();
    var sanitizedData = HtmlEncoder.Default.Encode(externalApiData);
    return Ok(new { Data = sanitizedData });
}


7. Ensure Proper Response Headers
Return the proper Content-Type headers in your API responses. If you’re returning JSON, ensure the Content-Type is set to application/json. This prevents browsers from interpreting JSON responses as HTML or scripts.
context.Response.ContentType = "application/json";

8. Real-World Example of XSS Prevention
Let’s implement an API endpoint that accepts a user's comment and sanitizes the input before storing it in the database.
    Comment Model
    public class Comment
    {
        public int Id { get; set; }
        [Required]
        [MaxLength(500)]
        public string Content { get; set; }
        public DateTime CreatedAt { get; set; }
    }


CommentController
[ApiController]
[Route("api/[controller]")]
public class CommentController : ControllerBase
{
    private readonly HtmlSanitizer _sanitizer;
    public CommentController()
    {
        _sanitizer = new HtmlSanitizer();
    }
    [HttpPost]
    [Route("create")]
    public IActionResult CreateComment([FromBody] Comment comment)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        comment.Content = _sanitizer.Sanitize(comment.Content);
        comment.CreatedAt = DateTime.UtcNow;
        _dbContext.Comments.Add(comment);
        _dbContext.SaveChanges();
        return Ok(new { Message = "Comment created successfully!" });
    }
}


Complete End to end Example In Asp.net Core Web API
Step 1. Create a New ASP.NET Core Web API Project

  • Open Visual Studio Code.
  • Create a new folder for your project.
  • Open the folder in VS Code.
  • Open a terminal in VS Code and run the following command to create an ASP.NET Core Web API project.

dotnet new webapi -n XSSAttacksinASP.NETCoreWebAPI

Step 2. Add Ganss.XSS NuGet Package
Navigate to the project folder and install the Ganss.XSS NuGet package, which will help with input sanitization.
dotnet add package Ganss.XSS

Step 3. Modify the Project Structure
Our project structure should look something like this.

XSSAttacksinASP.NETCoreWebAPI/

├── Controllers/
│   └── CommentController.cs

├── Models/
│   └── Comment.cs

├── Program.cs
├── Startup.cs
├── XssPreventionApi.csproj
└── appsettings.json


Step 4. Define the Model (Comment.cs)
In the Models folder, create a Comment.cs file to define the model for user input.

using System.ComponentModel.DataAnnotations;
namespace XSSAttacksinASP.NETCoreWebAPI.Models
{
    public class Comment
    {
        public int Id { get; set; }
        [Required]
        [MaxLength(500, ErrorMessage = "Comment cannot be longer than 500 characters.")]
        public string Content { get; set; }
        public DateTime CreatedAt { get; set; }
    }
}


Step 5. Create the Comment Controller (CommentController.cs)
In the Controllers folder, create a CommentController.cs file to handle incoming HTTP requests for the comments. We'll use the Ganss.XSS library to sanitize the comment content before saving it to a data store (in this example, we'll just simulate saving it).
using Ganss.Xss;
using Microsoft.AspNetCore.Mvc;
using XSSAttacksinASP.NETCoreWebAPI.Models;
namespace XSSAttacksinASP.NETCoreWebAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class CommentController : ControllerBase
    {
        private readonly HtmlSanitizer _sanitizer;
        public CommentController()
        {
            _sanitizer = new HtmlSanitizer();
        }
        [HttpPost]
        [Route("create")]
        public IActionResult CreateComment([FromBody] Comment comment)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            comment.Content = _sanitizer.Sanitize(comment.Content);
            comment.CreatedAt = DateTime.UtcNow;
            return Ok(new { Message = "Comment created successfully!", SanitizedContent = comment.Content });
        }
    }
}


Step 6. Configure Program. cs and Startup. cs (ASP.NET Core 6+)
Since ASP.NET Core 6+ has consolidated the Startup and Program files, you may just need to ensure the basic structure is in place to handle API routing and services.
namespace XSSAttacksinASP.NETCoreWebAPI
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            // Add services to the container.
            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
            var app = builder.Build();
            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }
            app.UseHttpsRedirection();
            app.UseAuthorization();
            app.MapControllers();
            app.Run();
        }
    }
}


Step 7. Add Launch Settings (Optional)
If you want to configure launch settings (for example, to run the project on a specific port), modify the Properties/launchSettings.json file.
{
  "profiles": {
    "XssPreventionApi": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Step 8. Run the Project
Open the terminal and navigate to the project folder (XssPreventionApi).

Run the project using the following command.
dotnet run

Step 9. Test the API Using Postman or curl
You can use Postman or Curl to send POST requests to the API.

    Example Request with curl
    curl -X POST https://localhost:5001/api/comment/create \
    -H "Content-Type: application/json" \
    -d "{\"Content\": \"<script>alert('XSS Attack!');</script>\"}"


Example Response
{
  "message": "Comment created successfully!",
  "sanitizedContent": "\"}"
}


In the response, you'll see that the <script> tags have been sanitized, preventing the malicious code from executing.

Step 10. Testing XSS Prevention
You can test by sending different kinds of potentially harmful input, such as.
    <script>alert('XSS')</script>
    <img src="x" onerror="alert('XSS')"/>
    onmouseover="alert('XSS')"

All these will be sanitized to their encoded form to ensure no harmful JavaScript gets executed.



European ASP.NET Core 9.0 Hosting - HostForLIFE :: ASP.NET Core 8 Logging Made Simpler with Serilog and AppInsight

clock September 3, 2024 07:06 by author Peter

Logs are a crucial component of application development since they let you keep an eye on and diagnose issues and defects in your program. Developers love Serilog because it offers organized logging, which makes it easy to find and fix problems. A diagnostic logging library called Serilog was created especially for.NET applications. This method of logging application events, failures, and other pertinent data is straightforward, adaptable, and effective. Support for structured logging, which enables developers to log rich, structured data rather than just plain text messages, is one of Serilog's main advantages.

This post will teach us how to use Serilog with sink AppInsights for application logging in an ASP.NET Core Web API project. Let's now proceed to using Verilog to develop application logging using stages.

Step 1: If your project requires the use of AppInsights for Serilog logging, create a new ASP.NET Core Web API application (.NET8) or utilize an already-existing one.

Give the project name, select the location of the project, and Click on Next.

Select project framework: .NET 8, as depicted below.

Step 2. Install the following packages in your project from the NuGet package manager.

  • Serilog
  • Serilog.AspNetCore
  • Serilog.Sinks.File
  • Serilog.Sinks.ApplicationInsights

Step 3. After the installation of the necessary packages, we will need to configure Serilog in the appsetting.json file. Implementing logging with Verilog in local files and Appinsights is almost similar. However, there are some changes, such as in Using, Write To, and so on, which you can see in the below appsetting.json file.

Note. You need to have an Azure subscription and have already created application insights for this configuration to work.

"Serilog": {
    "Using": [
        "Serilog.Sinks.ApplicationInsights"
    ],
    "MinimumLevel": {
        "Default": "Information",
        "Override": {
            "Microsoft": "Warning",
            "System": "Warning"
        }
    },
    "WriteTo": [
        {
            "Name": "ApplicationInsights",
            "Args": {
                "connectionString": "",
                "telemetryConverter": "Serilog.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
            }
        }
    ],
    "Enrich": [ "FromLogContext" ],
    "Properties": {
        "Application": "Connect.IMS"
    }
},


If you want to log in to the local file, you can refer to the previous article here.

Step 4. In the Program.cs, we will add the Serilog configuration
builder.Host.UseSerilog((context, configuration) =>
    configuration.ReadFrom.Configuration(context.Configuration));


Step 5. Then, above the App.Run() write Serilog middleware.
app.UseSerilogRequestLogging();

Step 6. Then, we can now log in to any C# class.
Below is an example of logging in TestController.
using Microsoft.AspNetCore.Mvc;
namespace SampleLogger.Controllers;
[ApiController]
[Route("[controller]")]
public class TestController :  ControllerBase
{
    private readonly ILogger<TestController> _logger;
    public TestController(ILogger<TestController> logger)
    {
        _logger = logger;
    }
    [HttpGet]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult Get()
    {
        _logger.LogInformation("Test Controller called!");
        return Ok();
    }
}


Now, we can run the application and check the logs in application insights.

Conclusion

By integrating Serilog to produce more thorough and useful log data, developers can enhance debugging, monitoring, and system maintenance. Because of its structured logging features, Serilog is crucial for contemporary applications as they facilitate log analysis and visualization. The traceability, dependability, and general performance of your application can all be greatly enhanced by using Serilog. This tutorial taught us how to use Application Insights and Serilog to log apps. I hope it's useful to you.



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