ASP.NET Core Archives - Learn Smart Coding https://blogs.learnsmartcoding.com/category/aspnetcore/ Everyone can code! Wed, 22 Dec 2021 16:08:04 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 209870635 Entity Framework Core commands explained with examples https://blogs.learnsmartcoding.com/2021/12/22/entity-framework-core-commands-explained-with-examples/ https://blogs.learnsmartcoding.com/2021/12/22/entity-framework-core-commands-explained-with-examples/#respond Wed, 22 Dec 2021 16:08:04 +0000 https://karthiktechblog.com/?p=999 Introduction Entity Framework Core commands are useful and make our life a bit easy to execute a few tasks. EF Core is popular Entity Framework data access technology. Entity Framework (EF) Core is a lightweight, extensible and open source. EF Core can serve as an object-relational mapper (O/RM) and it supports many database engines. I […]

The post Entity Framework Core commands explained with examples appeared first on Learn Smart Coding.

]]>
Introduction

Entity Framework Core commands are useful and make our life a bit easy to execute a few tasks. EF Core is popular Entity Framework data access technology. Entity Framework (EF) Core is a lightweight, extensible and open source. EF Core can serve as an object-relational mapper (O/RM) and it supports many database engines.

Entity Framework Core commands explained with examples

I will cover all the options from the three commands.

Commands:

  • database Commands to manage the database.
  • dbcontext Commands to manage DbContext types.
  • migrations Commands to manage migrations.

Short video tutorial

Installation

.NET Core CLI

Use the following .NET Core CLI command from the operating system’s command line to install or update the EF Core SQL Server provider

dotnet add package Microsoft.EntityFrameworkCore.SqlServer

Visual Studio NuGet Package Manager Console

Install-Package Microsoft.EntityFrameworkCore.SqlServer


Get the .NET Core CLI tools

dotnet ef must be installed as a global or local tool.

Also, Install the latest Microsoft.EntityFrameworkCore.Design package

dotnet tool install --global dotnet-ef

dotnet add package Microsoft.EntityFrameworkCore.Design

Refer to how to install Entity Framework Core for more information.

Demo App Explained

For the purpose of the demo, I have a sample restaurant app created using DOTNET CORE. Using the app, we will learn how to use all the dotnet ef commands.

Project structure:

The sample app project has five projects in it. Each serves its purpose and it satisfies the separation of concerns. In the real world, the project has more than one layer hence I choose to demo in a similar structure.

Entity Framework Core commands project structure

Entity Classes

 FoodMenus { get; set; }
    }

    public class FoodImages
    {
        public int Id { get; set; }
        public byte[] Image { get; set; }
        public string Mime { get; set; }
        public string ImageName { get; set; }
        public bool IsActive { get; set; }
        public int? FoodMenusId { get; set; }
        public virtual FoodMenus FoodMenus { get; set; }
    }

    public class FoodMenus
    {
        public int Id { get; set; }
        [Required]
        [MinLength(5), MaxLength(100)]
        public string Name { get; set; }
        [Required]
        [MinLength(100), MaxLength(5000)]
        public string Description { get; set; }
        public decimal Price { get; set; }        
        public bool IsActive { get; set; }
        public short? CategoryId { get; set; }
        public virtual Category Category { get; set; }
        public int? CuisineId { get; set; }
        public virtual Cuisine Cuisine { get; set; }
        public virtual List FoodImages { get; set; }
    }

Now, Let’s get started in exploring each command from dotnet ef command.

Using .NET CORE CLI : Command Prompt

  1. I have opened the database layer project’s location in the command prompt. E.g. “KarthikTechBlog.Restaurant.Data”.

2. To check entity framework core is installed and ready to use, type “dotnet ef” in the command prompt and you will see similar or same details as shown in the image.

dotnet entity framework core

EF Core Commands in Action

migrations : add

dotnet ef migrations add InitialCreate -s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj

To create migrations from the application, we use the command migration add followed by name of the migration. -s “location of the startup project” is to specify the startup project. This is required for the project to build and generate the migration.

dotnet ef migrations add

To generate SQL script for the Entity models, use the below command. Remember the script can be generated only when migrations are created.

migrations : script

dotnet ef migrations script  -s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj
dotnet ef migrations script

migrations: list

This lists all the migrations present in the project.

dotnet ef migrations list  -s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj

migrations: remove

Rollbacks the latest migration.

dotnet ef migrations remove-s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj

database: bundle

Creates an executable to update the database.

dotnet ef migrations bundle -s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj

database : update

This command updates the database with the details present in the migration. If the database is not present, it will create one for us.

dotnet ef database update -s ../KarthikTechBlog.Restaurant.API/KarthikTechBlog.Restaurant.API.csproj

database: drop

Deletes the database. some of the options are

  1. --force or -f which is used to just delete without confirmation.
  2. --dry-run option show which database would be dropped, but don’t drop it.
dotnet ef database drop

dbcontext: scaffold

Generates code for a DbContext and entity types for a database. In order for this command to generate an entity type, the database table must have a primary key.

To scaffold all schemas and tables and puts the new files in the Models folder.

dotnet ef dbcontext scaffold "Server=(localdb)\mssqllocaldb;Database=Shopping;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Models


For more options, visit MSDN

dbcontext: optimize

Generates a compiled version of the model used by the DbContext. Added in EF Core 6.

dotnet ef dbcontext optimize

dbcontext: script

Generates a SQL script from the DbContext. Bypasses any migrations.

dotnet ef dbcontext script

Summary

This post covers Entity Framework Core commands and their usage with examples. I hope you enjoyed and learned something new today.

The post Entity Framework Core commands explained with examples appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2021/12/22/entity-framework-core-commands-explained-with-examples/feed/ 0 999
How to solve Http Error 500.19 – Internal Server Error in windows server IIS for Dotnet Core application https://blogs.learnsmartcoding.com/2020/10/18/how-to-solve-http-error-500-19-internal-server-error-in-windows-server-iis-for-dotnet-core-application/ https://blogs.learnsmartcoding.com/2020/10/18/how-to-solve-http-error-500-19-internal-server-error-in-windows-server-iis-for-dotnet-core-application/#comments Sun, 18 Oct 2020 01:33:19 +0000 https://karthiktechblog.com/?p=744 Many of us have seen this common error Http Error 500.19 – Internal Server Error in windows server IIS. In this post, I will walk you through various steps on how to troubleshoot this error for your application. According to one of the Articles in MSDN on this error, the common HResult code is 0x8007000d. […]

