Search This Blog

2021-03-09

Basic .NET Topics

 Encapsulation is hiding the complexity, abstraction is focus on the essential characteristic.

Encapsulation is implemented by using access specifiers.

 

public

There are no restrictions on accessing public members.

private

Access is limited to within the class definition. This is the default access modifier type if none is formally specified

protected

Access is limited to within the class definition and any class that inherits from the class

internal

Access is limited exclusively to classes defined within the current project assembly

protected internal

Access is limited to the current assembly and types derived from the containing class. All members in the current project and all members in derived class can access the variables.

private protected

Access is limited to the containing class or types derived from the containing class within the current assembly.

 

Polymorphism is the ability of different objects to respond in a unique way to the same message.

 

An abstract class is a special type of class that cannot be instantiated. An abstract class is designed to be inherited by subclasses that either implement or override its methods. ... You can have functionality in your abstract class—the methods in an abstract class can be both abstract and concrete.

 

When a class is declared sealed, it cannot be inherited, abstract classes cannot be declared sealed.

 

A data type is a value type if it holds a data value within its own memory space. It means variables of these data types directly contain their values.

 

Unlike value types, a reference type doesn't store its value directly. Instead, it stores the address where the value is being stored. In other words, a reference type contains a pointer to another memory location that holds the data.

 

The following data types are of reference type:

•        String

•        All arrays, even if their elements are value types

•        Class

•        Delegates

 

The process of converting from a value type to a reference type is called boxing. The process of converting from a reference type to a value type is called unboxing.

 

Class

Struct

Reference Type

Value Type

Support Inheritance

No Inheritance

The reference can be null

Cannot have a null reference (unless Nullable is used)

 

Interfaces are still different from Abstract classes.

Interfaces support multiple inheritance

Interfaces can NOT provide implementation of an abstract class

Interface methods are by default public, while in abstract class one may have private and protected methods also

 

Const is a variable which has to be assigned a value at compile time. By default, a const is static and we cannot change the value of a const variable throughout the entire program.

Readonly is the keyword whose value we can change during runtime or we can assign it at run time but only through the non-static constructor. No need to assign a value at compile time.

A Static Readonly type variable's value can be assigned at runtime or assigned at compile time and changed at runtime. But this variable's value can only be changed in the static constructor. And cannot be changed further. It can change only once at runtime.

 

ref and out keywords

By default, the value type variable is passed by value, and the reference type variable is passed by reference from one method to another method in C#.C# includes ref and out are keywords, which help us to pass the value type variables to another function by the reference.

 

•The ref keyword passes arguments by reference. It means any changes made to this argument in the method will be reflected in that variable when control returns to the calling method.

The out parameters are always passed by reference for both, the value type and the reference type data types.

•A variable must be assigned a value before passing as an argument with the ref keyword. But in out declare a variable without initializing.

•In the called method, may or may not assign a value for ref parameter. For out variable, called method must specify the value.

•We must specify the ref keyword when passing to the method. Otherwise, it will give a compile-time error. For out, it's Out key word

Both ref and out are treated differently at run time and they are treated the same at compile time. So doesn't support overloading if 2 method one has ref and other has out, the compiler throws exception.

Properties are not variables, therefore it cannot be passed as an out or ref parameter.

 

Convert.ToInt32() calls int.Parse() internally.Except for one thing Convert.ToInt32() returns 0 when argument is null.  TryParse(), Never throws an exception. Returns false if cannot parse to an integer. It must use out parameter.

 

Can “this” be used within a static method ? No, exception is Extension method.

 

Properties or accessors : Can be read/write, read only(only get), write only (only set).

 

A Non Static class can have static method. But Static class should have Static method and Data member only.

 

Dispose vs Finalize

1.       Dispose can be called explicitly by code and Finalize is a non-deterministic method called by GC when it feels.

2.       Dispose free unmanaged resources almost immediately , Finalize cleans unmanaged resources when it goes out of scope.

3.       Dispose is defined in Idisposable interface, Finalize defined in object class.

4.       In dispose, we have to write GC.SuppressFinalized()

 

String vs StringBuilder : String is immutable, so every time when its value changed it will occupy a new memory.

 

Sealed classes are used to restrict the inheritance feature of object-oriented programming. Once a class is defined as a sealed class, the class cannot be inherited.

 

A partial class is only used to split the definition of a class in two or more classes in the same source code file or more than one source file.

 

Early Binding : Compile time Polymorphism, Late Binding : Run time Polymorphism

 

Unlike arrays, an ArrayList can hold data of multiple data types. Elements in the ArrayList are accessed via an integer index. A dynamic array does not have a predefined size using Array.Resize .

 

