by Contributed | Mar 17, 2024 | Technology
This article is contributed. See the original author and article here.
In a recent support case, our customer faced an intriguing issue where a query execution in a .NET application was unexpectedly canceled during asynchronous operations against Azure SQL Database. This experience highlighted the nuances of handling query cancellations, which could stem from either a CommandTimeout
or a CancellationToken
. Through this concise article, I aim to elucidate these two cancellation scenarios, alongside strategies for managing SQL errors, ensuring connection resilience through retries, and measuring query execution time. The accompanying code serves as a practical guide, demonstrating how to adjust timeouts dynamically in an attempt to successfully complete a query, should it face cancellation due to timeout constraints. This narrative not only shares a real-world scenario but also provides actionable insights for developers looking to fortify their .NET applications interacting with Azure SQL Database.
Introduction:
Understanding and managing query cancellations in asynchronous database operations are critical for maintaining the performance and reliability of .NET applications. This article stems from a real-world support scenario where a customer encountered unexpected query cancellations while interacting with Azure SQL Database. The issue brings to light the importance of distinguishing between cancellations caused by CommandTimeout
and those triggered by CancellationToken
, each requiring a distinct approach to error handling and application logic.
Cancellations: CommandTimeout vs. CancellationToken:
In asynchronous database operations, two primary types of cancellations can occur: one due to the command’s execution time exceeding the CommandTimeout
limit, and the other due to a CancellationToken
being invoked. Understanding the difference is crucial, as each scenario demands specific error handling strategies. A CommandTimeout
cancellation typically indicates that the query is taking longer than expected, possibly due to database performance issues or query complexity. On the other hand, a cancellation triggered by a CancellationToken
may be due to application logic deciding to abort the operation, often in response to user actions or to maintain application responsiveness.
Error Handling and Connection Resilience:
Errors during query execution, such as syntax errors or references to non-existent database objects, necessitate immediate attention and are not suitable for retry logic. The application must distinguish these errors from transient faults, where retry logic with exponential backoff can be beneficial. Moreover, connection resilience is paramount, and implementing a retry mechanism for establishing database connections ensures that transient network issues do not disrupt application functionality.
Measuring Query Execution Time:
Gauging the execution time of queries is instrumental in identifying performance bottlenecks and optimizing database interactions. The example code demonstrates using a Stopwatch
to measure and log the duration of query execution, providing valuable insights for performance tuning.
Adaptive Timeout Strategy:
The code snippet illustrates an adaptive approach to handling query cancellations due to timeouts. By dynamically adjusting the CommandTimeout
and CancellationToken
timeout values upon encountering a timeout-related cancellation, the application attempts to afford the query additional time to complete in subsequent retries, where feasible.
Conclusion:
The intersection of CommandTimeout
, CancellationToken
, error handling, and connection resilience forms the crux of robust database interaction logic in .NET applications. This article, inspired by a real-world support case, sheds light on these critical aspects, offering a pragmatic code example that developers can adapt to enhance the reliability and performance of their applications when working with Azure SQL Database. The nuanced understanding and strategic handling of query cancellations, as discussed, are pivotal in crafting responsive and resilient .NET database applications.
Example C# code:
using System;
using System.Diagnostics;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
namespace CancellationToken
{
class Program
{
private static string ConnectionString = "Server=tcp:servername.database.windows.net,1433;User Id=MyUser;Password=MyPassword;Initial Catalog=MyDB;Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Pooling=true;Max Pool size=100;Min Pool Size=1;ConnectRetryCount=3;ConnectRetryInterval=10;Application Name=ConnTest";
private static string Query = "waitfor delay '00:00:20'";
static async Task Main(string[] args)
{
SqlConnection connection = await EstablishConnectionWithRetriesAsync(3, 2000);
if (connection == null)
{
Console.WriteLine("Failed to establish a database connection.");
return;
}
await ExecuteQueryWithRetriesAsync(connection, 5, 1000, 30000,15);
connection.Close();
}
private static async Task EstablishConnectionWithRetriesAsync(int maxRetries, int initialDelay)
{
SqlConnection connection = null;
int retryDelay = initialDelay;
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
connection = new SqlConnection(ConnectionString);
await connection.OpenAsync();
Console.WriteLine("Connection established successfully.");
return connection;
}
catch (SqlException ex)
{
Console.WriteLine($"Failed to establish connection: {ex.Message}. Attempt {attempt} of {maxRetries}.");
if (attempt == maxRetries)
{
Console.WriteLine("Maximum number of connection attempts reached. The application will terminate.");
return null;
}
Console.WriteLine($"Waiting {retryDelay / 1000} seconds before the next connection attempt...");
await Task.Delay(retryDelay);
retryDelay *= 2;
}
}
return null;
}
private static async Task ExecuteQueryWithRetriesAsync(SqlConnection connection, int maxRetries, int initialDelay, int CancellationTokenTimeout, int CommandSQLTimeout)
{
int retryDelay = initialDelay;
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(CancellationTokenTimeout*attempt); // Set CancellationToken timeout
try
{
using (SqlCommand command = new SqlCommand(Query, connection))
{
command.CommandTimeout = CommandSQLTimeout*attempt;
Stopwatch stopwatch = Stopwatch.StartNew();
await command.ExecuteNonQueryAsync(cts.Token);
stopwatch.Stop();
Console.WriteLine($"Query executed successfully in {stopwatch.ElapsedMilliseconds} milliseconds.");
return;
}
}
catch (TaskCanceledException)
{
Console.WriteLine($"Query execution was canceled by the CancellationToken. Attempt {attempt} of {maxRetries}.");
}
catch (SqlException ex) when (ex.Number == -2)
{
Console.WriteLine($"Query execution was canceled due to CommandTimeout. Attempt {attempt} of {maxRetries}.");
}
catch (SqlException ex) when (ex.Number == 207 || ex.Number == 208 || ex.Number == 2627)
{
Console.WriteLine($"SQL error preventing retries: {ex.Message}");
return;
}
catch (Exception ex)
{
Console.WriteLine($"An exception occurred: {ex.Message}");
return;
}
Console.WriteLine($"Waiting {retryDelay / 1000} seconds before the next query attempt...");
await Task.Delay(retryDelay);
retryDelay *= 2;
}
}
}
}
}
Tests and Results:
In the course of addressing the query cancellation issue, we conducted a series of tests to understand the behavior under different scenarios and the corresponding exceptions thrown by the .NET application. Here are the findings:
Cancellation Prior to Query Execution:
- Scenario: The cancellation occurs before the query gets a chance to execute, potentially due to reasons such as application overload or a preemptive cancellation policy.
- Exception Thrown:
TaskCanceledException
- Internal Error Message: “A task was canceled.”
- Explanation: This exception is thrown when the operation is canceled through a
CancellationToken
, indicating that the asynchronous task was canceled before it could begin executing the SQL command. It reflects the application’s decision to abort the operation, often to maintain responsiveness or manage workload.
Cancellation Due to CommandTimeout:
- Scenario: The cancellation is triggered by reaching the
CommandTimeout
of SqlCommand
, indicating that the query’s execution duration exceeded the specified timeout limit.
- Exception Thrown:
SqlException
with an error number of -2
- Internal Error Message: “Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.”
- Explanation: This exception occurs when the query execution time surpasses the
CommandTimeout
value, prompting SQL Server to halt the operation. It suggests that the query may be too complex, the server is under heavy load, or there are network latency issues.
Cancellation Before CommandTimeout is Reached:
- Scenario: The cancellation happens before the
CommandTimeout
duration is met, not due to the CommandTimeout
setting but possibly due to an explicit cancellation request or an unforeseen severe error during execution.
- Exception Thrown: General
Exception
(or a more specific exception depending on the context)
- Internal Error Message: “A severe error occurred on the current command. The results, if any, should be discarded.rnOperation cancelled by user.”
- Explanation: This exception indicates an abrupt termination of the command, potentially due to an external cancellation signal or a critical error that necessitates aborting the command. Unlike the
TaskCanceledException
, this may not always originate from a CancellationToken
and can indicate more severe issues with the command or the connection.
by Contributed | Mar 15, 2024 | Technology
This article is contributed. See the original author and article here.
Azure Cognitive Search & OpenAI Output can be effectively restricted with the help of Azure Entra Security Groups. With Azure Entra Security Groups, organizations can limit access to an Azure search instance or an OpenAI Output instance based on group membership of the user. This ensures that users only have access to the data within the scope of their job responsibilities. Azure Entra Security Groups also provide advanced authentication and authorization services for Azure services, offering additional layers of security for organizations to protect their data.
Azure OpenAI service is being used to create more interactive & intelligent chatbots. A key use case is being able to have the OpenAI service respond to user requests using your own data.
Why filter search results from Azure Cognitive Search
Cognitive Search is a search engine that catalogues all the documents, databases, etc. you provide it. However, there may be situations where you want an index of large amounts of data, but you don’t want every user in healthcare organization to have access to everything.
- Protected Health Information (PHI) data
- HR data
- Classified data
For these situations, you need to adjust the search results based on the user’s identity (The medical professionals, such as doctors, nurses, and other health care workers should have access to PHI data, while other people who are not involved or not authorized should not see it).
With security filters, Azure Cognitive Search supports this use case. When you get search results, security filters let you give extra information to restrict results to only data the user can access.
There are three steps required to implement security filtering
- Create an index that includes a field for security filtering (such as Azure Entra security group IDs)
- Include which Azure Entra security group IDs are allowed to see the data on initial index of each document
- Include the list of Azure Entra security group IDs that the user is a part of so the security filtering can be applied on each query
Create an index that includes a field for security filtering
A security filtering field is required when you create a Cognitive Search index. This field should be filterable and not retrievable.
Example REST API call
POST https://[search service].search.windows.net/indexes/securedfiles/docs/index?api-version=2023-10-01-preview
{
"name": "securedfiles",
"fields": [
{"name": "file_id", "type": "Edm.String", "key": true, "searchable": false },
{"name": "file_name", "type": "Edm.String", "searchable": true },
...
{"name": "group_ids", "type": "Collection(Edm.String)", "filterable": true, "retrievable": false }
]
}
Example C#
var index = new SearchIndex(options.SearchIndexName)
{
Fields =
{
new SimpleField("file_id", SearchFieldDataType.String) { IsKey = true, ... },
new SimpleField("file_name", SearchFieldDataType.String) { ... },
...
new SimpleField("group_ids", SearchFieldDataType.Collection(SearchFieldDataType.String))
{ IsFilterable = true, IsHidden = true },
},
...
};
await indexClient.CreateIndexAsync(index);
Include which Azure Entra security group IDs are allowed to see the data on initial index of each document
Each time a new document is uploaded & indexed, you need to include the list of Azure Entra security group IDs that are allowed to have this document in their search results. These Azure Entra security group IDs are GUIDs.
Example REST API call
{
"value": [
{
"@search.action": "upload",
"file_id": "1",
"file_name": "secured_file_a",
"file_description": "File access is restricted to the medical professionals, such as doctors, nurses",
"group_ids": ["entra_security_group_id1"]
},
{
"@search.action": "upload",
"file_id": "2",
"file_name": "secured_file_b",
"file_description": " File access is restricted to the medical professionals, such as doctors, nurses, and other health care workers.",
"group_ids": ["entra_security_group_id1", " entra_security_group_id2"]
},
{
"@search.action": "upload",
"file_id": "3",
"file_name": "secured_file_c",
"file_description": "File access is restricted to third parties and law enforcements",
"group_ids": ["entra_security_group_id3", " entra_security_group_id5"]
}
]
}
Example C#
var searchClient = await GetSearchClientAsync(options);
var batch = new IndexDocumentsBatch();
foreach (var section in sections)
{
batch.Actions.Add(new IndexDocumentsAction(
IndexActionType.MergeOrUpload,
new SearchDocument
{
["file_id"] = section.Id,
["file_name"] = section.SourceFile,
["group_ids"] = section.GroupIds
}
));
IndexDocumentsResult result = await searchClient.IndexDocumentsAsync(batch);
...
}
Provide the IDs of the Azure Entra security groups that the user belongs to so that each query can have security filtering applied to it.
For every query, add the Azure Entra security group IDs that the user belongs to (that are relevant to this application) to the list. Use an OData query to format this.
Example REST API call
POST https://[service name].search.windows.net/indexes/securedfiles/docs/search?api-version=2023-10-01-preview
Content-Type: application/json
api-key: [admin or query key]
{
"filter":"group_ids/any(g:search.in(g, ' entra_security_group_id1, entra_security_group_id2'))"
}
Example C#
...
var filter = $"group_ids/any(g:search.in(g, '{string.Join(", ", user.Claims.Where(x => x.Type == "groups").Select(x => x.Value))}'))";
}
SearchOptions searchOption = new SearchOptions
{
Filter = filter,
QueryType = SearchQueryType.Semantic,
QueryLanguage = "en-us",
QuerySpeller = "lexicon",
SemanticConfigurationName = "default",
Size = top,
QueryCaption = useSemanticCaptions ? QueryCaptionType.Extractive : QueryCaptionType.None,
};
var searchResultResponse = await searchClient.SearchAsync(query, searchOption, cancellationToken);
My GitHub Reposiotry contains an example implementation (with security filtering using Azure Entra Security groups).
by Contributed | Mar 15, 2024 | Technology
This article is contributed. See the original author and article here.
Recording: As healthcare organizations invested heavily in traditional VDI on-premises solutions are found at a crossroads; continue with complex, costly infrastructure, management overhead or pivot to a future where agility, simplicity, and innovation lead. Windows 365 presents as the steppingstone to revolutionize healthcare experience for windows ecosystems.
This is a virtual webinar event series for healthcare focused on Microsoft Windows 365 Cloud PC Cloud Virtualization Desktop solution (a SaaS product), be sure to follow the full agenda for other sessions:
aka.ms/w365HealthcareVirtualWebinar
#W365HealthcareVirtualWebinar
Our Speakers
We have the pleasure of delivering a selective experience with a broad range of speakers focused on healthcare from (technical, specialist and engineering), and make sure to follow them.
Juan Sifuentes
Jesse Asmond
Sam Tulimat
Generated by Copilot.
Key Topics:
Introduction and agenda: Juan, Jesse and Sam introduced themselves and their roles and gave an overview of the session on Windows 365 and how it differs from traditional VDI.
Windows 365 vs traditional VDI: Juan explained how Windows 365 simplifies and automates the provisioning, management and security of cloud PCs, and how it can reduce complexity and cost compared to traditional VDI.
Windows 365 licensing models and use cases: Juan and Sam described the two licensing models for Windows 365: enterprise and frontline, and how they cater to different user scenarios and needs, such as shift workers, task workers, remote workers, etc.
Independent research and resources: Jesse shared some data and insights from Gartner and Forrester on the desktop as a service market and the business value of Windows 365, and also mentioned the availability of trials and partner assistance for customers.
Windows 365 frontline roadmap: Sam gave a preview of the upcoming features and enhancements for Windows 365 frontline, especially for the task worker scenario, such as faster login and resource sharing.
Video Recording
To see the rest of the post, including resources, visit:
https://aka.ms/w365HealthcareVirtualWebinar
#W365HealthcareVirtualWebinar
We will continue to target more webinars aimed at helping our healthcare customers, if you want to learn more be sure to follow these resources:
Thank you for stopping by; Juan Sifuentes | CETS | Healthcare.
by Contributed | Mar 15, 2024 | Dynamics 365, Microsoft 365, Technology
This article is contributed. See the original author and article here.
Harness the power of streamlined integration with third-party tax solutions through the universal tax rate API, now generally available in Microsoft Dynamics 365 Finance, Supply Chain Management and project management and accounting functionality of Project Operations. This advancement eases the complexities of managing multiple and frequently changed tax rates and rules across diverse tax jurisdictions for businesses worldwide.
Navigating the Challenges of Tax Calculation
The tax calculation functionality of Dynamics 365 offers highly flexible and powerful tax determination and calculation capabilities right out of the box. It allows customers to input and manage tax rates and rules to cover complex tax scenarios across Dynamics 365 Finance and Supply Chain Management applications. In some countries, tax rates and rules are inherently intricate, demanding constant vigilance and updates to comply with constant changes by local tax authorities across multiple jurisdictions. This complexity escalates for businesses operating internationally, necessitating the maintenance of accurate tax rates and rules for each location. Traditionally, this process has had a high potential for errors, requiring extensive manual data management and exposing businesses to risks of non-compliance, penalties, and reputational harm.
Recognizing these challenges, many businesses opt for third-party tax solutions to automate and simplify their tax calculation processes. However, integrating these solutions with Microsoft Dynamics 365 Finance and Supply Chain Management applications could be a complex endeavor, burdened by the need for deep understanding of the ERP systems data models and business logic, along with ongoing maintenance to ensure alignment with release updates.
Empowering Businesses with the Universal Tax Rate API
In response to these challenges, we are releasing the universal tax rate API as a standardized solution facilitating communication between Microsoft Dynamics 365 Finance and Supply Chain Management applications, and third-party tax solution providers. This API offers a consistent, reliable interface for data exchange, eliminating the need for extensive customization and simplifying the integration process.
Benefits of the Universal Tax Rate API
The universal tax rate API drives simplification and efficiency for users of Dynamics 365 Finance and Supply Chain Management applications. By offering integration with third-party tax solutions, this innovative API dispels the complexities traditionally associated with managing tax rates and rules, enabling businesses to focus on growth and scalability. Harnessing the universal tax rate API enhances compliance and operational efficiency, through delivering:
- Simplified Integration: Connect with supported third-party tax solution providers, leveraging their expertise without the need for expensive customizations.
- Standardized Communication: Utilize a predefined set of APIs for various tax operations, including address validation, tax calculation, and transaction posting, all employing the JSON format for efficient data exchange.
- Enhanced Compliance and Efficiency: Keep your tax calculations accurate and up to date, minimizing risks of non-compliance and improving operational efficiency.
- Comprehensive Dynamics 365 coverage: Take advantage of the wide coverage of tax transactions within Dynamics 365 Finance and Supply Chain Management applications, as well as within other Dynamics 365 applications that can be available through the universal tax rate API later.
Utilizing the Universal Tax Rate API
The process of employing the API is straightforward. Upon transaction creation or update, the system identifies taxable transactions configured for external tax calculation. It then prepares and sends a data payload to the chosen tax solution provider via the API. The provider calculates the tax and returns the results, which are then validated and recorded in Dynamics 365 Finance and Supply Chain Management applications for audit and reporting.
Get started today
To begin leveraging this powerful feature, select a compatible third-party tax solution provider that aligns with your business needs from the list on Microsoft Learn. Follow the detailed guide provided in the Connect to an external tax solution provider via the Universal Tax Rate API learning path on Microsoft Learn, ensuring a smooth setup and efficient use of the universal tax rate API in your organization.
Embrace the universal tax rate API to transform your tax calculation process, focusing on compliance, efficiency, and scalability within Microsoft Dynamics 365 Finance and Supply Chain Management applications.
Resources
- Universal tax rate API – Finance | Dynamics 365 | Microsoft Learn
- TechTalk Recoding
- Tax solution provider’s connectors available at general availability (GA):
The post Discover the Advantages of the Universal Tax Rate API for Simplified Tax Calculations in Microsoft Dynamics 365 Finance and Supply Chain Management applications appeared first on Microsoft Dynamics 365 Blog.
Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.
Recent Comments