The post How to solve Http Error 500.19 – Internal Server Error in windows server IIS for Dotnet Core application appeared first on Learn Smart Coding.

]]>
Many of us have seen this common error Http Error 500.19 – Internal Server Error in windows server IIS.

How to solve Http Error 500.19 - Internal Server Error in windows server IIS

In this post, I will walk you through various steps on how to troubleshoot this error for your application.

According to one of the Articles in MSDN on this error, the common HResult code is 0x8007000d. This problem occurs because the ApplicationHost.config file or the Web.config file contains a malformed XML element.

Step 1

Check the file. Web.config file is available inside the root folder of your application.

Step 2

The ApplicationHost. config file can be found in the folder %WINDIR%\system32\inetsrv\config. It is the root file of the configuration system when you are using IIS 7 and above.

If you have not solved the issue with the above two steps then follow the below troubleshooting steps to identify the issue.

Troubleshooting for HTTP Error 500.19 when publishing .net core project into IIS with 0x80070005

Firstly, to isolate the issue, you should identify what other dotnet applications are hosted in the IIS. For example, if there is a dot net framework application hosted and whether it is working fine or not.

Is your current application is built with Dotnet core ?

Follow these steps as one of them will definitely solve your issue in IIS.

Working Solution – Real-time live example

Step 1

Browse to the virtual directory of the dot net core application and open the location in the command prompt. Now, run the application locally using the dotnet command. Run command “dotnet <your application dll name>”. E.g. “dotnet myapplication.dll”

This will show up any error associated with the application. If you see an error stating “dotnet command not recognized” then you need to install dotnet core SDK on the server. The latest SDK can be installed from the below link Download .NET Core

Step 2

Since you are reading this, I assume the above step did work and you were able to run the dotnet core application locally.

The next important step is to make sure you have ASP.NET Core Runtime installed on IIS to run the DOTNET Core application from IIS.

The ASP.NET Core Runtime enables you to run existing web/server applications. On Windows, we recommended installing the Hosting Bundle, which includes the .NET Core Runtime and IIS support.

Install hosting bundle from the below link. Install the right file as shown in the image.

Download .NET Core

Hosting Bundle

ASP.NET Core Runtime hosting bundle

I hope you have resolved the issue by following the steps outlined above.

Don’t forget to leave a comment if this resolved your issue!

Security tips for Dotnet Core application

Other Interesting Post

Conclusion

In this post, I showed how to solve HTTP Error 500.19 – Internal Server Error in windows server IIS for Dotnet Core application. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below

The post How to solve Http Error 500.19 – Internal Server Error in windows server IIS for Dotnet Core application appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/10/18/how-to-solve-http-error-500-19-internal-server-error-in-windows-server-iis-for-dotnet-core-application/feed/ 5 744
Implement background tasks using IHostedService and access scoped service using IServiceScopeFactory https://blogs.learnsmartcoding.com/2020/10/17/implement-background-tasks-using-ihostedservice-and-access-scoped-service-using-iservicescopefactory/ https://blogs.learnsmartcoding.com/2020/10/17/implement-background-tasks-using-ihostedservice-and-access-scoped-service-using-iservicescopefactory/#comments Sat, 17 Oct 2020 03:39:06 +0000 https://karthiktechblog.com/?p=715 It is easy to implement Background tasks and scheduled work using IHostedService and the BackgroundService class. Sometimes it is required certain work to be offloaded when a Web API request is processed. That work could be accessing database records and update some information on some tables based on existing data. In this post, I’m going […]

The post Implement background tasks using IHostedService and access scoped service using IServiceScopeFactory appeared first on Learn Smart Coding.

]]>
It is easy to implement Background tasks and scheduled work using IHostedService and the BackgroundService class.

Sometimes it is required certain work to be offloaded when a Web API request is processed. That work could be accessing database records and update some information on some tables based on existing data.

In this post, I’m going to show how to Implement background tasks using IHostedService and the BackgroundService class that is suggested by the MSDN article.

Also, I will cover how to access your scoped service from this background task. This way you can access the service to talk to your database to process some information.

From NET Core 2.1 and up, you can use named IHostedService that helps you to easily implement hosted services.

We will register the hosted service that runs in the background while your web host or host is running.

You have to register the hosted services within the familiar ConfigureServices() method of the Startup class, as in the following code from a typical ASP.NET WebHost.

public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup();
            })
            .ConfigureServices(services =>
            {
                services.AddHostedService<StatusCheckerService>();
            });

Use only one way to register from these two options.

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    //Other DI registrations;

    // Register Hosted Services
    services.AddHostedService<StatusCheckerService>();
    services.AddHostedService<MyHostedServiceA>();
    services.AddHostedService<MyHostedServiceB>();
    //...
}

Next is to use the Background base class (available only from dot net core 2.1)

/// 
/// Base class for implementing a long running .
/// 
public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task _executingTask;
    private readonly CancellationTokenSource _stoppingCts =
       new CancellationTokenSource();

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        // Store the task we're executing
        _executingTask = ExecuteAsync(_stoppingCts.Token);

        // If the task is completed then return it,
        // this will bubble cancellation and failure to the caller
        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }

        // Otherwise it's running
        return Task.CompletedTask;
    }

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executingTask == null)
        {
            return;
        }

        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
                                                          cancellationToken));
        }

    }

    public virtual void Dispose()
    {
        _stoppingCts.Cancel();
    }
}

When deriving from the above abstract base class, you just need to implement the ExecuteAsync() method in your own custom hosted service class as shown below.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks; 

namespace Services // your namespace where this class is placed
{
    public class StatusCheckerService: BackgroundService
    {
        private readonly ILogger<StatusCheckerService> logger; 

        public StatusCheckerService(
            ILogger<StatusCheckerService> logger,
        {          
            this.logger = logger;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            logger.LogDebug($"StatusCheckerService is starting."); 

            stoppingToken.Register(() =>
                logger.LogDebug($"StatusCheckerService background task is stopping."));
            while (!stoppingToken.IsCancellationRequested)
            {
                
	// MyMethodOrLogic goes here. You may call any method inside this class.
 logger.LogDebug($"StatusCheckerService task doing background work.");
 
                await Task.Delay(5000, stoppingToken); // Time to pause this background logic
            } 
            logger.LogDebug($"StatusCheckerService background task is stopping.");

        }
    }
} 

For more detailed information on this topic, refer to this post from the MSDN article. My intention in this post is to show you how to access scoped service in this background task and communicate with the database.

Now, you wonder how to access Scoped Service from this background task?

Using IServiceScopeFactory Interface. A factory for creating instances of IServiceScope, which is used to create services within a scope

Complete logic to access scoped service.

