Thursday, April 15, 2021

Azure Series : Cosmos DB : Enhancing Query Performance with Azure Cosmos DB Indexing in .NET Core: Practical Code and Data Examples

 In modern applications, query performance is crucial for providing a seamless user experience. Azure Cosmos DB, a globally distributed NoSQL database service, offers indexing capabilities to optimize query performance. In this article, we will explore practical code and data examples of how to leverage Azure Cosmos DB indexing in .NET Core applications to enhance query performance.

Setting up the Environment

Before we begin, ensure you have the necessary prerequisites installed:

  1. Visual Studio or Visual Studio Code with the .NET Core SDK.
  2. Azure Cosmos DB account and connection string.

Step 1: Create a .NET Core Project

Open Visual Studio or Visual Studio Code and create a new .NET Core project. Select the appropriate project template based on your application's needs.

Step 2: Install Azure Cosmos DB NuGet Package

In the NuGet Package Manager Console, install the official Azure Cosmos DB SDK for .NET Core:

Install-Package Microsoft.Azure.Cosmos

Step 3: Connect to Azure Cosmos DB

In your .NET Core application, establish a connection to your Azure Cosmos DB account using the CosmosClient class:

using Microsoft.Azure.Cosmos;

const string cosmosDbConnectionString = "YOUR_CONNECTION_STRING";
CosmosClient cosmosClient = new CosmosClient(cosmosDbConnectionString);

Step 4: Define and Configure Indexing Policies

Decide whether you want to use Automatic Indexing or Manual Indexing. For Manual Indexing, define and configure the indexing policy for your container:

// Define the indexing policy
IndexingPolicy indexingPolicy = new IndexingPolicy
{
    Automatic = false, // Set to true for automatic indexing
    IndexingMode = IndexingMode.Consistent,
    IncludedPaths = new Collection<IncludedPath>
    {
        new IncludedPath
        {
            Path = "/*" // All properties will be indexed
        }
    }
};

// Create or retrieve the container and set the indexing policy
Database database = await cosmosClient.GetDatabase("YOUR_DATABASE_ID");
Container container = await database.GetContainer("YOUR_CONTAINER_ID");
await container.ReplaceContainerAsync(new ContainerProperties(container.Id, partitionKeyPath)
{
    IndexingPolicy = indexingPolicy
});

Step 5: Insert Sample Data

Insert some sample data into the container:

public class SampleData
{
    public string Id { get; set; }
    public string Name { get; set; }
    // Add more properties as needed
}

// Insert sample data into the container
SampleData data1 = new SampleData { Id = "1", Name = "John Doe" };
await container.CreateItemAsync(data1);

SampleData data2 = new SampleData { Id = "2", Name = "Jane Smith" };
await container.CreateItemAsync(data2);

Step 6: Execute Queries with Indexing

Now, let's execute some queries using the indexing strategy:

// Query for items with a specific Name property
string query = "SELECT * FROM c WHERE c.Name = @name";
QueryDefinition queryDefinition = new QueryDefinition(query).WithParameter("@name", "John Doe");

FeedIterator<SampleData> queryResultSetIterator = container.GetItemQueryIterator<SampleData>(
    queryDefinition, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("YOUR_PARTITION_KEY_VALUE") });

List<SampleData> results = new List<SampleData>();
while (queryResultSetIterator.HasMoreResults)
{
    FeedResponse<SampleData> response = await queryResultSetIterator.ReadNextAsync();
    results.AddRange(response.Resource);
}

// Process the results as needed

Azure Cosmos DB indexing is a powerful tool to optimize query performance in .NET Core applications. By strategically using indexes, you can reduce data retrieval times, minimize resource consumption, and improve overall application responsiveness. The code and data examples presented in this article demonstrate how to connect to Azure Cosmos DB, define indexing policies, insert sample data, and execute queries using the indexing strategy. Incorporate these practices into your .NET Core applications to leverage the full potential of Azure Cosmos DB and deliver an exceptional user experience.