Constructor Chaining is an approach where a constructor calls another constructor in the same or base class. This is very handy when we have a class that defines multiple constructors. Example : https://www.codeproject.com/Articles/271582/Constructor-Chaining-in-Csharp-2

 

CopyTo

Clone

The CopyTo() method copies the elements into another existing array

The Clone() method returns a new array (a shallow copy) object containing all the elements in the original array.

CopyTo require to have a destination array

 

when Clone return a new array

 

Does Shallow Copy(i.e the contents (each array element) contains references to the same object as the elements in the original array)

Does Shallow copy as well

 

throw ex vs throw

throw ex resets the stack trace (so your errors would appear to originate from HandleException)

throw doesn't - the original offender would be preserved.

 

Difference between the Equality Operator (==) and Equals()

Both the == Operator and the Equals() method are used to compare two value type data items or reference type data items. The Equality Operator (==) is the comparison operator and the Equals() method compares the contents of a string. The == Operator compares the reference identity while the Equals() method compares only contents. Let’s see with some examples.

 

In this example, we assigned a string variable to another variable. A string is a reference type and in the following example, a string variable is assigned to another string variable so they are referring to the same identity in the heap and both have the same content so you get True output for both the == Operator and the Equals() method.

        using System;   

        namespace ComparisionExample {   

            class Program {   

                static void Main(string[] args) {   

                    string name = "sandeep";   

                    string myName = name;   

                    Console.WriteLine("== operator result is {0}", name == myName);   

                    Console.WriteLine("Equals method result is {0}", name.Equals(myName));   

                    Console.ReadKey();   

                }   

            }   

        }  

Is vs As Operator

In C# language, we use the "is" operator to check the object type. If two objects are of the same type, it returns true, else it returns false. The "as" operator behaves in a similar way as the "is" operator. The only difference is it returns the object if both are compatible with that type. Else it returns a null.

Console.WriteLine(o2 is P1);

string str1 = o[q] as string;

 

Var vs dynamic

var is a statically typed variable. So the data type of these variables are inferred at compile time. dynamic are dynamically typed variables. type is inferred at run-time and not the compile time. var does not allow the type of value assigned to be changed after it is assigned to.

 

Serialization in C# is the process of converting an object into a stream of bytes to store the object to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed.

 

Anonymous types allow us to create new types without defining them. This is a way of defining read-only properties in a single object without having to define each type explicitly. Here, Type is generated by the compiler and is accessible only for the current block of code. The type of properties is also inferred by the compiler.

 

We can create anonymous types by using “new” keyword together with the object initializer. It's used in

Select clause of LINQ

 

Example

        var anonymousData = new    

        {   

            ForeName = "Jignesh",   

            SurName = "Trivedi"   

        };   

        Console.WriteLine("First Name : " + anonymousData.ForeName);   

 Through Put in Cosmos DB - 

Generally, the speed of a database system is measured by the transaction throughput, expressed as a number of transactions per second. 

Azure Cosmos DB supports many APIs, such as SQL, MongoDB, Cassandra, Gremlin, and Table. Each API has its own set of database operations. These operations range from simple point reads and writes to complex queries. Each database operation consumes system resources based on the complexity of the operation.

The cost of all database operations is normalized by Azure Cosmos DB and is expressed by Request Units (or RUs, for short). Request unit is a performance currency abstracting the system resources such as CPU, IOPS, and memory that are required to perform the database operations supported by Azure Cosmos DB.

Provisioned throughput mode: In this mode, you provision the number of RUs for your application on a per-second basis in increments of 100 RUs per second. To scale the provisioned throughput for your application, you can increase or decrease the number of RUs at any time in increments or decrements of 100 RUs.

 

IEnumerable vs IQueryable

If you are use IEnumerable when querying data from in-memory collections like List, Array collection etc And when querying data from out-memory (like remote database, service) collections so you are use Iqueryable

IQueryable and IEnumerable represent two different things. Think of a IQueryable as a "question", it does not have any results itself. A IEnumerable is an "answer", it only has data connected to it but you can't tell what generated that data.


2021-03-05

Call Web API from .NET Core using Polly

There is a lot of HttpClient Errors is caused by server overload, temporary network timeouts and generic gliches in the the downstream systems. Those error are temporary and can be dealt with using a retry pattern. In .NET Core, the most common retry library is the Polly library.

Step 1. Download the nuget packages

Microsoft.Extensions.Http.Polly

Polly.Extensions.Http


Step 2.  CONFIGURE SERVICES IN STARTUP.CS