 public class StatusCheckerService: BackgroundService
    {
        private readonly ILogger<StatusCheckerService> logger; 
		private readonly IServiceScopeFactory serviceScopeFactory;

        public StatusCheckerService(

            ILogger<StatusCheckerService> logger,IServiceScopeFactory serviceScopeFactory)
        {          
            this.logger = logger;
            this.serviceScopeFactory = serviceScopeFactory;
        }
 

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)

        {

            logger.LogDebug($"StatusCheckerService is starting."); 

            stoppingToken.Register(() =>
                logger.LogDebug($"StatusCheckerService background task is stopping."));
            while (!stoppingToken.IsCancellationRequested)
            {
                
		using (var scope = serviceScopeFactory.CreateScope())
                {
	// You can ask for any service here and DI will resolve it and give you back service instance
var contextService = scope.ServiceProvider.GetRequiredService<IContextService&ht;(); 
				   contextService.YourMethodOrServiceMethod(); //access dbcontext or anything thats available form your service
				}
                logger.LogDebug($"StatusCheckerService task doing background work."); 

                await Task.Delay(5000, stoppingToken); // Time to pause this background logic
            } 
            logger.LogDebug($"StatusCheckerService background task is stopping.");
        }
    }

Related Posts

Conclusion

In this post, I showed how to Implement background tasks using IHostedService and the BackgroundService class and access scoped service. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below

The post Implement background tasks using IHostedService and access scoped service using IServiceScopeFactory appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/10/17/implement-background-tasks-using-ihostedservice-and-access-scoped-service-using-iservicescopefactory/feed/ 6 715
How to use TLS 1.2 in ASP.NET Core 2.0 https://blogs.learnsmartcoding.com/2020/05/29/how-to-use-tls-1-2-in-asp-net-core-2-0-and-above/ https://blogs.learnsmartcoding.com/2020/05/29/how-to-use-tls-1-2-in-asp-net-core-2-0-and-above/#respond Fri, 29 May 2020 15:34:55 +0000 https://karthiktechblog.com/?p=504 In this short post, I will show how to use TLS 1.2 in ASP.NET Core 2.0 and the above version. Why TLS 1.2 ? Client-Server applications use the TLS protocol to communicate across a network in a way designed to prevent eavesdropping and tampering. Since applications can communicate either with or without TLS (or SSL), […]

The post How to use TLS 1.2 in ASP.NET Core 2.0 appeared first on Learn Smart Coding.

]]>
In this short post, I will show how to use TLS 1.2 in ASP.NET Core 2.0 and the above version.

Why TLS 1.2 ?

Client-Server applications use the TLS protocol to communicate across a network in a way designed to prevent eavesdropping and tampering. Since applications can communicate either with or without TLS (or SSL), it is necessary for the client to indicate to the server the setup of a TLS connection. Read more on Transport Layer Security

Encryption protocols like Transport Layer Security (TLS), Secure Sockets Layer (SSL) are intended to keep data secure when being transferred over a network.

Applying fix to use TTLS 1.2 in ASP.NET Core 2.0

In the Program.cs file, use the below code to configure the TLS 1.2.

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
           WebHost.CreateDefaultBuilder(args)
                .UseKestrel(opt =>

                {
                    opt.AddServerHeader = false;
                    opt.ConfigureHttpsDefaults(s =>
                    {
                        s.SslProtocols = SslProtocols.Tls12 ;
                    });
                })
                .ConfigureLogging(builder =>
                {
                    builder.ClearProviders();
                    builder.AddSerilog();
                })
               .UseStartup();
How to use TLS 1.2 in ASP.NET Core 2.0
How to use TLS 1.2 in ASP.NET Core 2.0

Though you can configure TLS 1.2 in Web applications, it will be a good idea to force the webserver to use the minimum security level of TLS 1.2.

There is a good article in MSDN How to enable TLS 1.2

Though this solution could protect the application to support TLS 1.2, the right way of implementing TLS 1.2 and above is to disable the lower version of TLS in the webserver.

The right way of TLS implementation

How to Enable/Disable TLS 1.0, 1.1 and 1.2 in Windows Server using IISCrypto tool

Related Post

You might be interested in the below security-related post, take a look.

Conclusion

In this post, I showed how to use TLS 1.2 in ASP.NET Core 2.0. I also suggested applying a fix in the webserver to support only TLS 1.2 and above versions. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

The post How to use TLS 1.2 in ASP.NET Core 2.0 appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/05/29/how-to-use-tls-1-2-in-asp-net-core-2-0-and-above/feed/ 0 504
How to remove the server header from ASP.NET Core 3.1 https://blogs.learnsmartcoding.com/2020/05/03/how-to-remove-the-server-header-from-asp-net-core-3-1/ https://blogs.learnsmartcoding.com/2020/05/03/how-to-remove-the-server-header-from-asp-net-core-3-1/#comments Sun, 03 May 2020 00:46:21 +0000 https://karthiktechblog.com/?p=473 In this post, I will show how to remove the server header from ASP.NET Core 3.1. The fix is the same for other versions as well. Are you looking for more security features from the below list to implement in the ASP.NET Core application? content-security-policy x-content-type-options: nosniff x-download-options: noopen x-frame-options: Deny x-ua-compatible: IE=edge,chrome=1 x-xss-protection: 1; […]

The post How to remove the server header from ASP.NET Core 3.1 appeared first on Learn Smart Coding.

]]>
In this post, I will show how to remove the server header from ASP.NET Core 3.1. The fix is the same for other versions as well.

Are you looking for more security features from the below list to implement in the ASP.NET Core application?

  • content-security-policy
  • x-content-type-options: nosniff
  • x-download-options: noopen
  • x-frame-options: Deny
  • x-ua-compatible: IE=edge,chrome=1
  • x-xss-protection: 1; mode=block

Related Posts

Add required security code in the ASP.NET Core application to avoid exploitation by the hackers.

Let me walk you through the problem and the solution to it. Most of us create ASP.NET Core applications using the default template that is available from Visual Studio IDE. The created template does not have the security feature implemented by default.

You may create a brand new ASP.NET Core Web Application using the default template and run the default weatherforecast endpoint, you will see the below response.

Open the developers’ tool by pressing F12 on your keyboard.


Response header details for a given API endpoint

Response header has server details displayed which puts the web application gets exploited by the outside world.

Remove Server Header

The code shown below is in the “Program” class which is created by default.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace KarthikTechBlog.SecurityFeatures.API
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup();
                });
    }
}

Fix is pretty small and easy. come, let’s fix it.

Code Fix

Add UseKestrel and specify AddServerHeader to false which is to make sure the server header is not sent in the API response.