Sunday, April 11, 2021

Azure Series - Cosmos DB : Enhancing Query Performance with Azure Cosmos DB Indexing in .NET Core

 Azure Cosmos DB is a globally distributed, multi-model database service provided by Microsoft that allows developers to build scalable and highly available applications. One of its key features is indexing, which plays a vital role in optimizing query performance. In this article, we will explore how Azure Cosmos DB indexing helps in improving query performance and how it can be leveraged in .NET Core applications. In the next article, I will showcase indexing using .Net Core.

Understanding Azure Cosmos DB Indexing

In a database, indexing is the process of organizing and structuring data to improve query performance. Indexes store a subset of the data's columns in a highly optimized structure, enabling faster data retrieval when performing queries. Azure Cosmos DB offers two types of indexing: Automatic Indexing and Manual Indexing.

1. Automatic Indexing:

With Automatic Indexing, Cosmos DB automatically determines the most suitable indexes for each query based on usage patterns. It continuously monitors the query workload and creates or removes indexes accordingly. This approach simplifies the development process as developers don't have to worry about defining and managing indexes manually. However, it might not be the most efficient choice for complex queries with specific requirements.

2. Manual Indexing:

Manual Indexing allows developers to have more control over the indexing strategy. They can specify which attributes or properties should be indexed based on their application's query patterns. This level of control can lead to more fine-tuned and optimized queries, especially when dealing with complex data models and large datasets.

Optimizing Query Performance with Indexing

Using indexing in Azure Cosmos DB significantly enhances query performance by reducing the time it takes to retrieve data. Here's how indexing achieves this:

  1. Faster Data Retrieval: By using indexes, Cosmos DB can quickly locate and retrieve data based on the specified query predicates. This reduces the amount of time needed to search through the entire dataset and improves query response times.

  2. Efficient Sorting and Filtering: Indexing allows for efficient sorting and filtering of data, which is particularly useful when dealing with large datasets. Queries that involve sorting or filtering on indexed properties benefit from improved performance.

  3. Minimized Resource Consumption: Without indexes, queries may require full scans of the dataset, leading to higher resource consumption and slower execution. Indexing reduces the overall resource usage, resulting in more efficient database operations.

Leveraging Cosmos DB Indexing in .NET Core

To utilize Cosmos DB indexing in .NET Core applications, follow these steps:

  1. Establish a Cosmos DB Connection: Connect your .NET Core application to the Cosmos DB account by using the CosmosClient class from the Cosmos DB SDK.

  2. Configure Indexing Policies: Decide on whether you want to use Automatic Indexing or Manual Indexing. If using manual indexing, define the indexing policy according to the query patterns and requirements of your application.

  3. Execute Queries: Construct and execute queries using the appropriate indexing strategy. For example, if using automatic indexing, ensure that the queried properties are frequently accessed to benefit from automatically created indexes.

  4. Monitor Query Performance: Continuously monitor query performance to identify areas of improvement. Analyze query execution times and adjust indexing strategies as needed to optimize performance.

Azure Cosmos DB indexing is a powerful tool that significantly enhances query performance in .NET Core applications. By strategically using indexes, developers can reduce data retrieval times, minimize resource consumption, and improve overall application responsiveness. Whether opting for automatic or manual indexing, understanding the query patterns and optimizing the indexing strategy will lead to a more efficient and scalable Cosmos DB solution.

Friday, April 09, 2021

Azure Series : Cosmos DB : Key Features and Examples

 Azure Cosmos DB is a globally distributed, multi-model database service offered by Microsoft Azure. It provides developers with a scalable, low-latency, and highly available database solution to build modern, cloud-native applications. In this article, we will dive into some of the main features of Azure Cosmos DB, including indexing, storage, and more, while providing examples to illustrate their importance.

