{"id":2807,"date":"2023-09-08T10:24:31","date_gmt":"2023-09-08T17:24:31","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=2807"},"modified":"2023-09-08T11:52:12","modified_gmt":"2023-09-08T18:52:12","slug":"understanding-the-azure-core-library-for-net","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/understanding-the-azure-core-library-for-net\/","title":{"rendered":"Understanding the Azure Core library for .NET"},"content":{"rendered":"<p>One of the goals of the Azure SDK is to provide a unified developer experience across Azure. That means that basic capabilities\u2014like authenticating with a service or retrieving a value from service\u2014should work the same way, regardless of what Azure service you&#8217;re working with. To achieve this, Azure SDK client libraries use common patterns that you can learn once, and then use with any library. Many of the types used in these common patterns live in a foundational library called Azure Core.<\/p>\n<p>This post gives an introduction to the .NET <code>Azure.Core<\/code> library and some of the most common types in it. We&#8217;ll start with a sample that introduces the standard usage pattern for an Azure SDK client, and show how <code>Azure.Core<\/code> enables consistent use of that pattern across .NET clients. Then, we&#8217;ll give an overview of the library&#8217;s namespaces and how they organize the types that the library holds. Finally, we&#8217;ll go through some of the types you would use when building applications with the Azure SDK.<\/p>\n<p>This article is primarily focused on the .NET <code>Azure.Core<\/code> library, but every Azure SDK language has an Azure Core library that implements similar patterns. The main features of the Azure Core libraries are described in the <a href=\"https:\/\/azure.github.io\/azure-sdk\/general_azurecore.html\">Azure SDK General Guidelines<\/a>, and the guidance regarding how client libraries should use them in each of the SDK languages are linked from there. Language-specific libraries can be found at the following links:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-cpp\/tree\/main\/sdk\/core\/azure-core\">C++ <code>azure-core-cpp<\/code><\/a><\/li>\n<li><a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/azcore\">Go <code>azcore<\/code><\/a><\/li>\n<li><a href=\"https:\/\/search.maven.org\/artifact\/com.azure\/azure-core\">Java <code>azure-core<\/code><\/a><\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/@azure\/core-client\">JavaScript <code>@azure\/core-client<\/code><\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Azure.Core\">.NET <code>Azure.Core<\/code><\/a><\/li>\n<li><a href=\"https:\/\/pypi.org\/project\/azure-core\">Python <code>azure-core<\/code><\/a><\/li>\n<\/ul>\n<p>Other language libraries are also available on our <a href=\"https:\/\/azure.github.io\/azure-sdk\/releases\/latest\/index.html\">Azure SDK Releases<\/a> page.<\/p>\n<h2>The Azure SDK for .NET client pattern<\/h2>\n<p>To get started, let&#8217;s look at the standard usage pattern for a typical Azure SDK for .NET client. This sample uses the <code>Azure.AI.TextAnalytics<\/code> library to analyze the sentiment of some text with the Azure Text Analytics service.<\/p>\n<pre><code class=\"language-csharp\">using Azure.AI.TextAnalytics;\r\nusing Azure.Identity;\r\n\r\nTextAnalyticsClient client = new TextAnalyticsClient(\r\n    new Uri(\"https:\/\/example.com\"), \r\n    new DefaultAzureCredential());\r\n\r\nDocumentSentiment analysis = client.AnalyzeSentiment(\"Today was great!\");\r\n\r\nConsole.WriteLine($\"Text sentiment is {analysis.Sentiment}.\");<\/code><\/pre>\n<p>When you write an application using the Azure SDK for .NET, you start by creating an instance of a <a href=\"https:\/\/azure.github.io\/azure-sdk\/dotnet_introduction.html#dotnet-client\"><em>service client<\/em><\/a>. You then invoke a <a href=\"https:\/\/azure.github.io\/azure-sdk\/dotnet_introduction.html#dotnet-client-methods\"><em>service method<\/em><\/a> on the client to call its corresponding Azure service. The service method returns a <a href=\"https:\/\/azure.github.io\/azure-sdk\/dotnet_introduction.html#dotnet-model-types\"><em>model type<\/em><\/a>, that you can then use in your application. In our example, we simply print the sentiment inferred from the text to the console.<\/p>\n<p>So how does <code>Azure.Core<\/code> support this pattern?<\/p>\n<p>In this example, <code>Azure.Core<\/code> types are used in both the client constructor and the service method. In the client constructor, we pass a <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.identity.defaultazurecredential?view=azure-dotnet\"><code>DefaultAzureCredential<\/code><\/a> that is defined in the <code>Azure.Identity<\/code> library, but it inherits from <code>Azure.Core<\/code>&#8216;s <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.tokencredential?view=azure-dotnet\"><code>TokenCredential<\/code><\/a> type. Many Azure SDK clients take <code>DefaultAzureCredential<\/code> or another subtype of <code>TokenCredential<\/code> to authenticate with the service. The service method <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.ai.textanalytics.textanalyticsclient.analyzesentiment?view=azure-dotnet\"><code>AnalyzeSentiment<\/code><\/a> returns a templated type <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.response-1?view=azure-dotnet\"><code>Response&lt;T&gt;<\/code><\/a> that is also defined in <code>Azure.Core<\/code>. <code>Response&lt;T&gt;<\/code> has an <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.response-1.op_implicit?view=azure-dotnet#azure-response-1-op-implicit(azure-response((-0)\">implicit cast<\/a>)-t) to <code>T<\/code>, which represents the value you retrieve from the service. In this case, our <code>T<\/code> is the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.ai.textanalytics.documentsentiment?view=azure-dotnet\"><code>DocumentSentiment<\/code><\/a> model type.<\/p>\n<p>We&#8217;ll look more closely at these and other <code>Azure.Core<\/code> types in the following sections. But before we do, let&#8217;s talk about how the library is organized and what it&#8217;s doing at a high level.<\/p>\n<h2>What&#8217;s in <code>Azure.Core<\/code>?<\/h2>\n<p>As we mentioned earlier, the goal of <code>Azure.Core<\/code> is to help ensure consistency across Azure SDK libraries. That means it provides types that are used in the common patterns the client libraries implement. Some of these types are used in the client libraries&#8217; public APIs, and some of them are used to implement common behaviors without being visible externally.<\/p>\n<p>At a high level, we think of the library as having two groups of users:<\/p>\n<ol>\n<li>The consumers of our client libraries, who use types like <code>Response&lt;T&gt;<\/code> that appear in clients&#8217; public APIs. Broadly speaking, types for end-user developers can be found in <code>Azure.Core<\/code>&#8216;s <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure?view=azure-dotnet\"><code>Azure<\/code> namespace<\/a>.<\/li>\n<li>The developers who write the client libraries themselves. Types used to implement the SDK clients live primarily in the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core?view=azure-dotnet\"><code>Azure.Core<\/code> namespace<\/a> or one of the specialized namespaces like <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.serialization?view=azure-dotnet\"><code>Azure.Core.Serialization<\/code><\/a>.<\/li>\n<\/ol>\n<p>In general, types that are intended for consumers have simpler APIs and usage patterns. Types in the specialized namespaces may be more complex since they&#8217;re intended for use with more advanced scenarios.<\/p>\n<p>One specialized namespace worth noting is the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.pipeline?view=azure-dotnet\"><code>Azure.Core.Pipeline<\/code> namespace<\/a>. Clients for HTTP-based Azure services use an <a href=\"https:\/\/azure.github.io\/azure-sdk\/general_azurecore.html#the-http-pipeline\">HTTP pipeline<\/a> to exchange messages with the service, and <code>Azure.Core<\/code> implements this pipeline and related types. The pipeline is composed of a sequence of policies that implement functionality common to all libraries, such as authentication, retry-handling logic, logging, and tracing. Requests flow through from the first policy to the transport, and responses travel back through them in the opposite direction. Details of the pipeline architecture are described in Jeffrey Richter&#8217;s article <a href=\"https:\/\/devblogs.microsoft.com\/azure-sdk\/architecture\/\">Inside the Azure SDK Architecture<\/a>, so we won&#8217;t go into many of those details here. Types that implement the pipeline are defined in the <code>Azure.Core.Pipeline<\/code> namespace.<\/p>\n<p>For the rest of this post, we&#8217;ll look more closely at some of the types that appear in Azure SDK clients public APIs.<\/p>\n<h2>Response types<\/h2>\n<p>As mentioned before, Azure SDK clients for HTTP-based services have service methods you can call to invoke an operation on the service. When the service sends back a response, the service method returns it to you as one of the response types defined in the <code>Azure<\/code> namespace. The most common of these types are <code>Response&lt;T&gt;<\/code>, <code>Pageable&lt;T&gt;<\/code>, and <code>Operation&lt;T&gt;<\/code>.<\/p>\n<h3>Response&lt;T&gt;<\/h3>\n<p>Most service methods for operations on HTTP-based services return <code>Response&lt;T&gt;<\/code>, like the <code>AnalyzeSentiment<\/code> method shown at the start of this post. The <code>T<\/code> in <code>Response&lt;T&gt;<\/code> is typically a model type\u2014a strongly typed representation of a resource defined by the service you&#8217;re working with. The model value can be accessed by using the implicit cast to <code>T<\/code>, as shown in the sample, or by using <code>Response&lt;T&gt;<\/code>&#8216;s <code>Value<\/code> property. For example, the earlier sample could be rewritten to access the <code>DocumentSentiment<\/code> model like this:<\/p>\n<pre><code class=\"language-csharp\">Response&lt;DocumentSentiment&gt; response = client.AnalyzeSentiment(\"Today was great!\");\r\nDocumentSentiment analysis = response.Value;<\/code><\/pre>\n<p>The only other member defined on <code>Response&lt;T&gt;<\/code> is the <code>GetRawResponse<\/code> method. Calling <code>GetRawResponse<\/code> returns a <code>Response<\/code> object, which holds many of the raw details of the service&#8217;s HTTP response. <code>Response<\/code> is considered a more advanced type and\u2014since the response&#8217;s payload has been abstracted into the strongly typed model\u2014it shouldn&#8217;t be needed for most common scenarios. This means you as a developer can focus on the application logic that uses the resource, without having to reason about the details of the messaging protocol. If you have a more advanced use case and need access to details that aren&#8217;t exposed on the model type, you can always get to those by calling <code>GetRawResponse<\/code> on <code>Response&lt;T&gt;<\/code>. For example, if you needed to read the HTTP status code that the service returned, you might write:<\/p>\n<pre><code class=\"language-csharp\">Response&lt;DocumentSentiment&gt; response = client.AnalyzeSentiment(\"Today was great!\");\r\nResponse httpResponse = response.GetRawResponse();\r\nConsole.WriteLine($\"HTTP status code is {httpResponse.Status}.\");<\/code><\/pre>\n<p>You can also access HTTP headers from <code>Response<\/code>. For example, if you needed more information about the response message&#8217;s content, you might write:<\/p>\n<pre><code class=\"language-csharp\">Response&lt;DocumentSentiment&gt; response = client.AnalyzeSentiment(\"Today was great!\");\r\nResponse httpResponse = response.GetRawResponse();\r\nConsole.WriteLine(\"Content-Length is \" + httpResponse.Headers.ContentLength);\r\nConsole.WriteLine(\"Content-Type is \" + httpResponse.Headers.ContentType);<\/code><\/pre>\n<h3>Pageable&lt;T&gt;<\/h3>\n<p>Some service operations let you retrieve a collection of resources held on the service. Many of these service APIs let you <a href=\"https:\/\/github.com\/microsoft\/api-guidelines\/blob\/vNext\/azure\/Guidelines.md#collections-support-server-driven-paging\">request the elements of the collection in separate groups, called pages<\/a>, to prevent the response size from becoming too large. Managing paged requests is relatively complex, and we wanted .NET users to be able to treat these collections like any other .NET collection type. The <code>Pageable&lt;T&gt;<\/code> type lets you do this.<\/p>\n<p>At its simplest, you can take the <code>Pageable&lt;T&gt;<\/code> object returned from a service method that returns a collection, and <code>foreach<\/code> over it to iterate through the items in the collection. For example, to retrieve a collection of <code>ConfigurationSetting<\/code> values from the Azure App Configuration service and print them to the screen, you might write:<\/p>\n<pre><code class=\"language-csharp\">Pageable&lt;ConfigurationSetting&gt; settings = client.GetConfigurationSettings();\r\nforeach (ConfigurationSetting setting in settings)\r\n{\r\n    Console.WriteLine(setting.Value);\r\n}<\/code><\/pre>\n<p>Under the hood, <code>Pageable&lt;T&gt;<\/code> handles all the requests needed to obtain the first page, keep track of the most recent collection item you&#8217;ve seen, and request subsequent pages as needed. As a user, you just see an <code>IEnumerable<\/code> that returns each element of the collection as you iterate through the enumeration.<\/p>\n<p>Further details regarding how to use <code>Pageable&lt;T&gt;<\/code> and its <code>async<\/code> counterpart <code>AsyncPageable&lt;T&gt;<\/code> can be found in the article <a href=\"https:\/\/learn.microsoft.com\/dotnet\/azure\/sdk\/pagination\">Pagination with the Azure SDK for .NET<\/a>.<\/p>\n<h3>Operation&lt;T&gt;<\/h3>\n<p>Some service operations take a long time to process, so the service isn&#8217;t able to return a response immediately. Azure services use <a href=\"https:\/\/github.com\/microsoft\/api-guidelines\/blob\/vNext\/azure\/Guidelines.md#long-running-operations--jobs\">long-running operations (LROs)<\/a> to model these &#8220;service asynchronous&#8221; operations. Like managing paged requests, handling the sequence of calls needed to start an LRO, poll for updates, and then retrieve the result once the operation has completed can require writing complex code. The <code>Operation&lt;T&gt;<\/code> type is designed to make handling LROs a little easier.<\/p>\n<p>The following example shows how <code>Operation&lt;T&gt;<\/code> is used when you search for addresses with the Azure Maps client.<\/p>\n<pre><code class=\"language-csharp\">List&lt;SearchAddressQuery&gt; queries = new List&lt;SearchAddressQuery&gt;\r\n{\r\n    new SearchAddressQuery(\"One Microsoft Way, Redmond, WA 98052\"),\r\n    new SearchAddressQuery(\"15010 NE 36th St, Redmond, WA 98052\")\r\n};\r\n\r\nSearchAddressBatchOperation operation = client.SearchAddressBatch(WaitUntil.Started, queries);\r\nResponse&lt;SearchAddressBatchResult&gt; result = operation.WaitForCompletion();<\/code><\/pre>\n<p>In this example, the <code>SearchAddressBatch<\/code> method returns a <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.maps.search.searchaddressbatchoperation\"><code>SearchAddressBatchOperation<\/code><\/a> object, which inherits from <code>Operation&lt;T&gt;<\/code>. The <code>T<\/code> in this example is a <code>SearchAddressBatchResult<\/code>, and this is the model type that&#8217;s returned when the operation completes. Calling <code>SearchAddressBatch<\/code> sends a message to the service telling it to begin the LRO. After that, the <code>Operation&lt;T&gt;<\/code> type internally polls the service to find out whether the service has finished computing the result. When the operation has completed, <code>Operation&lt;T&gt;<\/code> does the work to collect the output resource from the appropriate service endpoint and make it available on the client.<\/p>\n<p>As a developer working with <code>Operation&lt;T&gt;<\/code>, you obtain the output value of the operation as a <code>Response&lt;T&gt;<\/code> from the <code>WaitForCompletion<\/code> method, or from its <code>async<\/code> counterpart, <code>WaitForCompletionAsync<\/code>. Once the operation has successfully completed, you can also retrieve the result object from the operation&#8217;s <code>Value<\/code> property, which is similar to the <code>Value<\/code> property on <code>Response&lt;T&gt;<\/code>.<\/p>\n<p>Service methods that start an LRO on the service are named the same way as other service methods\u2014with the name of the operation. In our example, the service method is called <code>SearchAddressBatch<\/code>. You can change how the control flow returns from the service method by passing a <code>WaitUntil<\/code> enum value. If you pass <code>WaitUntil.Started<\/code>, the method will return after the first message is sent to the service telling it to start the operation. If you pass <code>WaitUntil.Completed<\/code>, the method returns when the operation completes on the service and the result is available. For example, we could rewrite the previous example without the call to <code>WaitForCompletion<\/code> by doing the following:<\/p>\n<pre><code class=\"language-csharp\">SearchAddressBatchOperation operation = client.SearchAddressBatch(WaitUntil.Completed, queries);\r\nResponse&lt;SearchAddressBatchResult&gt; result = operation.Value;<\/code><\/pre>\n<p>More details of the <code>Operation&lt;T&gt;<\/code> API can be found in the documentation for the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.operation-1?view=azure-dotnet\"><code>Operation&lt;T&gt;<\/code> class<\/a>.<\/p>\n<h2>Error types<\/h2>\n<p>Sometimes a service needs to notify you of an error, either because of a problem with the input it received or because of a problem on the service side. In .NET, when an error occurs, we <a href=\"https:\/\/learn.microsoft.com\/dotnet\/standard\/design-guidelines\/exception-throwing\">throw an exception<\/a>. Today in <code>Azure.Core<\/code>, we have only one exception type to indicate that a service request failed, and that is <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.requestfailedexception?view=azure-dotnet\"><code>RequestFailedException<\/code><\/a>.<\/p>\n<p>Like other common types appearing in our public APIs, <code>RequestFailedException<\/code> lives in the <code>Azure<\/code> namespace. A few of the details of the error response are available as properties on the exception, including the response status code and the <a href=\"https:\/\/github.com\/microsoft\/api-guidelines\/blob\/vNext\/azure\/Guidelines.md#handling-errors\">Azure-standard error code<\/a>. Beyond that, the client parses details from the error message returned by the service and makes them available in the exception&#8217;s <code>Message<\/code> property. If details of the HTTP response are needed programmatically at runtime, they can be accessed from the <code>Response<\/code> returned by calling the exception&#8217;s <code>GetRawResponse<\/code> method, the same way you access these from <code>Response&lt;T&gt;<\/code>.<\/p>\n<p>This makes the code you write to handle service errors work the same way as exception handling code in any .NET application. For example, to request a secret from Azure Key Vault, you might write:<\/p>\n<pre><code class=\"language-csharp\">try\r\n{\r\n    KeyVaultSecret secret = client.GetSecret(\"NonexistentSecret\");\r\n}\r\ncatch (RequestFailedException e) when (e.Status == 404)\r\n{\r\n    Console.WriteLine(\"ErrorCode \" + e.ErrorCode);\r\n}<\/code><\/pre>\n<p>More details of the <code>RequestFailedException<\/code> API can be found in the documentation for the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.requestfailedexception?view=azure-dotnet\"><code>RequestFailedException<\/code> class<\/a>.<\/p>\n<h2>Client configuration<\/h2>\n<p>So far, we&#8217;ve covered some of the most common types in <code>Azure.Core<\/code>, types in the <code>Azure<\/code> namespace that you could expect to see in any application built using the Azure SDK. The last type we&#8217;ll cover in this post is in the <code>Azure.Core<\/code> namespace, and as you might expect from that, enables more advanced scenarios.<\/p>\n<p>Most of the time, you construct an Azure SDK client by passing the service endpoint and authentication details as we showed in the first example in this post. Sometimes, however, you might need to do something specialized, like work with a specific version of a service, or log the content of HTTP messages sent and received by the client. To do this, you need to pass special configuration options to the client using its <code>ClientOptions<\/code> type.<\/p>\n<p>The following example shows how to create an instance of an Azure Key Vault <code>SecretClient<\/code> that logs the content of request and response messages:<\/p>\n<pre><code class=\"language-csharp\">SecretClientOptions options = new SecretClientOptions()\r\n{\r\n    Diagnostics =\r\n    {\r\n        IsLoggingContentEnabled = true\r\n    }\r\n};\r\n\r\nSecretClient client = new SecretClient(Uri(\"https:\/\/example.com\"), new DefaultAzureCredential(), options);<\/code><\/pre>\n<p>Notice that we created an instance of <code>SecretClientOptions<\/code> and set its <code>DiagnosticOptions<\/code> property <code>IsLoggingContentEnabled<\/code> to <code>true<\/code>. Every Azure SDK for .NET client constructor for an HTTP-based Azure service has an overload that <a href=\"https:\/\/azure.github.io\/azure-sdk\/dotnet_introduction.html#dotnet-client-constructor-overloads\">takes a subtype of <code>ClientOptions<\/code><\/a>. For the Key Vault <code>SecretClient<\/code>, the client options type is called <code>SecretClientOptions<\/code>. Every client-specific options type inherits from the <code>ClientOptions<\/code> type in <code>Azure.Core<\/code>. Some client options types add configuration options specific to the service, but deriving from <code>Azure.Core<\/code>&#8216;s <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.clientoptions?view=azure-dotnet\"><code>ClientOptions<\/code><\/a> type means they all implement the same core set of functionality.<\/p>\n<p>The set of things you can configure using <code>ClientOptions<\/code> fall into four main buckets:<\/p>\n<ul>\n<li>Diagnostics<\/li>\n<li>Retries<\/li>\n<li>The HTTP pipeline<\/li>\n<li>The pipeline transport<\/li>\n<\/ul>\n<p>The configurable options for diagnostics are defined on the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.diagnosticsoptions?view=azure-dotnet\"><code>DiagnosticOptions<\/code><\/a> type, and primarily control client logging and distributed tracing. How the client retries HTTP requests can be configured using the client options <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.retryoptions?view=azure-dotnet\"><code>RetryOptions<\/code><\/a>, which let you configure the pipeline&#8217;s default retry policy, and change values like the time between retries and the maximum number of retries to send. Alternatively, you can take complete control of how retries are sent by replacing the default retry policy with your own <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.clientoptions.retrypolicy?view=azure-dotnet\"><code>RetryPolicy<\/code><\/a> implementation.<\/p>\n<p>If you need to make changes to the client&#8217;s HTTP pipeline, <code>ClientOptions<\/code> lets you insert your own policy implementations into the pipeline using the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.clientoptions.addpolicy?view=azure-dotnet\"><code>AddPolicy<\/code><\/a> method. And at the lowest level, you can replace the pipeline&#8217;s <code>HttpPipelineTransport<\/code> with your own implementation using the client options <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/azure.core.clientoptions.transport?view=azure-dotnet\"><code>Transport<\/code><\/a> property. To succeed at reconfiguring the client pipeline requires a good knowledge of types in the <code>Azure.Core.Pipeline<\/code> namespace, and is a topic for a later blog post about <code>Azure.Core<\/code>.<\/p>\n<h2>What else?<\/h2>\n<p>We hope this overview of the <code>Azure.Core<\/code> library helps explain a little about the library and the types it contains, as well as patterns you&#8217;ll see across all our Azure SDK clients. We&#8217;re always looking for ways to make our products great for your specific needs, so leave suggestions and feedback in our <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/issues\/new\/choose\">GitHub repo<\/a>. If there are topics you&#8217;d like to dive into in more depth in a later blog post on <code>Azure.Core<\/code>, let us know by posting in the comments, or leaving feedback for us on GitHub. We look forward to hearing from you about your experiences, and even more, to working with you to improve the Azure SDK!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn about the Azure Core library and how it enables consistent usage patterns across the Azure SDK.<\/p>\n","protected":false},"author":41096,"featured_media":2816,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[701,734,706,703,920,161],"class_list":["post-2807","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-net","tag-azure","tag-azuresdk","tag-clientlibraries","tag-core","tag-dotnet"],"acf":[],"blog_post_summary":"<p>Learn about the Azure Core library and how it enables consistent usage patterns across the Azure SDK.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2807","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/41096"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=2807"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2807\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/2816"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=2807"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=2807"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=2807"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}