webBuilder.UseKestrel((options) =>
                    {
                        // Do not add the Server HTTP header.
                        options.AddServerHeader = false;
                    });

Complete Code

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace KarthikTechBlog.SecurityFeatures.API
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup();
                    webBuilder.UseKestrel((options) =>
                    {
                        // Do not add the Server HTTP header.
                        options.AddServerHeader = false;
                    });
                });
    }
}

How to remove the server header from ASP.NET Core

Server header information removed

Related Resources

Conclusion

In this post, I showed how to remove the server header from ASP.NET Core 3.1. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

The post How to remove the server header from ASP.NET Core 3.1 appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/05/03/how-to-remove-the-server-header-from-asp-net-core-3-1/feed/ 4 473
How to apply various Security Feature in ASP.NET Core application https://blogs.learnsmartcoding.com/2020/05/02/how-to-apply-various-security-feature-in-asp-net-core-application/ https://blogs.learnsmartcoding.com/2020/05/02/how-to-apply-various-security-feature-in-asp-net-core-application/#respond Sat, 02 May 2020 21:08:12 +0000 https://karthiktechblog.com/?p=478 In this post, I will show How to apply various Security Feature in ASP.NET Core application. In today’s world, the attacks against internet-exposed web apps are the top cause of data breaches that is why Web application security is crucial. There is various important security measure one should implement in a website or in a web application. I […]

The post How to apply various Security Feature in ASP.NET Core application appeared first on Learn Smart Coding.

]]>
In this post, I will show How to apply various Security Feature in ASP.NET Core application.

In today’s world, the attacks against internet-exposed web apps are the top cause of data breaches that is why Web application security is crucial. There is various important security measure one should implement in a website or in a web application.

I will show how to implement the most important listed security features in ASP.NET Core application. For this demo, I have used the latest ASP.NET Core 3.1 version. However, you can apply this to a lower version like 2.0, 2.1, and 2.2 as well.

Related Post

Security Feature in ASP.NET Core

Problem Statement

Most of us create ASP.NET Core application using the default template using Visual Studio IDE. The created template does not have the security feature implemented by default.

Missing security feature
Missing security implementation will have this kind of response from an API

Security Feature Implementation

I will show how to implement all the listed security features using Middleware in ASP.NET Core. The complete working code is available in GitHub for your reference.

Create a folder named “Middleware” in your project that keeps us separated for readability.

Now, add a file named CspSettings which should have the properties shown in the below code.

namespace KarthikTechBlog.SecurityFeatures.API
{
    public class CspSettings
    {
        public string Default { get; set; }
        public string Image { get; set; }
        public string Style { get; set; }
        public string Font { get; set; }
        public string Script { get; set; }
        public bool UseHttps { get; set; }
        public bool BlockMixedContent { get; set; }
    }
}

Add a file named MiddlewareExtensions and copy paste the below code.

using Microsoft.AspNetCore.Builder;
using System;

namespace KarthikTechBlog.SecurityFeatures.API
{
    public static class MiddlewareExtensions
    {
        public static IApplicationBuilder UseSecurityHeader(this IApplicationBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            return app.UseMiddleware(new CspSettings
            {
                Default = "'self' https://*.karthiktechblog.com",
                Image = "'self' data: https://*.karthiktechblog.com",
                Style = "'self' 'unsafe-inline' https://*.karthiktechblog.com",
                Font = "'self' data: * https://*.karthiktechblog.com",
                Script = "'self' 'unsafe-inline' https://*.karthiktechblog.com",
                BlockMixedContent = true,
                UseHttps = true
            });
        }

        public static IApplicationBuilder UseSecurityHeader(
            this IApplicationBuilder app,
            Action configure)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            var settings = new CspSettings();
            configure(settings);
            return app.UseMiddleware(settings);
        }
    }
}

Now add a file named SecurityHeader and copy the below code to it.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace KarthikTechBlog.SecurityFeatures.API
{
    /// 
    /// A middleware for adding security headers.
    /// 
    public class SecurityHeader
    {
        private readonly RequestDelegate _next;
        private readonly CspSettings _settings;
        private readonly SecurityHeaderService _securityHeaderService;

        private readonly ILogger _logger;

        public SecurityHeader(
            RequestDelegate next,
            ILoggerFactory loggerFactory,
            CspSettings settings)
        {
            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _next = next ?? throw new ArgumentNullException(nameof(next));
            _securityHeaderService = new SecurityHeaderService();
            _logger = loggerFactory.CreateLogger();
            _settings = settings ?? throw new ArgumentNullException(nameof(settings));
        }

        public Task Invoke(HttpContext context)
        {
            if (_settings == null)
            {
                _logger.LogDebug("no csp settings found");
                return _next(context);
            }

            var isOptionsRequest = string.Equals(context.Request.Method, HttpMethods.Options, StringComparison.OrdinalIgnoreCase);
            if (!isOptionsRequest)
            {
                context.Response.OnStarting(OnResponseStarting, context);
                return _next(context);
            }

            return _next(context);
        }

        private Task OnResponseStarting(object state)
        {
            var context = (HttpContext)state;
            try
            {
                _securityHeaderService.ApplyResult(context.Response, _settings);
            }
            catch (Exception exception)
            {
                _logger.LogError(exception, "Failed to set security header");
            }
            return Task.CompletedTask;
        }
    }
}

Add another file named SecurityHeaderService and add the code shown below.

using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Text;

namespace KarthikTechBlog.SecurityFeatures.API
{
    public class SecurityHeaderService
    {
        private readonly string[] RemoveHeader = new[] { "Server" };
        private readonly string CSP_HEADER = "Content-Security-Policy";

         private readonly IDictionary SecurityHeader = new Dictionary
        {
            { "X-Content-Type-Options", "nosniff" },            
            { "X-UA-Compatible", "IE=edge,chrome=1" },
            { "X-Download-Options", "noopen" },
            { "X-Frame-Options", "Deny" },
            { "X-XSS-Protection", "1; mode=block" },
            // The Referer header will be omitted entirely to avoid sending of url to oter domain. eg seding to CDN
            // there is chance that the referer url will have a token or password that you do not want to send to other domain/web server.
            { "Referrer-Policy", "no-referrer" }
        };
        internal void ApplyResult(HttpResponse response, CspSettings settings)
        {
            var headers = response.Headers;

            StringBuilder stb = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(settings.Default))
                stb.Append($"default-src {settings.Default};");
            if (!string.IsNullOrWhiteSpace(settings.Image))
                stb.Append($"img-src {settings.Image};");
            if (!string.IsNullOrWhiteSpace(settings.Style))
                stb.Append($"style-src {settings.Style};");
            if (!string.IsNullOrWhiteSpace(settings.Font))
                stb.Append($"font-src {settings.Font};");
            if (!string.IsNullOrWhiteSpace(settings.Script))
                stb.Append($"script-src {settings.Script};");
            if (settings.BlockMixedContent)
                // block all mixed contents( force to use https )
                stb.Append("block-all-mixed-content;");
            if (settings.UseHttps)
                // redirect to https
                stb.Append("upgrade-insecure-requests;");