var serviceProvider = services.BuildServiceProvider();
var httpSettings = serviceProvider.GetService<IOptions<HttpSettingsOptions>>()?.Value;            services.AddHttpClient(HttpClientConstants.HttpClientWithBackOff).AddPolicyHandler(GetRetryPolicy(httpSettings));


IOption is used for strongly typed configuration. We need to download the nuget package Microsoft.Extensions.Options for IOption. We need a class structure that matches with the configuration.

So create a class HttpSettingsOptions as below

public class HttpSettingsOptions
    {
        public const string HttpSettings = "HttpSettings";
        public int RetryCount { get; set; }
        public int InitialRetryDelay { get; set; }
    }
Create the similar structure in appSetting.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "HttpSettings": {
    "RetryCount": 3,
    "InitialRetryDelay": 2
  },
  "ServiceURL": {
    "Questionnaire": "https://localhost:44368/api"
  }
}

Create a method GetRetryPolicy in startup.cs and which accept the above httpsetting

 private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpSettingsOptions options)
        {
            return HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(options.RetryCount, retryAttempt =>
                {
                    return TimeSpan.FromSeconds(Math.Pow(options.InitialRetryDelay, retryAttempt));
                });
        }
    }
Now for the parameter of AddHttpClient methods (i.eHttpClientWithBackOff) create a below class
public class HttpClientConstants
    {
        public const string HttpClientWithBackOff = "HttpClientBackOff";
    }

Step 3: USE THE IHttpClientFactory IN THE CALLING CLASS

The IHttpClientFactory can be injected using constructor injection. The cool part of the Polly implementation is that your HttpClient code does not contain any special retry-code, just the usual Get or Post calls:

public class QuestionnaireQueryService : IQuestionnaireQueryService
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly ServiceURLOptions _serviceUrlOptions;
        public QuestionnaireQueryService(IOptions<ServiceURLOptions>
            serviceUrlOptions,
            IHttpClientFactory httpClientFactory)
        {
            _serviceUrlOptions = serviceUrlOptions != null
                ? serviceUrlOptions.Value
                : throw new ArgumentNullException($"Options/Configuration not found for {nameof(serviceUrlOptions)}");
            _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
        }
        public async Task<QuestionnaireServiceModel> GetAllQuestionnaire()
        {
            QuestionnaireServiceModel questionnaireServiceModel = null;
            using var httpClient = _httpClientFactory.CreateClient(HttpClientConstants.HttpClientWithBackOff);
            //httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token);
            var questionnaireResponse = await httpClient.GetAsync($"{_serviceUrlOptions.Questionnaire}/Questions");
            var qResponse = await questionnaireResponse.Content.ReadAsStringAsync();
            if (questionnaireResponse.IsSuccessStatusCode)
            {
                questionnaireServiceModel = JsonConvert.DeserializeObject<QuestionnaireServiceModel>(qResponse);
            }
            return questionnaireServiceModel;
        }
    }

Step 4. Add ServiceURLOptions in ConfigureServices of Startup.cs
services.Configure<ServiceURLOptions>(Configuration.GetSection(ServiceURLOptions.ServiceURLs));

Add below class and make sure ServiceURLOptions is present in appsetting.json as per Step 2 Above

 public class ServiceURLOptions
    {
        public const string ServiceURLs = "ServiceURL";
        public string Questionnaire { get; set; }        
    }

2021-03-03

Integrate Application Insight With .NET Core WebAPI

Configure Azure Web App Configuration

Add the below configuration key in the configuration of azure web app

{

    "name": "Logging.ApplicationInsights.LogLevel.Default",

    "value": "Information",

    "slotSetting": false

  },

  {

    "name": "Logging.ApplicationInsights.LogLevel.APP1.Service",

    "value": "Debug",

    "slotSetting": false

  },

  {

    "name": "Logging.ApplicationInsights.LogLevel.Microsoft",

    "value": "Error",

    "slotSetting": false

  },

  {

    "name": "LogLevel.Default",

    "value": "Information",

    "slotSetting": false

  },

  {

    "name": "LogLevel.Microsoft",

    "value": "Warning",

    "slotSetting": false

  },

  {

    "name": "LogLevel.Microsoft.Hosting.Lifetime",

    "value": "Information",

    "slotSetting": false

  }

Add Instrumentation Key in AppSetting.json

In application.development.json or Appsetting.loal.json add the APPINSIGHTS_INSTRUMENTATIONKEY key from Azure App Insight

"APPINSIGHTS_INSTRUMENTATIONKEY": "9d6e43e7-123c-4bfa-b80e-67c699998a4f"

Add the same key in the web app configuration


The key can be found from Application insight in azure