1. Global Distribution:
One of the standout features of Cosmos DB is its ability to replicate data across multiple regions worldwide. This ensures low-latency access for users regardless of their geographic location. For example, let's say you have a mobile app with users in North America, Europe, and Asia. Cosmos DB's global distribution automatically replicates data across datacenters in each region, ensuring that users experience fast response times and uninterrupted service.

2. Multi-Model Support:
Cosmos DB supports various data models, including document, key-value, graph, and column-family. This means you can use Cosmos DB to store different types of data, such as JSON documents, key-value pairs, graph structures, and large column-family data. For instance, consider an e-commerce platform that stores product information (document model), user preferences (key-value model), social network relationships (graph model), and logging data (column-family model). Cosmos DB simplifies data storage and retrieval for all these diverse use cases.

3. Indexing:
Indexing plays a crucial role in optimizing database query performance. Cosmos DB automatically indexes all properties within your data, enabling efficient search and retrieval operations. For example, let's consider a real-time analytics application that tracks user interactions. By indexing specific properties like the user's location or behavior, you can quickly analyze and visualize trends, enhancing the user experience.

4. Automatic Scaling:
Cosmos DB offers elastic scalability, allowing your database to handle varying workloads seamlessly. With its autoscaling feature, you can define throughput limits, and Cosmos DB will automatically adjust resources based on demand. For example, during peak hours, an e-commerce website may experience a surge in traffic. Cosmos DB's automatic scaling ensures that the database can handle the increased load without manual intervention.

5. Consistency Levels:
Cosmos DB offers different consistency levels to meet the requirements of various applications. You can choose from five levels, ranging from strong consistency to eventual consistency. For instance, in a banking application, strong consistency ensures that a user's balance is always up-to-date, while eventual consistency might be acceptable for a social media platform where minor data inconsistencies for a short time are tolerable.

6. Enterprise-Grade Security:
Cosmos DB incorporates robust security features, including encryption at rest and in transit, role-based access control (RBAC), and virtual network isolation. This ensures that your data remains protected and compliant with industry standards. For instance, a healthcare application storing sensitive patient information can leverage Cosmos DB's security measures to meet stringent regulatory requirements.

7. Analytical Capabilities:
Cosmos DB integrates with Azure Synapse Analytics and Apache Spark for real-time analytics and big data processing. You can perform complex analytical queries on your data without affecting the performance of your production workloads. For example, a marketing team can use Cosmos DB to analyze customer behavior data to tailor targeted campaigns.

Azure Cosmos DB provides a feature-rich and flexible database service that empowers developers to build highly responsive and globally scalable applications. From global distribution and multi-model support to automatic scaling and advanced indexing, Cosmos DB offers a wide range of capabilities that cater to diverse application requirements. Leveraging Cosmos DB's powerful features and examples mentioned in this article, developers can architect data-intensive applications with ease and confidence, while ensuring high availability, low-latency access, and optimal performance for their users worldwide.

Tuesday, March 02, 2021

Azure Series - Understanding Kubernetes Environment Components and Setting Up with Docker high level steps

Kubernetes, often abbreviated as K8s, has become the de facto standard for managing containerized applications in modern software development. Its ability to automate deployment, scaling, and management of containerized workloads makes it a crucial tool for developers and operations teams alike. In this article, we'll explore the main components of a Kubernetes environment and guide you on how to set up Kubernetes using Docker high-level steps. I will publish another article soon with actual commands to set up Kubernetes using Docker. 

Main Components of a Kubernetes Environment:

1. Master Node:
The Master Node is the control plane of the Kubernetes cluster. It manages and coordinates all the cluster's activities, including scheduling and monitoring containers, maintaining the desired state, and handling API requests. The primary components within the Master Node are:

  • kube-apiserver: Exposes the Kubernetes API and acts as the front-end for the control plane.
  • etcd: A distributed key-value store that stores the cluster's configuration data.
  • kube-scheduler: Responsible for distributing workloads across worker nodes based on resource availability and constraints.
  • kube-controller-manager: Manages various controllers that handle different aspects of the cluster, such as replication, endpoints, and nodes.