            headers[CSP_HEADER] = stb.ToString();
            foreach (var headerValuePair in SecurityHeader)
            {
                headers[headerValuePair.Key] = headerValuePair.Value;
            }

            foreach (var header in RemoveHeader)
            {
                headers.Remove(header);
            }
        }
    }
}

Let’s add a static class called ApplicationBuilderExtensions and make use of calling UseSecurityHeaders to set Security headers. This class can go directly to your project.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace KarthikTechBlog.SecurityFeatures.API
{
    /// 
    /// A simple middleware to process the request to use UseSecurityHeaders
    /// 
    public static class ApplicationBuilderExtensions
    {
         /// Security Header middleware
        internal static IApplicationBuilder UseSecurityHeaders(this IApplicationBuilder app,
            IConfiguration configuration,
            IWebHostEnvironment env)
            => MiddlewareExtensions.UseSecurityHeader(app, (settings) =>
            {
                settings.Default = configuration["SecurityHeader:CSP:default"];
                settings.Image = configuration["SecurityHeader:CSP:image"];
                settings.Style = configuration["SecurityHeader:CSP:style"];
                settings.Font = configuration["SecurityHeader:CSP:font"];
                settings.Script = configuration["SecurityHeader:CSP:script"];
                settings.BlockMixedContent = !env.IsDevelopment();
                settings.UseHttps = !env.IsDevelopment();
            });
    }
}

Few more simple code to be added in our settings file and startup class.

Add the SecurityHeader settings for csp in your environment settings’s json file.

 "SecurityHeader": {
    "CSP": {
      "default": "* data: blob: 'unsafe-inline' 'unsafe-eval'",
      "script": "* data: blob: 'unsafe-inline' 'unsafe-eval'"
    }
  }

Add the below in the settings.json file

 "SecurityHeader": {
    "CSP": {
      "default": "'self' https://*.karthiktechblog.com",
      "image": "'self' data: https://*.karthiktechblog.com",
      "style": "'self' 'unsafe-inline' https://*.karthiktechblog.com",
      "font": "'self' data: * https://*.karthiktechblog.com",
      "script": "'self' 'unsafe-inline' https://*.karthiktechblog.com"
    }
  }

don’t forget to change karthiktechblog.com to your website name or your organization project domain name.

The final piece of code to consume all the implementation. Go to the Startup class and inside the Configure Method, add app..UseSecurityHeaders(Configuration, env);

To Add HSTS security feature, add the below code.

 if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

Explanation of the above implementation

In this implementation, I have configured the application to use SecurityHeader middleware to include all the required settings like CSP and other security headers. Also, the logic applies all these features on each and every API’s response while the response is been prepared. E.g. OnResponseStarting method.

Result after applying Security Feature in ASP.NET Core

How to apply various Security Feature in ASP.NET Core
API response with all the security feature implemented

GitHub Reference

The entire working code is in GitHub. Repository name is SecurityFeature

Conclusion

In this post, I showed how to apply various Security Feature in ASP.NET Core application 3.1. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below

The post How to apply various Security Feature in ASP.NET Core application appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/05/02/how-to-apply-various-security-feature-in-asp-net-core-application/feed/ 0 478
Working with optional body parameters in ASP.NET Core 2.2 https://blogs.learnsmartcoding.com/2020/04/04/working-with-optional-body-parameters-in-asp-net-core-2-2/ https://blogs.learnsmartcoding.com/2020/04/04/working-with-optional-body-parameters-in-asp-net-core-2-2/#respond Sat, 04 Apr 2020 20:33:43 +0000 https://karthiktechblog.com/?p=444 Working with optional body parameters in ASP.NET Core 2.2 is now possible and I will show how to solve the issue in this post. Optional parameter exists in .Net for a long time. Specifying the default value used to be enough to mark them as optional. However, marking a body parameter in a Web API […]

The post Working with optional body parameters in ASP.NET Core 2.2 appeared first on Learn Smart Coding.

]]>
Working with optional body parameters in ASP.NET Core 2.2 is now possible and I will show how to solve the issue in this post. Optional parameter exists in .Net for a long time. Specifying the default value used to be enough to mark them as optional. However, marking a body parameter in a Web API action method is not going to work if you are working with .NET Core 2, 2.1 and 2.2 versions.

Let me explain the problem that you might face and a solution to solve the problem.

An issue in accepting body parameter as optional

I have a model class in my action method and that reads the content from the body as shown below.

        // POST api/values
        [HttpPost]
        public IActionResult Post([FromBody]ModelClass request = null)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            return Ok();
        }

Here is the problem, as soon as you include an attribute [FromBody], MVC binding will trigger. If you did not send content in the request body, you will see an error as shown below.

{
  "": [
    "A non-empty request body is required."
  ]
}

This is an existing issue in .NET Core 2.0. Optional body parameters no longer work since upgrading to .NET Core 2.0 #6920

Solution

One of the solutions is to read the content from the request body and then process it if it was sent in the request.

 string body;
            SomeClassModel model = null;
            using (var reader = new StreamReader(Request.Body, Encoding.UTF8, true, 1024, true))
            {
                body = reader.ReadToEnd();
            }

            if (!string.IsNullOrEmpty(body))
            {
               finalModel = JsonConvert.DeserializeObject(body);
            }

This way the body parameters can be made optional and custom validation can be implemented in case you need to validate a JSON string in the body parameter.

Related Posts

Implement create, read, update, and delete functionalities using Entity Framework Core

Conclusion

In this post, I showed how to work with optional body parameters in ASP.NET Core 2.2. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

The post Working with optional body parameters in ASP.NET Core 2.2 appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/04/04/working-with-optional-body-parameters-in-asp-net-core-2-2/feed/ 0 444
How to upload a file with .NET CORE Web API 3.1 using IFormFile https://blogs.learnsmartcoding.com/2020/04/04/how-to-upload-a-file-with-net-core-web-api-3-1-using-iformfile/ https://blogs.learnsmartcoding.com/2020/04/04/how-to-upload-a-file-with-net-core-web-api-3-1-using-iformfile/#respond Sat, 04 Apr 2020 15:41:08 +0000 https://karthiktechblog.com/?p=434 In this post, I will show how to upload a file with .NET CORE Web API 3.1 using IFormFile. Uploading a file is a process of uploading a file from the user’s system to a hosted web application server. You may choose to store the file in the web server’s local disc or in the […]