Install Nuget Package and Configure Applicaton 


Install the nuget package - Microsoft.Extensions.Logging

In Program.cs as below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace App1.Service
{
    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<Startup>()
                .ConfigureLogging(
                builder =>
                {
                    builder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>
                        ("", LogLevel.Trace);
                }
            );

          });
    }
}

Configure Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddLocalization();
// The following line enables Application Insights telemetry collection.
services.AddApplicationInsightsTelemetry(options => {
                options.EnableDebugLogger = true;
                options.InstrumentationKey = this.Configuration.GetSection(FISResource.APP_KEY_APPINSIGHTS_INSTRUMENTATIONKEY).Get<string>();
            });
}

Create a Simple .NET Core Web API Structure

 App.Core Project
















SharedKernel\BaseEntity.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.DataAnnotations;

namespace PairingTest.API.Core.SharedKernel
{
    public abstract class BaseEntity
    {
        [Required]
        [Key]
        public long Id { get; set; }
    }
}

Entities\Question.cs

using PairingTest.API.Core.SharedKernel;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace PairingTest.API.Core.Entities
{
    public class Question : BaseEntity
    {
        [Required]
        public string QuestionnaireTitle { get; set; }
        public List<QuestionOption> QuestionOption { get; set; }
    }
}

Entities\QuestionOption.cs

using PairingTest.API.Core.SharedKernel;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace PairingTest.API.Core.Entities
{
    public class QuestionOption : BaseEntity
    {
        [Required]
        public long QuestionID { get; set; }
        public Question QuestionOptionQuestion { get; set; }
        [Required]
        public string QuestionsText { get; set; }
    }
}

Interfaces\IQuestionnaireService.cs

using PairingTest.API.Core.Entities;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace PairingTest.API.Core.Interfaces
{
    public interface IQuestionnaireService
    {
        Task<List<Question>> GetAllQuestionsWithOptions();
    }
}

Interfaces\IRepository.cs

using PairingTest.API.Core.Entities;
using PairingTest.API.Core.SharedKernel;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace PairingTest.API.Core.Interfaces
{
    public interface IRepository
    {
        T Add<T>(T entity) where T : BaseEntity;
        void Update<T>(T entity) where T : BaseEntity;
        void Delete<T>(T entity) where T : BaseEntity;
        Task<List<Question>> GetAllQuestions();
    }
}

Services\QuestionnaireService.cs

using PairingTest.API.Core.Entities;
using PairingTest.API.Core.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace PairingTest.API.Core.Services
{
    public class QuestionnaireService : IQuestionnaireService
    {
        private IRepository repository;
        public QuestionnaireService(IRepository repos)
        {
            this.repository = repos;
        }
        public async Task<List<Question>> GetAllQuestionsWithOptions()
        {
            return await this.repository.GetAllQuestions();
        }
    }
}

 App.Infrastructure Project















Data\PairingTestDBContext.cs

using Microsoft.EntityFrameworkCore;
using PairingTest.API.Core.Entities;
using PairingTest.API.Infrastructure.DBMapping;
using System;
using System.Collections.Generic;
using System.Text;

namespace PairingTest.API.Infrastructure.Data
{
    public class PairingTestDBContext : DbContext
    {
        public DbSet<Question> Question { get; set; }
        public DbSet<QuestionOption> QuestionOption { get; set; }

        public PairingTestDBContext(DbContextOptions<PairingTestDBContext> options) : base(options)
        {

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Question>().HasData(
               new { Id =(long) 1, QuestionnaireTitle = "Geography Questions" }
            );
            modelBuilder.Entity<QuestionOption>().HasData(
               new { Id = (long)1, QuestionID = (long)1, QuestionsText = "What is the capital of Cuba?" },
               new { Id = (long)2, QuestionID = (long)1, QuestionsText = "What is the capital of France?" },
               new { Id = (long)3, QuestionID = (long)1, QuestionsText = "What is the capital of Poland?" },
               new { Id = (long)4, QuestionID = (long)1, QuestionsText = "What is the capital of Germany?" }
            );

            new QuestionMap(modelBuilder.Entity<Question>());
            new QuestionOptionMap(modelBuilder.Entity<QuestionOption>());
        }
    }
}

Data\PairingTestRepository.cs