2. Worker Nodes:
Worker Nodes are the machines where containers are scheduled and run. Each node must have the following components installed:

  • kubelet: Communicates with the Master Node and ensures containers are running as expected.
  • kube-proxy: Manages network communication between services and pods.
  • Container Runtime: Responsible for running containers, e.g., Docker, containerd, or CRI-O.

3. Pods:
Pods are the smallest deployable units in Kubernetes and encapsulate one or more containers. Containers within a pod share the same network namespace and can communicate with each other using localhost. Pods enable colocation of tightly coupled application components and ensure that they run on the same node.

4. Services:
Services provide a stable endpoint to access a set of pods. They act as an abstraction layer, enabling communication between pods using labels. There are different types of services, such as ClusterIP, NodePort, and LoadBalancer, each serving a specific purpose in managing network traffic.

Setting Up Kubernetes Environment with Docker:

To get started with Kubernetes on Docker, follow these steps:

Step 1: Install Docker:
Make sure you have Docker installed on your machine. Docker allows you to run containers and acts as the container runtime for Kubernetes.

Step 2: Install kubeadm, kubelet, and kubectl:
On your machine, install kubeadm, kubelet, and kubectl - these are the command-line tools to set up and interact with Kubernetes.

Step 3: Initialize Kubernetes Cluster:
Run kubeadm init to initialize the Kubernetes cluster on the Master Node. This command generates a unique token to allow worker nodes to join the cluster.

Step 4: Join Worker Nodes:
On each worker node, run the kubeadm join command with the token obtained from Step 3. This will connect the worker node to the cluster.

Step 5: Deploy Network Plugin:
Choose a network plugin like Flannel, Calico, or Weave, and deploy it to enable networking between pods across different nodes.

Step 6: Deploy Dashboard (Optional):
If you wish to have a graphical user interface for managing the Kubernetes cluster, you can deploy the Kubernetes Dashboard using kubectl.

Conclusion:
Kubernetes provides a powerful platform for managing containerized applications, but setting up a Kubernetes environment from scratch can be a complex task. Using Docker to run Kubernetes on your local machine allows for easier experimentation and development. By understanding the key components of a Kubernetes environment and following the steps outlined in this article, you can start exploring the potential of container orchestration and streamline your application deployment process. Happy Kuberneting!

Thursday, January 14, 2021

Azure Series - An In-Depth Guide to Event Grid and Event Hub

Introduction

Event-driven architectures have become increasingly popular in modern application development. Microsoft Azure offers two key services, Event Grid and Event Hub, to facilitate event-driven communication and processing within cloud-based applications. This article will explore the fundamentals of Event Grid and Event Hub, understand their differences, and provide detailed examples with diagrams to illustrate their functionalities.

  1. Event Grid:

Event Grid is a fully managed, serverless event routing service in Azure. It enables efficient and real-time event processing by connecting events from various Azure services and custom sources to desired endpoints like Azure Functions, Logic Apps, and Webhooks. Event Grid acts as a central event router, ensuring that events are delivered to subscribers securely and reliably.

Key Features of Event Grid:

  • Seamless integration with Azure services and custom topics.
  • Scalable and flexible event routing based on event types and filters.
  • Support for filtering events based on subject, event type, and data content.
  • Built-in retry mechanism for improved reliability.
  • Dead-lettering capability to capture undeliverable events for analysis.

Example Scenario:

Consider an e-commerce application that relies on Azure services like Azure Blob Storage and Azure Functions. Whenever a new product image is uploaded to a specific container in Blob Storage, you want to trigger a function that resizes the image and saves it in another container.

Diagram:

In this scenario, the Blob Storage container acts as the event source, and the Event Grid topic is set up to receive events from the container. The Azure Function is registered as a subscriber to the Event Grid topic and is triggered whenever an image upload event occurs.

  1. Event Hub:

Event Hub is another event ingestion service in Azure designed to handle high-throughput event streams. It is particularly useful for collecting and processing large volumes of telemetry data from various devices and applications. Event Hub can ingest and retain events for a specified period, allowing multiple consumers to process them independently at their own pace.

Key Features of Event Hub:

  • High throughput and low latency event ingestion.
  • Built-in partitioning to allow parallel processing of events.
  • Event retention for a configurable duration.
  • Support for AMQP and HTTP-based protocols for event consumption.
  • Compatibility with Apache Kafka APIs for seamless integration.

Example Scenario:

Imagine an Internet of Things (IoT) application that collects temperature and humidity data from sensors deployed in different locations. You want to stream this data to Azure for real-time monitoring and analytics.

Diagram:





In this case, the IoT sensors act as the event source, and Event Hub is configured to ingest events from the sensors. The data is then processed using Azure Stream Analytics to derive insights and generate real-time alerts based on predefined rules.

Build hybrid solutions that ingest and process edge data locally on your Azure Stack Hub. Send aggregated data to Azure for further processing, visualization, and storage. If appropriate, leverage serverless computing on Azure. 


Conclusion:

Event Grid and Event Hub are powerful event-driven services offered by Microsoft Azure. While Event Grid excels at handling real-time event routing and processing across various Azure services, Event Hub specializes in ingesting and managing high-throughput event streams. By understanding their strengths and differences, developers can choose the correct service based on their application requirements. Implementing event-driven architectures with Event Grid and Event Hub enables developers to build scalable, efficient, and responsive cloud-based applications.

Remember, successful implementation often involves experimenting and adapting these services to suit your unique use cases, allowing you to harness the full potential of event-driven architectures in the Azure ecosystem.

Friday, June 12, 2020

Azure Series - Cosmos DB - Understanding Consistency

Cosmos DB is a distributed NoSQL database offered by Microsoft Azure, designed to handle large-scale applications with global reach. One of the essential features of Cosmos DB is its consistency model. In this article, we'll explore the concept of Cosmos DB consistency in simple terms, highlighting its significance in data availability and performance.

What is Consistency in Cosmos DB?

In the context of Cosmos DB, consistency refers to the level of data synchronization across different replicas of the database in a distributed environment. When multiple copies of data are spread across data centers globally, ensuring consistency becomes crucial to maintain data accuracy and reliability.

Types of Consistency Levels:

Cosmos DB offers five different consistency levels, each providing varying trade-offs between data consistency and performance. Let's explore them in simple terms:

  1. Strong Consistency:

    Strong consistency ensures that all replicas of data are synchronized at all times. When a write operation is performed, all subsequent read requests will return the latest data. While this provides the highest level of data accuracy, it might impact performance due to increased latency for read operations.

  2. Bounded Staleness:

    Bounded staleness guarantees that read operations will return data that is not older than a specified time limit (staleness window). This level offers a balance between strong consistency and performance, allowing some delay in data synchronization but ensuring data is reasonably up-to-date.

  3. Session Consistency:

    Session consistency guarantees that read operations performed within the same session will always return the latest data. It is useful for applications where users interact with the same data repeatedly and expect real-time updates without affecting other users' read requests.

  4. Consistent Prefix:

    Consistent prefix ensures that read operations will return data in the order in which they were written. This consistency level is suitable for applications that rely on chronological data ordering but may tolerate some inconsistency among different data replicas.

  5. Eventual Consistency:

    Eventual consistency allows for temporary inconsistency across replicas, as data might take some time to propagate across the distributed database. This level offers the best performance but can lead to stale data being read during short windows of time.

Choosing the Right Consistency Level:

Selecting the appropriate consistency level depends on your application's requirements. If your application demands real-time, up-to-date data at all times, strong consistency might be suitable. However, if performance is a top priority and eventual consistency is acceptable, you can opt for that.

Conclusion:

Cosmos DB consistency plays a crucial role in ensuring data accuracy and performance for distributed applications. By understanding the various consistency levels and their trade-offs, developers can make informed decisions when designing and deploying their applications on Cosmos DB. Consider your application's needs and user expectations to choose the most appropriate consistency level, striking the right balance between data synchronization and performance.

Thursday, May 28, 2020

The provider for the source IQueryable doesn't implement IAsyncQueryProvider (How to unit test code that uses AutoMapper ProjectTo?)


Whenever we like to develop using test-driven development approach, Unit Testing is always essential. When it comes to .Net Core and .Net Entity Framework and Automapper it little bit different, no matter what unit testing framework we use, we need to mock libraries. Also when you use third party packages such as AutoMapper it becomes more difficult and comes with lot of other issues in Unit Testing. Here is one of the issue with automapper function “ProjectTo” I am discussing now.



In my previous article, I explained how to make mocking Asynchronous database calls in Unit Testing  




“ProjectTo” function of Automapper Issue in Unit Testing:

So far it was good, We made decision to use the AutoMapper to map our database entities to Business entities. As plan of this we changed our existing function to use automapper.



Note: I assume the reader of this article is aware of how AutoMapper works.



From my previous article example, we changed our function to use automapper. We used TrainingTypeDto as our business entity. This business entity is already mapped in AutoMapper Profile. E.g.    CreateMap().ReverseMap();



Here is our modified function: _mapper is instance of Automapper.



public async Task<string> GetTrainingTypeDescription(string code)
        {
                var dto = _mapper.ProjectTo(_dbContext.Set().Where(x => x.TrainingTypeCode.Equals(code)));
                var result = await dto.FirstOrDefaultAsync(cancellationToken);
            if (trainingType != null)
                return trainingType.Descriptions.ToString();

            return string.Empty;
        }



But we had the same error as below which we were getting while making asynchronous DB calls. After deep dive into the issue we found that the issue was with ProjectTo function of automapper.



System.InvalidOperationException: The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.



Possible Reason for failure:

If we want to test this function with in-memory set of data, the test will fail because our ProjectTo function of automapper tries to generate the TrainingTypeDto object which won’t support the interfaces needed to make the asynchronous call. The reason behind this failure is ProjectTo function failed to create the new object which implements the IAsyncQueryProvider interface needed for the entity framework asynchronous extension method.



We already saw how to implement this IAsyncQueryProvider interface. We need to make few changes so that ProjectTo function to return the proper object which can make the help us to mock the asynchronous calls. See the changes are highlighted in Yellow Background in your previously created helping classes.





internal class TestAsyncEnumerable<T> : EnumerableQuery, IAsyncEnumerable, IQueryable
    {
        public TestAsyncEnumerable(IEnumerable enumerable)
            : base(enumerable)
        { }

        public TestAsyncEnumerable(Expression expression)
            : base(expression)
        { }

        public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken)
        {
            return GetEnumerator();
        }

        public IAsyncEnumerator GetEnumerator()
        {
            return new TestAsyncEnumerator(this.AsEnumerable().GetEnumerator());
        }

        IQueryProvider IQueryable.Provider
        {
            get { return new TestAsyncQueryProvider(this); }
        }
    }


internal class TestAsyncEnumerator<T> : IAsyncEnumerator
    {
        private readonly IEnumerator _inner;

        public TestAsyncEnumerator(IEnumerator inner)
        {
            _inner = inner;
        }

        public ValueTask DisposeAsync()
        {
            _inner.Dispose();
            return new ValueTask();
        }

        public T Current => _inner.Current;

        public ValueTask<bool> MoveNextAsync()
        {
            return new ValueTask<bool>(_inner.MoveNext());
        }
    }

internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider
    {
        private readonly IQueryProvider _inner;

        internal TestAsyncQueryProvider(IQueryProvider inner)
        {
            _inner = inner;
        }

        public IQueryable CreateQuery(Expression expression)
        {
            switch (expression)
            {
                case MethodCallExpression m:
                    {
                        var resultType = m.Method.ReturnType; // Should be IQueryable
                        var tElement = resultType.GetGenericArguments()[0];
                        var queryType = typeof(TestAsyncEnumerable<>).MakeGenericType(tElement);
                        return (IQueryable)Activator.CreateInstance(queryType, expression);
                    }
            }

            return new TestAsyncEnumerable(expression);
        }

        public IQueryable CreateQuery<TElement>(Expression expression)
        {
            return new TestAsyncEnumerable(expression);
        }

        public object Execute(Expression expression)
        {
            return _inner.Execute(expression);
        }

        public TResult Execute<TResult>(Expression expression)
        {
            return _inner.Execute(expression);
        }

        public IAsyncEnumerable ExecuteAsync<TResult>(Expression expression)
        {
            return new TestAsyncEnumerable(expression);
        }

        public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
        {
            var expectedResultType = typeof(TResult).GetGenericArguments()[0];
            var executionResult = typeof(IQueryProvider)
                .GetMethod(
                    name: nameof(IQueryProvider.Execute),
                    genericParameterCount: 1,
                    types: new[] { typeof(Expression) })
                ?.MakeGenericMethod(expectedResultType)
                .Invoke(this, new[] { expression });

            return (TResult)typeof(Task).GetMethod(nameof(Task.FromResult))
                ?.MakeGenericMethod(expectedResultType)
                .Invoke(null, new[] { executionResult });
        }
    }





There will be no change in our Helper class which generate our mock data.



public class UnitTestHelper
    {
        public static Mock> GetQueryableMockDbSet<T>(IQueryable testData) where T : class
        {
            var mockSet = new Mock>();

            mockSet.As>()
                .Setup(x => x.GetAsyncEnumerator(default))
                .Returns(new TestAsyncEnumerator(testData.GetEnumerator()));

            mockSet.As>()
                .Setup(x => x.Provider)
                .Returns(new TestAsyncQueryProvider(testData.Provider));

            mockSet.As>()
                .Setup(x => x.Expression)
                .Returns(testData.Expression);

            mockSet.As>()
                .Setup(x => x.ElementType)
                .Returns(testData.ElementType);

            mockSet.As>()
                .Setup(x => x.GetEnumerator())
                .Returns(testData.GetEnumerator());

            mockSet.As>()
                .Setup(x => x.GetEnumerator())
                .Returns(testData.GetEnumerator());

            return mockSet;
        }
    }



 Next Step is to create the data (No change):

private static IQueryable GetTrainingTypes()
        {
            return new List
            {
                new TrainingType()
                {
                    TrainingTypeCode = "Qa",
                    Descriptions = " Quality Assurance Training",
                    Name =  "QA Training"
                },
                new TrainingType()
                {
                    TrainingTypeCode = "Lab",
                    Descriptions = "Laboratory Training.",
                    Name =  "Labs Training."
                }
            }.AsQueryable();
        }



Now that we have the test data and the helper classes needed for that data to be accessed asynchronously by Entity Framework, Lets write our test function.



So given our function GetTrainingTypeDescription(), we want to test it to make sure it works and it’s returning the correct value.



[Fact]
public async void When_querying_for_a_TrainingTypeDescription__returns_Description()
        {
            var context = new Mock();
            var trainingtype = GetTrainingTypes();
            var cancellationToken = new CancellationToken();

            context.SetupGet(c => c.TrainingType)
                .Returns(UnitTestHelper.GetQueryableMockDbSet( trainingtype).Object);

context.SetupSet(c => c.TrainingType)
                .Returns(UnitTestHelper.GetQueryableMockDbSet( trainingtype).Object);

            // Call the function to test
    var typeHandler = new TypeHandler(context.Object);
    var result = await TypeHandler.GetTrainingTypeDescription("Lab");

            Assert.True(result.HasValue);
        }



Now, Run the Test. It will be successfully completed without errors. You can debug and see how it works.