The post How to upload a file with .NET CORE Web API 3.1 using IFormFile appeared first on Learn Smart Coding.

]]>
In this post, I will show how to upload a file with .NET CORE Web API 3.1 using IFormFile.

Uploading a file is a process of uploading a file from the user’s system to a hosted web application server. You may choose to store the file in the web server’s local disc or in the database.

With ASP NET CORE, it is easy to upload a file using IFormFile that comes under the namespace "Microsoft.AspNetCore.Http". IFormFile represents a file sent with the HttpRequest.

Upload File using IFormFile in .NET Core

Methods of uploading files have changed since DOT NET CORE was introduced. To upload a single file using .NET CORE Web API, use IFormFile which Represents a file sent with the HttpRequest.

This is how a controller method looks like which accepts a single file as a parameter.

[HttpPost("upload", Name = "upload")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> UploadFile(
         IFormFile file,
         CancellationToken cancellationToken)
        {
            if (CheckIfExcelFile(file))
            {
                await WriteFile(file);
            }
            else
            {
                return BadRequest(new { message = "Invalid file extension" });
            }

            return Ok();
        }

Code Explanation

The controller action method “UploadFile” accepts file using IFormFile as a parameter. We check whether the file sent is in the required format using a custom private method named “CheckIfExcelFile” which checks whether an incoming file is an excel file. You may change this based on your needs.

       
 private bool CheckIfExcelFile(IFormFile file)
        {
            var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
            return (extension == ".xlsx" || extension == ".xls"); // Change the extension based on your need
        }

Once the validation is a success, we save the file to the disc using “WriteFile(file)” method.

private async Task<bool> WriteFile(IFormFile file)
        {
            bool isSaveSuccess = false;
            string fileName;
            try
            {
                var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                fileName = DateTime.Now.Ticks + extension; //Create a new Name for the file due to security reasons.

                var pathBuilt = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\files");

                if (!Directory.Exists(pathBuilt))
                {
                    Directory.CreateDirectory(pathBuilt);
                }

                var path = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\files",
                   fileName);

                using (var stream = new FileStream(path, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }

                isSaveSuccess = true;
            }
            catch (Exception e)
            {
               //log error
            }

            return isSaveSuccess;
        }

Yes, to upload a file with .NET CORE Web API 3.1 using IFormFile is very easy with DOTNET CORE Web API.

How to upload a file with .NET CORE Web API 3.1 using IFormFile

Here is the short video tutorial.

Upload file from Angular, Video demo

Complete Code

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace KarthikTechBlog.API.Controllers
{
    [HttpPost("upload", Name = "upload")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> UploadFile(
         IFormFile file,
         CancellationToken cancellationToken)
        {
            if (CheckIfExcelFile(file))
            {
                await WriteFile(file);
            }
            else
            {
                return BadRequest(new { message = "Invalid file extension" });
            }

            return Ok();
        }

        /// 
        /// Method to check if file is excel file
        /// 
        /// 
        /// 
        private bool CheckIfExcelFile(IFormFile file)
        {
            var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
            return (extension == ".xlsx" || extension == ".xls"); // Change the extension based on your need
        }

        private async Task<bool> WriteFile(IFormFile file)
        {
            bool isSaveSuccess = false;
            string fileName;
            try
            {
                var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                fileName = DateTime.Now.Ticks + extension; //Create a new Name for the file due to security reasons.

                var pathBuilt = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\files");

                if (!Directory.Exists(pathBuilt))
                {
                    Directory.CreateDirectory(pathBuilt);
                }

                var path = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\files",
                   fileName);

                using (var stream = new FileStream(path, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }

                isSaveSuccess = true;
            }
            catch (Exception e)
            {
               //log error
            }

            return isSaveSuccess;
        }
    }
}

GitHub Code

You can get the complete code from github https://github.com/karthiktechblog/UploadFileUsingDotNETCore

Reference

Read more about IFormFile Interface
To upload multiple files, use IFormFileCollection Interface

Related Posts

Conclusion

In this post, I showed how to upload a file with .NET CORE Web API 3.1 using IFormFile. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

The post How to upload a file with .NET CORE Web API 3.1 using IFormFile appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/04/04/how-to-upload-a-file-with-net-core-web-api-3-1-using-iformfile/feed/ 0 434
Entity Framework Core dbcontextoptionsbuilder does not contain a definition for usesqlserver – Solved https://blogs.learnsmartcoding.com/2020/03/04/entity-framework-core-dbcontextoptionsbuilder-does-not-contain-a-definition-for-usesqlserver-solved/ https://blogs.learnsmartcoding.com/2020/03/04/entity-framework-core-dbcontextoptionsbuilder-does-not-contain-a-definition-for-usesqlserver-solved/#respond Wed, 04 Mar 2020 16:19:04 +0000 https://karthiktechblog.com/?p=406 Introduction In this post, I will show how to solve the error that shows “Entity Framework Core dbcontextoptionsbuilder does not contain a definition for UseSqlServer” with ASP.Net Core 3 and 3.1 framework. Overview We wanted to connect our ASP.NET Core application with MS SQL. To do this, we configure a connection in the startup class. […]

The post Entity Framework Core dbcontextoptionsbuilder does not contain a definition for usesqlserver – Solved appeared first on Learn Smart Coding.

]]>
Introduction

In this post, I will show how to solve the error that shows “Entity Framework Core dbcontextoptionsbuilder does not contain a definition for UseSqlServer” with ASP.Net Core 3 and 3.1 framework.

Overview

We wanted to connect our ASP.NET Core application with MS SQL. To do this, we configure a connection in the startup class.

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContextPool(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DbContext")));

            services.AddControllers();
        }

However, when I did the same setup with ASP.NET Core 3.1, I ran into issue. Compiler complained that “Entity Framework Core dbcontextoptionsbuilder does not contain a definition for UseSqlServer”.

Entity Framework Core dbcontextoptionsbuilder does not contain a definition for usesqlserver

Solution

After digging into the issue, I figured out there was a small change done from Microsoft and to make this work you need to just add a package called “Microsoft.EntityFrameworkCore.SqlServer“.

Install NuGet Package Microsoft.EntityFrameworkCore.SqlServer

    
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />

Or