using Microsoft.EntityFrameworkCore;
using PairingTest.API.Core.Entities;
using PairingTest.API.Core.Interfaces;
using PairingTest.API.Core.SharedKernel;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace PairingTest.API.Infrastructure.Data
{
    public class PairingTestRepository : IRepository
    {
        private readonly PairingTestDBContext dbContext;
        public PairingTestRepository(PairingTestDBContext context)
        {
            this.dbContext = context;

            if (this.dbContext.Database.IsSqlServer())
            {
                this.dbContext.Database.Migrate();
            }
        }

        public T Add<T>(T entity) where T : BaseEntity
        {
            this.dbContext.Set<T>().Add(entity);
            this.dbContext.SaveChanges();

            return entity;
        }

        public void Delete<T>(T entity) where T : BaseEntity
        {
            this.dbContext.Set<T>().Remove(entity);
            this.dbContext.SaveChanges();
        }

        public void Update<T>(T entity) where T : BaseEntity
        {
            this.dbContext.Entry(entity).State = EntityState.Modified;
            this.dbContext.SaveChanges();
        }

        public async Task<List<Question>> GetAllQuestions()
        {
            List<Question> lstQuestion = await this.dbContext.Question
                .Include(p=>p.QuestionOption)
                .ToListAsync<Question>();
            return lstQuestion;
        }
    }
}

DBMapping\QuestionMap.cs

using Microsoft.EntityFrameworkCore.Metadata.Builders;
using PairingTest.API.Core.Entities;
using System;
using System.Collections.Generic;
using System.Text;

namespace PairingTest.API.Infrastructure.DBMapping
{
    public class QuestionMap
    {
        public QuestionMap(EntityTypeBuilder<Question> entityBuilder)
        {
            entityBuilder.HasKey(p => p.Id);
            entityBuilder.Property(p => p.QuestionnaireTitle).IsRequired();
        }
    }
}

DBMapping\QuestionOptionMap.cs

using Microsoft.EntityFrameworkCore.Metadata.Builders;
using PairingTest.API.Core.Entities;
using System;
using System.Collections.Generic;
using System.Text;

namespace PairingTest.API.Infrastructure.DBMapping
{
    public class QuestionOptionMap
    {
        public QuestionOptionMap(EntityTypeBuilder<QuestionOption> entityBuilder)
        {
            entityBuilder.HasKey(p => p.Id);
            entityBuilder.Property(p => p.QuestionsText).IsRequired();
        }
    }
}

App.WebAPI Project
















appsettings.Development.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "ConnectionStrings": {
    "TESTDB": "Server=(localdb)\\mssqllocaldb;Database=Test01;Trusted_Connection=True;"
  }
}

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PairingTest.API.Infrastructure.Data;
using PairingTest.WebApi.Interfaces;
using Microsoft.EntityFrameworkCore;
using PairingTest.API.Core.Interfaces;
using PairingTest.API.Core.Services;

namespace PairingTest.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddTransient<IQuestionRepository, QuestionRepository>();

            services.AddSingleton(this.Configuration);
            string connectionString = this.Configuration.GetConnectionString("TESTDB");
            services.AddDbContext<PairingTestDBContext>(options => options.UseSqlServer(connectionString));
            services.AddScoped<IRepository, PairingTestRepository>();

            services.AddTransient<IQuestionnaireService, QuestionnaireService>();           

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
           
            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

Interfaces\IQuestionRepository.cs
namespace PairingTest.WebApi.Interfaces
{
    public interface IQuestionRepository
    {
        Questionnaire GetQuestionnaire();
    }
}

Controllers\QuestionsController.cs

using Microsoft.AspNetCore.Mvc;
using PairingTest.API.Core.Interfaces;
using PairingTest.WebApi.Interfaces;

namespace PairingTest.WebApi.Controllers
{
    [Route("api/[controller]")]
    public class QuestionsController : Controller
    {
        private readonly IQuestionRepository _questionRepository;
        private IQuestionnaireService questionnaireService;
        public QuestionsController(IQuestionRepository questionRepository, IQuestionnaireService _questionnaireService)
        {
            _questionRepository = questionRepository;
            this.questionnaireService = _questionnaireService;
        }

        // GET api/questions
        [HttpGet]
        public Questionnaire Get() //public async Task<IActionResult> Get()
        {
            var x =this.questionnaireService.GetAllQuestionsWithOptions().Result;
            return _questionRepository.GetQuestionnaire();
        }
}
}




Use of XUnit in .NET Core application - Part 04: Mocking and Test Coverage

 

Model Error










Mocking – Set Object

If we have to mock below httpcontext class, model and loginservice I order to do unit test of login method











Test Method

Mocking of httpcontext in constructor




















Note the mock class and mock service and ReturnAsAsync and Mock.of shortcut



But as the email address is not using for password comparison, we can ignore that by below code







Final Test method















Test Coverage

Nuget Package – Coverlet

Add it to the Test Project

Run the below command



During CI CD, if you want to store the test coverage result.