PM > Install-Package Microsoft.EntityFrameworkCore.SqlServer

Just remove or comment the lines that are showing as error and install the package. That’s it!

dbcontextoptionsbuilder does not contain a definition for usesqlserver solved

Also see how to Implement create, read, update, and delete functionalities using Entity Framework Core

Conclusion

Thanks for reading this piece. As you can see, the method is not moved to a different namespace from ASP.NET Core 3.0 version and installing this extra package will solve the problem. Let me know in the comments if you have questions.

The post Entity Framework Core dbcontextoptionsbuilder does not contain a definition for usesqlserver – Solved appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/03/04/entity-framework-core-dbcontextoptionsbuilder-does-not-contain-a-definition-for-usesqlserver-solved/feed/ 0 406
Implement create, read, update, and delete functionalities using Entity Framework Core https://blogs.learnsmartcoding.com/2020/01/10/implement-curd-functionalities-in-aspnetcore-using-entity-framework-core/ https://blogs.learnsmartcoding.com/2020/01/10/implement-curd-functionalities-in-aspnetcore-using-entity-framework-core/#comments Fri, 10 Jan 2020 11:02:02 +0000 https://karthiktechblog.com/?p=310 Introduction In this post, I show how to Implement CURD functionality in ASPNETCORE using Entity Framework Core. I have my existing project with bare minimum configuration setup to start and to start with this post demo, I will be using it. To follow along with me for this post, you need to know some basic […]

The post Implement create, read, update, and delete functionalities using Entity Framework Core appeared first on Learn Smart Coding.

]]>
Introduction

In this post, I show how to Implement CURD functionality in ASPNETCORE using Entity Framework Core. I have my existing project with bare minimum configuration setup to start and to start with this post demo, I will be using it.

To follow along with me for this post, you need to know some basic knowledge on setting up a SQL Database to use as our back end.

To know more, take a look at my post CONFIGURE AZURE SQL RELATIONAL DATABASE USING VS 2019

The full demo application is available for free and you may download from my GitHub repository. Take “feature/ImplementCURDFunctionality” branch for this demo.

Getting Started

Now with the demo application in place, we have setup our back end database which has shopping related entities. I will show you how to implement create, read, update, and delete functionalities using Entity Framework Core.

I will be implementing CURD functionalities for Product entity.

To speed up the development work and also to encapsulate the logic required to access data sources, I will be using Repository pattern in this demo and to my demo project.

What is Repository pattern ?

Repositories are classes or components that encapsulate the logic required to access data sources. The functionality written in the repository is centralized and providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.

As we are using Object-Relational Mapper (ORM) like Entity Framework Core in our project, the code that must be implemented is simplified and it is easy to use.

If you ever think why not to use UnitOfWork pattern along with the repository patter, the answer is NO in my opinion.

This is because, the ORM, in our case Entity Framework Core itself is designed using UnitOfWork design patter as it is tracking all the changes that we make and commits all at once.

It is good idea not to bring in a wrapper for EntityFramework Core.

Repository Setup

Let’s have a generic repository which will have most of the common logic that is required to perform CURD operation on a given entity.

 public interface IGenericRepository
    {
        Task> GetAsync(
            Expression> filter = null,
            Func, IOrderedQueryable> orderBy = null,
            string includeProperties = "", CancellationToken cancellationToken = default, bool trackable = true);

        Task GetByIdAsync(object id, CancellationToken cancellationToken = default);

        Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default);
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        void Update(TEntity entityToUpdate);
        void UpdateStateAlone(TEntity entityToUpdate);
        void DetachEntities(TEntity entityToDetach);
        void DetachEntities(List entitiesToDetach);
    }
 public class GenericRepository : IGenericRepository
   where TEntity : class, new()
    {
        private readonly ManageTextDbContext context;
        internal DbSet dbSet;

        public GenericRepository(ManageTextDbContext context)
        {
            this.context = context;
            dbSet = context.Set();
        }

        public virtual Task> GetAsync(
            Expression> filter = null,
            Func, IOrderedQueryable> orderBy = null,
            string includeProperties = "", CancellationToken cancellationToken = default, bool trackable = true)
        {
            IQueryable query = dbSet;

            if (filter != null)
            {
                query = trackable ? query.Where(filter).AsNoTracking() : query.Where(filter).AsNoTracking();
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty).AsNoTracking();
            }

            if (orderBy != null)
            {
                return orderBy(query).AsNoTracking().ToListAsync();
            }
            else
            {
                return query.AsNoTracking().ToListAsync();
            }
        }

        public virtual Task GetByIdAsync(object id, CancellationToken cancellationToken = default)
        {
            return dbSet.FindAsync(id);
        }

        public virtual Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
        {
            return dbSet.AddAsync(entity, cancellationToken);
        }

        public virtual void Delete(object id)
        {
            TEntity entityToDelete = dbSet.Find(id);
            Delete(entityToDelete);
        }

        public virtual void Delete(TEntity entityToDelete)
        {
            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityToDelete);
            }
            dbSet.Remove(entityToDelete);
        }

        public virtual void Update(TEntity entityToUpdate)
        {
            dbSet.Attach(entityToUpdate);
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }

        public virtual void UpdateStateAlone(TEntity entityToUpdate)
        {            
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }

        public void DetachEntities(TEntity entityToDetach)
        {
            context.Entry(entityToDetach).State = EntityState.Detached;            
        }

        public void DetachEntities(List entitiesToDetach)
        {
            foreach (var entity in entitiesToDetach)
            {
                context.Entry(entity).State = EntityState.Detached;
            }
        }

    }

Setup repository for Entities

In this demo, I need a repository for Product entity, below is the code to setup IProductRepository.

using KarthikTechBlog.Shopping.Core;
using System.Threading.Tasks;

namespace KarthikTechBlog.Shopping.Data
{
    public interface IProductRepository : IGenericRepository
    {
        Task CommitAsync();
    }
}
using KarthikTechBlog.Shopping.Core;
using System.Threading.Tasks;

namespace KarthikTechBlog.Shopping.Data
{
    public class ProductRepository : GenericRepository, IProductRepository
    {
        private readonly ShoppingDbContext _context;
        public ProductRepository(ShoppingDbContext context) : base(context)
        {
            _context = context;
        }

        public Task CommitAsync()
        {
            return _context.SaveChangesAsync();
        }
    }
}

Create Product Service

Let’s create a service for the Product entity and this will access all product related functionality.

using KarthikTechBlog.Shopping.Core;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace KarthikTechBlog.Shopping.Service
{
    public interface IProductService
    {
        Task CreateProductAsync(Product product);
        Task UpdateProductAsync(Product product);
        Task DeleteProductAsync(int productId);
        Task> GetProductsAsync();
        Task GetProductAsync(int productId);
    }
}

using KarthikTechBlog.Shopping.Core;
using KarthikTechBlog.Shopping.Data;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace KarthikTechBlog.Shopping.Service
{
    public class ProductService: IProductService
    {
        public ProductService(IProductRepository productRepository)
        {
            ProductRepository = productRepository;
        }

        public IProductRepository ProductRepository { get; }

        public async Task CreateProductAsync(Product product)
        {
            await ProductRepository.InsertAsync(product);
            return await ProductRepository.CommitAsync();
        }

        public async Task DeleteProductAsync(int productId)
        {
            ProductRepository.Delete(productId);
            return await ProductRepository.CommitAsync();
        }

        public Task GetProductAsync(int productId)
        {
            return ProductRepository.GetByIdAsync(productId);
        }

        public Task> GetProductsAsync()
        {
            return ProductRepository.GetAsync();
        }

        public async Task UpdateProductAsync(Product product)
        {
            ProductRepository.Update(product);
            return await ProductRepository.CommitAsync();
        }
    }
}

Now all we left here is controller, come let’s write some minimum code to complete our CURD functionality for Product entity.

Read Product data (GET API)

    public class ProductController : ControllerBase
    {
        public ProductController(IProductService productService)
        {
            ProductService = productService;
        }

        public IProductService ProductService { get; }

        public async Task GetProduct(
           [FromQuery] int productId)
        {
            var product = await ProductService.GetProductAsync(productId);
            return Ok(product);
        }
    }

The controller code is pretty simply, that is the beauty of using right layers to talk to back end database. In this case, we inject the Service layer for Product and call the required methods to get Product data.

Now, one thing in this I would like to change. Currently we are returning the entity model itself from the controller. what if we need to add custom data annotation or custom model validation? I will show you the custom validation in another post.

For now, let’s create view model for that we need to send to client which is our API consuming client.

I have created ProductViewModel as the model for any GET API calls.

public class ProductViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public DateTime? AvailableSince { get; set; }
        public int StockCount { get; set; }
        public int CategoryId { get; set; }
    }

Configure AutoMapper

Now, we need to map our Entity properties to custom view model. There are two ways we can do this, one is to manually assign values and other best one is to use AutoMapper.

Add auto mapper package to the API project to setup AutoMapper

AutoMapper Version="8.0.0" AutoMapper.Extensions.Microsoft.DependencyInjection Version="6.0.0"

Configure AutoMapper for the Entities

Add a class AutoMapperConfiguration to the API project and inherit Profile class from AutoMapper. Create configuration for Product and ProductViewModel.

 public class AutoMapperConfiguration : Profile
    {
        public AutoMapperConfiguration()
        {
            CreateMap(); //source, destination
        }
    }

Modified Controller Code

using AutoMapper;
using KarthikTechBlog.Shopping.API.ViewModel;
using KarthikTechBlog.Shopping.Service;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace KarthikTechBlog.Shopping.API.Controllers
{
    public class ProductController : ControllerBase
    {
        public ProductController(IProductService productService, IMapper mapper)
        {
            ProductService = productService;
            Mapper = mapper;
        }

        public IProductService ProductService { get; }
        public IMapper Mapper { get; }

        public async Task GetProduct(
           [FromQuery] int productId)
        {
            var product = await ProductService.GetProductAsync(productId);
            var model = Mapper.Map(product);
            return new OkObjectResult(model);
        }
    }
}

Complete Controller Code to Implement CURD functionality in ASPNETCORE

using AutoMapper;
using KarthikTechBlog.Shopping.API.ViewModel;
using KarthikTechBlog.Shopping.Service;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using KarthikTechBlog.Shopping.Core;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;

namespace KarthikTechBlog.Shopping.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        public ProductController(IProductService productService, IMapper mapper)
        {
            ProductService = productService;
            Mapper = mapper;
        }

        public IProductService ProductService { get; }
        public IMapper Mapper { get; }

        [HttpGet("{productId}")]
        [ProducesResponseType(typeof(ProductViewModel), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status404NotFound)]
        public async Task GetProduct(
           [FromRoute] int productId)
        {
            var product = await ProductService.GetProductAsync(productId);

            if (product == null)
                return NotFound();

            var model = Mapper.Map(product);
            return new OkObjectResult(model);
        }

        [HttpGet("")]
        [ProducesResponseType(typeof(IReadOnlyList), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status404NotFound)]
        public async Task GetProducts()
        {
            var products = await ProductService.GetProductsAsync();

            var model = Mapper.Map>(products);
            return new OkObjectResult(model);
        }

        [HttpPost("", Name = "CreateProduct")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status400BadRequest)]
        public async Task CreateProduct(
           [FromBody] CreateProduct product)
        {
            var entityToAdd = Mapper.Map(product);

            await ProductService.CreateProductAsync(entityToAdd);

            return Ok();
        }

        [HttpPut("{productId}", Name = "UpdateProduct")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task UpdateProduct(
           [FromRoute] int productId, [FromBody] UpdateProduct product)
        {

            var existingProduct = await ProductService.GetProductAsync(productId);

            if (existingProduct == null)
                return NotFound();

            var entityToUpdate = Mapper.Map(product);

            await ProductService.UpdateProductAsync(entityToUpdate);

            return Ok();
        }


        [HttpDelete("{productId}", Name = "DeleteProduct")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task DeleteProduct(
          [FromRoute] int productId)
        {

            var existingProduct = await ProductService.GetProductAsync(productId);

            if (existingProduct == null)
                return NotFound();

            await ProductService.DeleteProductAsync(productId);

            return Ok();
        }

    }
}

One last thing to include is to configure the DI in the ConfigureServices method of startup class.

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext(options =>
               options.UseSqlServer(Configuration.GetConnectionString("DbContext")));
                        
            services.AddScoped();
            services.AddScoped();
            services.AddAutoMapper();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

Additional Resource

Design the infrastructure persistence layer

Conclusion

In this post, I showed how to implement create, read, update, and delete functionalities using Entity Framework Core. This post is part of learning track for azure AZ-203 certification. I have covered end to end coding that is required to write a good Restful API. In next post, I will show how to create API documentation using OpenAPI & Swagger.

That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

The post Implement create, read, update, and delete functionalities using Entity Framework Core appeared first on Learn Smart Coding.

]]>
https://blogs.learnsmartcoding.com/2020/01/10/implement-curd-functionalities-in-aspnetcore-using-entity-framework-core/feed/ 1 310