diff --git a/README.md b/README.md index a1e86dac78c16..afab88c7adcf0 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,25 @@ This repository contains the conceptual documentation for .NET. The [.NET documentation site](https://learn.microsoft.com/dotnet) is built from multiple repositories in addition to this one: +- [ASP.NET Core](https://github.com/dotnet/AspNetCore.Docs) - [.NET Aspire](https://github.com/dotnet/docs-aspire) - [.NET Desktop workloads](https://github.com/dotnet/docs-desktop) -- [API reference](https://github.com/dotnet/dotnet-api-docs) -- [C# Language design](https://github.com/dotnet/csharplang) +- [.NET MAUI](https://github.com/dotnet/docs-maui) +- [Entity Framework 6/Core](https://github.com/dotnet/EntityFramework.Docs) +- [Community toolkit](https://github.com/MicrosoftDocs/communitytoolkit) + +API reference documentation is published from the following repositories. The following reference API repositories are public. Only some accept issues and pull requests, although some folders in `dotnet-api-docs` use the product repository as the source of truth. Others are pass-through repositories because API reference is generated directly from the `///` in the product source. + +- [.NET API reference](https://github.com/dotnet/dotnet-api-docs) +- [.NET MAUI API reference](https://github.com/dotnet/maui-api-docs) +- [Android API reference](https://github.com/dotnet/android-api-docs) +- [Entity Framework 6/Core API reference](https://github.com/dotnet/EntityFramework.ApiDocs) +- [Roslyn API reference](https://github.com/dotnet/roslyn-api-docs) +- [Community toolkit API reference](https://github.com/MicrosoftDocs/community-toolkit-api-ref-dotnet) + +The C# language specification documentation comes from the following two repositories: + +- [C# language design](https://github.com/dotnet/csharplang) - [C# specification - draft](https://github.com/dotnet/csharpstandard) Our team's tasks are tracked in our [project boards](https://github.com/dotnet/docs/projects?query=is%3Aopen). You'll see monthly sprint projects, along with long-running projects for major documentation updates. The projects contain documentation issues across the repositories that build .NET docs. Issues are tracked in the relevant repositories. We have a large community using these resources. We make our best effort to respond to issues in a timely fashion. To create a new issue, click the "Open a documentation issue" button at the bottom of any of our published docs, or [choose one of the available templates](https://github.com/dotnet/docs/issues/new/choose). The control at the bottom of each article automatically routes you to the correct repo and fills in some relevant information based on the article. diff --git a/docs/ai/index.yml b/docs/ai/index.yml index 5f9ce2e547720..0c476af7dbd5a 100644 --- a/docs/ai/index.yml +++ b/docs/ai/index.yml @@ -79,6 +79,8 @@ landingContent: url: get-started-app-chat-template.md - text: Implement RAG using vector search url: tutorials/tutorial-ai-vector-search.md + - text: Evaluate a model's response + url: tutorials/evaluate-with-reporting.md # Card (Optional; Remove if not applicable.) - title: Training diff --git a/docs/ai/quickstarts/build-vector-search-app.md b/docs/ai/quickstarts/build-vector-search-app.md index 9959a14b4b192..0f848e2f70083 100644 --- a/docs/ai/quickstarts/build-vector-search-app.md +++ b/docs/ai/quickstarts/build-vector-search-app.md @@ -46,12 +46,12 @@ The abstractions in `Microsoft.Extensions.VectorData.Abstractions` provide libra ## Create the app -Complete the following steps to create a .NET console app that can accomplish the following: +Complete the following steps to create a .NET console app that can: - Create and populate a vector store by generating embeddings for a data set - Generate an embedding for the user prompt - Query the vector store using the user prompt embedding -- Displays the relevant results from the vector search +- Display the relevant results from the vector search 1. In an empty directory on your computer, use the `dotnet new` command to create a new console app: @@ -85,7 +85,7 @@ Complete the following steps to create a .NET console app that can accomplish th - [`Azure.AI.OpenAI`](https://www.nuget.org/packages/Azure.AI.OpenAI) is the official package for using OpenAI's .NET library with the Azure OpenAI Service. - [`Microsoft.SemanticKernel.Connectors.InMemory`](https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.InMemory) provides an in-memory vector store class to hold queryable vector data records. - [`Microsoft.Extensions.VectorData.Abstractions`](https://www.nuget.org/packages/Microsoft.Extensions.AI) enables Create-Read-Update-Delete (CRUD) and search operations on vector stores. - - [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) provides implementation of key-value pair based configuration. + - [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) provides an implementation of key-value pair—based configuration. - [`Microsoft.Extensions.Configuration.UserSecrets`](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) is a user secrets configuration provider implementation for `Microsoft.Extensions.Configuration`. :::zone-end @@ -105,7 +105,7 @@ Complete the following steps to create a .NET console app that can accomplish th - [`Microsoft.Extensions.AI.OpenAI`](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI) provides AI abstractions for OpenAI-compatible models or endpoints. This library also includes the official [`OpenAI`](https://www.nuget.org/packages/OpenAI) library for the OpenAI service API as a dependency. - [`Microsoft.SemanticKernel.Connectors.InMemory`](https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.InMemory) provides an in-memory vector store class to hold queryable vector data records. - [`Microsoft.Extensions.VectorData.Abstractions`](https://www.nuget.org/packages/Microsoft.Extensions.AI) enables Create-Read-Update-Delete (CRUD) and search operations on vector stores. - - [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) provides implementation of key-value pair based configuration. + - [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) provides an implementation of key-value pair—based configuration. - [`Microsoft.Extensions.Configuration.UserSecrets`](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) is a user secrets configuration provider implementation for `Microsoft.Extensions.Configuration`. :::zone-end diff --git a/docs/ai/quickstarts/create-assistant.md b/docs/ai/quickstarts/create-assistant.md index e9a60417009b6..a91f448eaad4f 100644 --- a/docs/ai/quickstarts/create-assistant.md +++ b/docs/ai/quickstarts/create-assistant.md @@ -39,14 +39,14 @@ In this quickstart, you'll learn how to create a minimal AI assistant using the ## Core components of AI assistants -AI assistants are based around conversational threads with a user. The user sends prompts to the assistant on a conversation thread, which directs the assistant to complete tasks using the tools it has available. Assistants can process and analyze data, make decisions, and interact with users or other systems to achieve specific goals. Most assistants include the following components: +AI assistants are based around conversational threads with a user. The user sends prompts to the assistant on a conversation thread, which direct the assistant to complete tasks using the tools it has available. Assistants can process and analyze data, make decisions, and interact with users or other systems to achieve specific goals. Most assistants include the following components: | **Component** | **Description** | -|---|---| +|---------------|-----------------| | **Assistant** | The core AI client and logic that uses Azure OpenAI models, manages conversation threads, and utilizes configured tools. | -| **Thread** | A conversation session between an assistant and a user. Threads store messages and automatically handle truncation to fit content into a model's context. | -| **Message** | A message created by an assistant or a user. Messages can include text, images, and other files. Messages are stored as a list on the thread. | -| **Run** | Activation of an assistant to begin running based on the contents of the thread. The assistant uses its configuration and the thread's messages to perform tasks by calling models and tools. As part of a run, the assistant appends messages to the thread. | +| **Thread** | A conversation session between an assistant and a user. Threads store messages and automatically handle truncation to fit content into a model's context. | +| **Message** | A message created by an assistant or a user. Messages can include text, images, and other files. Messages are stored as a list on the thread. | +| **Run** | Activation of an assistant to begin running based on the contents of the thread. The assistant uses its configuration and the thread's messages to perform tasks by calling models and tools. As part of a run, the assistant appends messages to the thread. | | **Run steps** | A detailed list of steps the assistant took as part of a run. An assistant can call tools or create messages during its run. Examining run steps allows you to understand how the assistant is getting to its final results. | Assistants can also be configured to use multiple tools in parallel to complete tasks, including the following: diff --git a/docs/ai/quickstarts/evaluate-ai-response.md b/docs/ai/quickstarts/evaluate-ai-response.md index 730be6dfce6c6..48a59c7dbe137 100644 --- a/docs/ai/quickstarts/evaluate-ai-response.md +++ b/docs/ai/quickstarts/evaluate-ai-response.md @@ -10,6 +10,9 @@ ms.custom: devx-track-dotnet, devx-track-dotnet-ai In this quickstart, you create an MSTest app to evaluate the chat response of a model. The test app uses the [Microsoft.Extensions.AI.Evaluation](https://www.nuget.org/packages/Microsoft.Extensions.AI.Evaluation) libraries. +> [!NOTE] +> This quickstart demonstrates the simplest usage of the evaluation API. Notably, it doesn't demonstrate use of the [response caching](../conceptual/evaluation-libraries.md#cached-responses) and [reporting](../conceptual/evaluation-libraries.md#reporting) functionality, which are important if you're authoring unit tests that run as part of an "offline" evaluation pipeline. The scenario shown in this quickstart is suitable in use cases such as "online" evaluation of AI responses within production code and logging scores to telemetry, where caching and reporting aren't relevant. For a tutorial that demonstrates the caching and reporting functionality, see [Tutorial: Evaluate a model's response with response caching and reporting](../tutorials/evaluate-with-reporting.md) + ## Prerequisites - [Install .NET 8.0](https://dotnet.microsoft.com/download) or a later version @@ -86,7 +89,7 @@ Complete the following steps to create an MSTest project that connects to your l :::code language="csharp" source="./snippets/evaluate-ai-responses/MyTests.cs" id="Initialize"::: - This methods accomplishes the following tasks: + This method accomplishes the following tasks: - Sets up the . - Sets the , including the and the . diff --git a/docs/ai/quickstarts/use-function-calling.md b/docs/ai/quickstarts/use-function-calling.md index c3586124bc4ec..060630ca79cdf 100644 --- a/docs/ai/quickstarts/use-function-calling.md +++ b/docs/ai/quickstarts/use-function-calling.md @@ -107,7 +107,7 @@ Complete the following steps to create a .NET console app to connect to an AI mo The app uses the [`Microsoft.Extensions.AI`](https://www.nuget.org/packages/Microsoft.Extensions.AI/) package to send and receive requests to the AI model. -1. In the **Program.cs** file, add the following code to connect and authenticate to the AI model. The `ChatClient` is also configured to use function invocation, which allows .NET functions in your code to be called by the AI model. +1. In the **Program.cs** file, add the following code to connect and authenticate to the AI model. The `ChatClient` is also configured to use function invocation, which allows the AI model to call .NET functions in your code. :::zone target="docs" pivot="azure-openai" @@ -124,7 +124,7 @@ The app uses the [`Microsoft.Extensions.AI`](https://www.nuget.org/packages/Micr :::zone-end -1. Create a new `ChatOptions` object that contains an inline function the AI model can call to get the current weather. The function declaration includes a delegate to run logic and name and description parameters to describe the purpose of the function to the AI model. +1. Create a new `ChatOptions` object that contains an inline function the AI model can call to get the current weather. The function declaration includes a delegate to run logic, and name and description parameters to describe the purpose of the function to the AI model. :::code language="csharp" source="snippets/function-calling/openai/program.cs" range="16-26"::: @@ -138,7 +138,7 @@ The app uses the [`Microsoft.Extensions.AI`](https://www.nuget.org/packages/Micr dotnet run ``` - The app prints the completion response from the AI model that includes data provided by the .NET function. The AI model understood the registered function was available and called it automatically to generate a proper response. + The app prints the completion response from the AI model, which includes data provided by the .NET function. The AI model understood that the registered function was available and called it automatically to generate a proper response. :::zone target="docs" pivot="azure-openai" diff --git a/docs/ai/toc.yml b/docs/ai/toc.yml index 8070112ea2eea..2cabaa1a073ea 100644 --- a/docs/ai/toc.yml +++ b/docs/ai/toc.yml @@ -79,6 +79,8 @@ items: href: conceptual/evaluation-libraries.md - name: "Quickstart: Evaluate a model's response" href: quickstarts/evaluate-ai-response.md + - name: "Tutorial: Evaluate a response with response caching and reporting" + href: tutorials/evaluate-with-reporting.md - name: "Tutorial: Evaluate LLM prompt completions" href: tutorials/llm-eval.md - name: Resources diff --git a/docs/ai/tutorials/evaluate-with-reporting.md b/docs/ai/tutorials/evaluate-with-reporting.md new file mode 100644 index 0000000000000..d597527ba7150 --- /dev/null +++ b/docs/ai/tutorials/evaluate-with-reporting.md @@ -0,0 +1,174 @@ +--- +title: Tutorial - Evaluate a model's response +description: Create an MSTest app and add a custom evaluator to evaluate the AI chat response of a language model, and learn how to use the caching and reporting features of Microsoft.Extensions.AI.Evaluation. +ms.date: 03/14/2025 +ms.topic: tutorial +ms.custom: devx-track-dotnet-ai +--- + +# Tutorial: Evaluate a model's response with response caching and reporting + +In this tutorial, you create an MSTest app to evaluate the chat response of an OpenAI model. The test app uses the [Microsoft.Extensions.AI.Evaluation](https://www.nuget.org/packages/Microsoft.Extensions.AI.Evaluation) libraries to perform the evaluations, cache the model responses, and create reports. The tutorial uses both a [built-in evaluator](xref:Microsoft.Extensions.AI.Evaluation.Quality.RelevanceTruthAndCompletenessEvaluator) and a custom evaluator. + +## Prerequisites + +- [.NET 8 or a later version](https://dotnet.microsoft.com/download) +- [Visual Studio Code](https://code.visualstudio.com/) (optional) + +## Configure the AI service + +To provision an Azure OpenAI service and model using the Azure portal, complete the steps in the [Create and deploy an Azure OpenAI Service resource](/azure/ai-services/openai/how-to/create-resource?pivots=web-portal) article. In the "Deploy a model" step, select the `gpt-4o` model. + +## Create the test app + +Complete the following steps to create an MSTest project that connects to the `gpt-4o` AI model. + +1. In a terminal window, navigate to the directory where you want to create your app, and create a new MSTest app with the `dotnet new` command: + + ```dotnetcli + dotnet new mstest -o TestAIWithReporting + ``` + +1. Navigate to the `TestAIWithReporting` directory, and add the necessary packages to your app: + + ```dotnetcli + dotnet add package Azure.AI.OpenAI + dotnet add package Azure.Identity + dotnet add package Microsoft.Extensions.AI.Abstractions --prerelease + dotnet add package Microsoft.Extensions.AI.Evaluation --prerelease + dotnet add package Microsoft.Extensions.AI.Evaluation.Quality --prerelease + dotnet add package Microsoft.Extensions.AI.Evaluation.Reporting --prerelease + dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease + dotnet add package Microsoft.Extensions.Configuration + dotnet add package Microsoft.Extensions.Configuration.UserSecrets + ``` + +1. Run the following commands to add [app secrets](/aspnet/core/security/app-secrets) for your Azure OpenAI endpoint, model name, and tenant ID: + + ```bash + dotnet user-secrets init + dotnet user-secrets set AZURE_OPENAI_ENDPOINT + dotnet user-secrets set AZURE_OPENAI_GPT_NAME gpt-4o + dotnet user-secrets set AZURE_TENANT_ID + ``` + + (Depending on your environment, the tenant ID might not be needed. In that case, remove it from the code that instantiates the .) + +1. Open the new app in your editor of choice. + +## Add the test app code + +1. Rename the *Test1.cs* file to *MyTests.cs*, and then open the file and rename the class to `MyTests`. Delete the empty `TestMethod1` method. +1. Add the necessary `using` directives to the top of the file. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="UsingDirectives"::: + +1. Add the property to the class. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="TestContext"::: + +1. Add the `GetAzureOpenAIChatConfiguration` method, which creates the that the evaluator uses to communicate with the model. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="GetChatConfig"::: + +1. Set up the reporting functionality. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="ReportingSetup"::: + + **Scenario name** + + The [scenario name](xref:Microsoft.Extensions.AI.Evaluation.Reporting.ScenarioRun.ScenarioName) is set to the fully qualified name of the current test method. However, you can set it to any string of your choice when you call . Here are some considerations for choosing a scenario name: + + - When using disk-based storage, the scenario name is used as the name of the folder under which the corresponding evaluation results are stored. So it's a good idea to keep the name reasonably short and avoid any characters that aren't allowed in file and directory names. + - By default, the generated evaluation report splits scenario names on `.` so that the results can be displayed in a hierarchical view with appropriate grouping, nesting, and aggregation. This is especially useful in cases where the scenario name is set to the fully qualified name of the corresponding test method, since it allows the results to be grouped by namespaces and class names in the hierarchy. However, you can also take advantage of this feature by including periods (`.`) in your own custom scenario names to create a reporting hierarchy that works best for your scenarios. + + **Execution name** + + The execution name is used to group evaluation results that are part of the same evaluation run (or test run) when the evaluation results are stored. If you don't provide an execution name when creating a , all evaluation runs will use the same default execution name of `Default`. In this case, results from one run will be overwritten by the next and you lose the ability to compare results across different runs. + + This example uses a timestamp as the execution name. If you have more than one test in your project, ensure that results are grouped correctly by using the same execution name in all reporting configurations used across the tests. + + In a more real-world scenario, you might also want to share the same execution name across evaluation tests that live in multiple different assemblies and that are executed in different test processes. In such cases, you could use a script to update an environment variable with an appropriate execution name (such as the current build number assigned by your CI/CD system) before running the tests. Or, if your build system produces monotonically increasing assembly file versions, you could read the from within the test code and use that as the execution name to compare results across different product versions. + + **Reporting configuration** + + A identifies: + + - The set of evaluators that should be invoked for each that's created by calling . + - The LLM endpoint that the evaluators should use (see ). + - How and where the results for the scenario runs should be stored. + - How LLM responses related to the scenario runs should be cached. + - The execution name that should be used when reporting results for the scenario runs. + + This test uses a disk-based reporting configuration. + +1. In a separate file, add the `WordCountEvaluator` class, which is a custom evaluator that implements . + + :::code language="csharp" source="./snippets/evaluate-with-reporting/WordCountEvaluator.cs"::: + + The `WordCountEvaluator` counts the number of words present in the response. Unlike some evaluators, it isn't based on AI. The `EvaluateAsync` method returns an includes a that contains the word count. + + The `EvaluateAsync` method also attaches a default interpretation to the metric. The default interpretation considers the metric to be good (acceptable) if the detected word count is between 6 and 100. Otherwise, the metric is considered failed. This default interpretation can be overridden by the caller, if needed. + +1. Back in `MyTests.cs`, add a method to gather the evaluators to use in the evaluation. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="GetEvaluators"::: + +1. Add a method to add a system prompt , define the [chat options](xref:Microsoft.Extensions.AI.ChatOptions), and ask the model for a response to a given question. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="GetResponse"::: + + The test in this tutorial evaluates the LLM's response to an astronomy question. Since the has response caching enabled, and since the supplied is always fetched from the created using this reporting configuration, the LLM response for the test is cached and reused. The response will be reused until the corresponding cache entry expires (in 14 days by default), or until any request parameter, such as the the LLM endpoint or the question being asked, is changed. + +1. Add a method to validate the response. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="Validate"::: + + > [!TIP] + > The metrics each include a `Reason` property that explains the reasoning for the score. The reason is included in the [generated report](#generate-a-report) and can be viewed by clicking on the information icon on the corresponding metric's card. + +1. Finally, add the [test method](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute) itself. + + :::code language="csharp" source="./snippets/evaluate-with-reporting/MyTests.cs" id="TestMethod"::: + + This test method: + + - Creates the . The use of `await using` ensures that the `ScenarioRun` is correctly disposed and that the results of this evaluation are correctly persisted to the result store. + - Gets the LLM's response to a specific astronomy question. The same that will be used for evaluation is passed to the `GetAstronomyConversationAsync` method in order to get *response caching* for the primary LLM response being evaluated. (In addition, this enables response caching for the LLM turns that the evaluators use to perform their evaluations internally.) With response caching, the LLM response is fetched either: + - Directly from the LLM endpoint in the first run of the current test, or in subsequent runs if the cached entry has expired (14 days, by default). + - From the (disk-based) response cache that was configured in `s_defaultReportingConfiguration` in subsequent runs of the test. + - Runs the evaluators against the response. Like the LLM response, on subsequent runs, the evaluation is fetched from the (disk-based) response cache that was configured in `s_defaultReportingConfiguration`. + - Runs some basic validation on the evaluation result. + + This step is optional and mainly for demonstration purposes. In real-world evaluations, you might not want to validate individual results since the LLM responses and evaluation scores can change over time as your product (and the models used) evolve. You might not want individual evaluation tests to "fail" and block builds in your CI/CD pipelines when this happens. Instead, it might be better to rely on the generated report and track the overall trends for evaluation scores across different scenarios over time (and only fail individual builds when there's a significant drop in evaluation scores across multiple different tests). That said, there is some nuance here and the choice of whether to validate individual results or not can vary depending on the specific use case. + + When the method returns, the `scenarioRun` object is disposed and the evaluation result for the evaluation is stored to the (disk-based) result store that's configured in `s_defaultReportingConfiguration`. + +## Run the test/evaluation + +Run the test using your preferred test workflow, for example, by using the CLI command `dotnet test` or through [Test Explorer](/visualstudio/test/run-unit-tests-with-test-explorer). + +## Generate a report + +1. Install the [Microsoft.Extensions.AI.Evaluation.Console](https://www.nuget.org/packages/Microsoft.Extensions.AI.Evaluation.Console) .NET tool by running the following command from a terminal window (update the version as necessary): + + ```dotnetcli + dotnet tool install --local Microsoft.Extensions.AI.Evaluation.Console --version 9.3.0-preview.1.25164.6 + ``` + +1. Generate a report by running the following command: + + ```dotnetcli + dotnet tool run aieval report --path --output report.html + ``` + +1. Open the `report.html` file. It should look something like this. + + :::image type="content" source="media/evaluation-report.png" alt-text="Screenshot of the evaluation report showing the conversation and metric values."::: + +## Next steps + +- Navigate to the directory where the test results are stored (which is `C:\TestReports`, unless you modified the location when you created the ). In the `results` subdirectory, notice that there's a folder for each test run named with a timestamp (`ExecutionName`). Inside each of those folders is a folder for each scenario name—in this case, just the single test method in the project. That folder contains a JSON file with the all the data including the messages, response, and evaluation result. +- Expand the evaluation. Here are a couple ideas: + - Add an additional custom evaluator, such as [an evaluator that uses AI to determine the measurement system](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/evaluation/Evaluators/MeasurementSystemEvaluator.cs) that's used in the response. + - Add another test method, for example, [a method that evaluates multiple responses](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/reporting/ReportingExamples.Example02_SamplingAndEvaluatingMultipleResponses.cs) from the LLM. Since each response can be different, it's good to sample and evaluate at least a few responses to a question. In this case, you specify an iteration name each time you call . diff --git a/docs/ai/tutorials/media/evaluation-report.png b/docs/ai/tutorials/media/evaluation-report.png new file mode 100644 index 0000000000000..b3efc9b8f05c9 Binary files /dev/null and b/docs/ai/tutorials/media/evaluation-report.png differ diff --git a/docs/ai/tutorials/snippets/evaluate-with-reporting/MyTests.cs b/docs/ai/tutorials/snippets/evaluate-with-reporting/MyTests.cs new file mode 100644 index 0000000000000..01b457ab2f6d5 --- /dev/null +++ b/docs/ai/tutorials/snippets/evaluate-with-reporting/MyTests.cs @@ -0,0 +1,153 @@ +// +using Azure.AI.OpenAI; +using Azure.Identity; +using Microsoft.Extensions.AI.Evaluation; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.AI.Evaluation.Reporting.Storage; +using Microsoft.Extensions.AI.Evaluation.Reporting; +using Microsoft.Extensions.AI.Evaluation.Quality; +// + +namespace TestAIWithReporting; + +[TestClass] +public sealed class MyTests +{ + // + // The value of the TestContext property is populated by MSTest. + public TestContext? TestContext { get; set; } + // + + // + private static ChatConfiguration GetAzureOpenAIChatConfiguration() + { + IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets().Build(); + + string endpoint = config["AZURE_OPENAI_ENDPOINT"]; + string model = config["AZURE_OPENAI_GPT_NAME"]; + string tenantId = config["AZURE_TENANT_ID"]; + + // Get an instance of Microsoft.Extensions.AI's + // interface for the selected LLM endpoint. + AzureOpenAIClient azureClient = + new( + new Uri(endpoint), + new DefaultAzureCredential(new DefaultAzureCredentialOptions() { TenantId = tenantId })); + IChatClient client = azureClient.AsChatClient(modelId: model); + + // Create an instance of + // to communicate with the LLM. + return new ChatConfiguration(client); + } + // + + // + private string ScenarioName => $"{TestContext!.FullyQualifiedTestClassName}.{TestContext.TestName}"; + + private static string ExecutionName => $"{DateTime.Now:yyyyMMddTHHmmss}"; + + private static readonly ReportingConfiguration s_defaultReportingConfiguration = + DiskBasedReportingConfiguration.Create( + storageRootPath: "C:\\TestReports", + evaluators: GetEvaluators(), + chatConfiguration: GetAzureOpenAIChatConfiguration(), + enableResponseCaching: true, + executionName: ExecutionName); + // + + // + private static IEnumerable GetEvaluators() + { + IEvaluator rtcEvaluator = new RelevanceTruthAndCompletenessEvaluator(); + IEvaluator wordCountEvaluator = new WordCountEvaluator(); + + return [rtcEvaluator, wordCountEvaluator]; + } + // + + // + private static async Task<(IList Messages, ChatResponse ModelResponse)> GetAstronomyConversationAsync( + IChatClient chatClient, + string astronomyQuestion) + { + const string SystemPrompt = + """ + You're an AI assistant that can answer questions related to astronomy. + Keep your responses concise and under 100 words. + Use the imperial measurement system for all measurements in your response. + """; + + IList messages = + [ + new ChatMessage(ChatRole.System, SystemPrompt), + new ChatMessage(ChatRole.User, astronomyQuestion) + ]; + + var chatOptions = + new ChatOptions + { + Temperature = 0.0f, + ResponseFormat = ChatResponseFormat.Text + }; + + ChatResponse response = await chatClient.GetResponseAsync(messages, chatOptions); + return (messages, response); + } + // + + // + /// + /// Runs basic validation on the supplied . + /// + private static void Validate(EvaluationResult result) + { + // Retrieve the score for relevance from the . + NumericMetric relevance = + result.Get(RelevanceTruthAndCompletenessEvaluator.RelevanceMetricName); + Assert.IsFalse(relevance.Interpretation!.Failed, relevance.Reason); + Assert.IsTrue(relevance.Interpretation.Rating is EvaluationRating.Good or EvaluationRating.Exceptional); + + // Retrieve the score for truth from the . + NumericMetric truth = result.Get(RelevanceTruthAndCompletenessEvaluator.TruthMetricName); + Assert.IsFalse(truth.Interpretation!.Failed, truth.Reason); + Assert.IsTrue(truth.Interpretation.Rating is EvaluationRating.Good or EvaluationRating.Exceptional); + + // Retrieve the score for completeness from the . + NumericMetric completeness = + result.Get(RelevanceTruthAndCompletenessEvaluator.CompletenessMetricName); + Assert.IsFalse(completeness.Interpretation!.Failed, completeness.Reason); + Assert.IsTrue(completeness.Interpretation.Rating is EvaluationRating.Good or EvaluationRating.Exceptional); + + // Retrieve the word count from the . + NumericMetric wordCount = result.Get(WordCountEvaluator.WordCountMetricName); + Assert.IsFalse(wordCount.Interpretation!.Failed, wordCount.Reason); + Assert.IsTrue(wordCount.Interpretation.Rating is EvaluationRating.Good or EvaluationRating.Exceptional); + Assert.IsFalse(wordCount.ContainsDiagnostics()); + Assert.IsTrue(wordCount.Value > 5 && wordCount.Value <= 100); + } + // + + // + [TestMethod] + public async Task SampleAndEvaluateResponse() + { + // Create a with the scenario name + // set to the fully qualified name of the current test method. + await using ScenarioRun scenarioRun = + await s_defaultReportingConfiguration.CreateScenarioRunAsync(this.ScenarioName); + + // Use the that's included in the + // to get the LLM response. + (IList messages, ChatResponse modelResponse) = await GetAstronomyConversationAsync( + chatClient: scenarioRun.ChatConfiguration!.ChatClient, + astronomyQuestion: "How far is the Moon from the Earth at its closest and furthest points?"); + + // Run the evaluators configured in against the response. + EvaluationResult result = await scenarioRun.EvaluateAsync(messages, modelResponse); + + // Run some basic validation on the evaluation result. + Validate(result); + } + // +} diff --git a/docs/ai/tutorials/snippets/evaluate-with-reporting/TestAIWithReporting.csproj b/docs/ai/tutorials/snippets/evaluate-with-reporting/TestAIWithReporting.csproj new file mode 100644 index 0000000000000..731943523066f --- /dev/null +++ b/docs/ai/tutorials/snippets/evaluate-with-reporting/TestAIWithReporting.csproj @@ -0,0 +1,29 @@ + + + + net9.0 + latest + enable + enable + 07aae6fc-a2ea-407b-b1e1-83d0de270091 + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/ai/tutorials/snippets/evaluate-with-reporting/WordCountEvaluator.cs b/docs/ai/tutorials/snippets/evaluate-with-reporting/WordCountEvaluator.cs new file mode 100644 index 0000000000000..72ab54416c34f --- /dev/null +++ b/docs/ai/tutorials/snippets/evaluate-with-reporting/WordCountEvaluator.cs @@ -0,0 +1,77 @@ +using System.Text.RegularExpressions; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.AI.Evaluation; + +namespace TestAIWithReporting; + +public class WordCountEvaluator : IEvaluator +{ + public const string WordCountMetricName = "Words"; + + public IReadOnlyCollection EvaluationMetricNames => [WordCountMetricName]; + + /// + /// Counts the number of words in the supplied string. + /// + private static int CountWords(string? input) + { + if (string.IsNullOrWhiteSpace(input)) + { + return 0; + } + + MatchCollection matches = Regex.Matches(input, @"\b\w+\b"); + return matches.Count; + } + + /// + /// Provides a default interpretation for the supplied . + /// + private static void Interpret(NumericMetric metric) + { + if (metric.Value is null) + { + metric.Interpretation = + new EvaluationMetricInterpretation( + EvaluationRating.Unknown, + failed: true, + reason: "Failed to calculate word count for the response."); + } + else + { + if (metric.Value <= 100 && metric.Value > 5) + metric.Interpretation = new EvaluationMetricInterpretation( + EvaluationRating.Good, + reason: "The response was between 6 and 100 words."); + else + metric.Interpretation = new EvaluationMetricInterpretation( + EvaluationRating.Unacceptable, + failed: true, + reason: "The response was either too short or greater than 100 words."); + } + } + + public ValueTask EvaluateAsync( + IEnumerable messages, + ChatResponse modelResponse, + ChatConfiguration? chatConfiguration = null, + IEnumerable? additionalContext = null, + CancellationToken cancellationToken = default) + { + // Count the number of words in the supplied . + int wordCount = CountWords(modelResponse.Text); + + string reason = + $"This {WordCountMetricName} metric has a value of {wordCount} because " + + $"the evaluated model response contained {wordCount} words."; + + // Create a with value set to the word count. + // Include a reason that explains the score. + var metric = new NumericMetric(WordCountMetricName, value: wordCount, reason); + + // Attach a default for the metric. + Interpret(metric); + + return new ValueTask(new EvaluationResult(metric)); + } +} diff --git a/docs/core/install/windows.md b/docs/core/install/windows.md index 24918533f3f16..85223458a0ab6 100644 --- a/docs/core/install/windows.md +++ b/docs/core/install/windows.md @@ -167,7 +167,15 @@ For more information about, see [.NET SDK, MSBuild, and Visual Studio versioning ## Install with Visual Studio Code -Visual Studio Code is a powerful and lightweight source code editor that runs on your desktop. Visual Studio Code can use the SDK already installed on your system. Additionally, the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension will install .NET for you if it's not already installed. +Visual Studio Code is a powerful and lightweight source code editor that runs on your desktop. Visual Studio Code can use the SDK already installed on your system. + +This [WinGet configuration file](https://builds.dotnet.microsoft.com/dotnet/install/dotnet_basic_config_docs.winget) installs the latest .NET SDK, Visual Studio Code and the C# DevKit. If you already have any of them installed, WinGet will skip that step. + +1. Download the file and double-click to run it. +1. Read the license agreement, type y, and select Enter when prompted to accept. +1. Be on the lookout for a flashing User Account Control (UAC) prompt in your Windows Taskbar, you may need to require administrator-level permissions to install. + +Additionally, the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension will install .NET for you if it's not already installed. For instructions on installing .NET through Visual Studio Code, see [Getting Started with C# in VS Code](https://code.visualstudio.com/docs/csharp/get-started). diff --git a/docs/core/resilience/http-resilience.md b/docs/core/resilience/http-resilience.md index 702e30b548fd0..79180e12e0cbb 100644 --- a/docs/core/resilience/http-resilience.md +++ b/docs/core/resilience/http-resilience.md @@ -90,8 +90,8 @@ The preceding code: - Creates a instance. - Adds the standard resilience handler to all instances. - For the "custom" : -- Removes all predefined resilience handlers that were previously registered. This is useful when you want to start with a clean state to add your own custom strategies. -- Adds a `StandardHedgingHandler` to the . You can replace `AddStandardHedgingHandler()` with any strategy that suits your application's needs, such as retry mechanisms, circuit breakers, or other resilience techniques. + - Removes all predefined resilience handlers that were previously registered. This is useful when you want to start with a clean state to add your own custom strategies. + - Adds a `StandardHedgingHandler` to the . You can replace `AddStandardHedgingHandler()` with any strategy that suits your application's needs, such as retry mechanisms, circuit breakers, or other resilience techniques. ### Standard resilience handler defaults @@ -293,7 +293,7 @@ There's a build time check that verifies if you're using `Grpc.Net.ClientFactory ### Compatibility with .NET Application Insights -If you're using .NET Application Insights, then enabling resilience functionality in your application could cause all Application Insights telemetry to be missing. The issue occurs when resilience functionality is registered before Application Insights services. Consider the following sample causing the issue: +If you're using .NET Application Insights version **2.22.0** or lower, then enabling resilience functionality in your application could cause all Application Insights telemetry to be missing. The issue occurs when resilience functionality is registered before Application Insights services. Consider the following sample causing the issue: ```csharp // At first, we register resilience functionality. @@ -303,7 +303,7 @@ services.AddHttpClient().AddStandardResilienceHandler(); services.AddApplicationInsightsTelemetry(); ``` -The issue is caused by the following [bug](https://github.com/microsoft/ApplicationInsights-dotnet/issues/2879) in Application Insights and can be fixed by registering Application Insights services before resilience functionality, as shown below: +The issue can be fixed by updating .NET Application Insights to version **2.23.0** or higher. If you cannot update it, then registering Application Insights services before resilience functionality, as shown below, will fix the issue: ```csharp // We register Application Insights first, and now it will be working correctly. diff --git a/docs/core/testing/unit-testing-with-mstest.md b/docs/core/testing/unit-testing-with-mstest.md index a8de53239af11..859ffe1b97212 100644 --- a/docs/core/testing/unit-testing-with-mstest.md +++ b/docs/core/testing/unit-testing-with-mstest.md @@ -13,7 +13,7 @@ This tutorial takes you through an interactive experience building a sample solu ## Prerequisites -* The [.NET 6.0 SDK or later](https://dotnet.microsoft.com/download) +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Create the source project diff --git a/docs/core/testing/unit-testing-with-nunit.md b/docs/core/testing/unit-testing-with-nunit.md index c69241715328d..1eee945534622 100644 --- a/docs/core/testing/unit-testing-with-nunit.md +++ b/docs/core/testing/unit-testing-with-nunit.md @@ -13,8 +13,7 @@ This tutorial takes you through an interactive experience building a sample solu ## Prerequisites -- [.NET 8.0](https://dotnet.microsoft.com/download) or later versions. -- A text editor or code editor of your choice. +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Creating the source project diff --git a/docs/core/tutorials/creating-app-with-plugin-support.md b/docs/core/tutorials/creating-app-with-plugin-support.md index 22304c597b0ad..0629ecd2a10ec 100644 --- a/docs/core/tutorials/creating-app-with-plugin-support.md +++ b/docs/core/tutorials/creating-app-with-plugin-support.md @@ -20,7 +20,7 @@ This tutorial shows you how to create a custom method (for the mode) only searches for the SHA-1 Thumbprint value. -There is some risk to using the `Find` method for finding SHA-2-256 ("SHA256") and SHA-3-256 thumbprints since these hash algorithms have the same lengths. +There's some risk to using the `Find` method for finding SHA-2-256 ("SHA256") and SHA-3-256 thumbprints since these hash algorithms have the same lengths. Instead, .NET 10 introduces a new method that accepts the name of the hash algorithm to use for matching. @@ -27,7 +27,7 @@ return coll.SingleOrDefault(); ## Find PEM-encoded Data in ASCII/UTF-8 -The PEM encoding (originally "Privacy Enhanced Mail", but now used widely outside of email) is defined for "text", which means that the class was designed to run on and `ReadOnlySpan`. However, it's quite common (especially on Linux) to have something like a certificate written in a file that uses the ASCII (string) encoding. Historically, that meant you needed to open the file and convert the bytes to chars (or a string) before you could use `PemEncoding`. +The PEM encoding (originally *Privacy Enhanced Mail*, but now used widely outside of email) is defined for "text", which means that the class was designed to run on and `ReadOnlySpan`. However, it's common (especially on Linux) to have something like a certificate written in a file that uses the ASCII (string) encoding. Historically, that meant you needed to open the file and convert the bytes to chars (or a string) before you could use `PemEncoding`. Taking advantage of the fact that PEM is only defined for 7-bit ASCII characters, and that 7-bit ASCII has a perfect overlap with single-byte UTF-8 values, you can now skip the UTF-8/ASCII-to-char conversion and read the file directly. @@ -57,7 +57,7 @@ public static class ISOWeek ## String normalization APIs to work with span of characters -Unicode string normalization has been supported for a long time, but existing APIs have only worked with the string type. This means that callers with data stored in different forms, such as character arrays or spans, must allocate a new string to use these APIs. Additionally, APIs that return a normalized string always allocate a new string to represent the normalized output. +Unicode string normalization has been supported for a long time, but existing APIs only worked with the string type. This means that callers with data stored in different forms, such as character arrays or spans, must allocate a new string to use these APIs. Additionally, APIs that return a normalized string always allocate a new string to represent the normalized output. .NET 10 introduces new APIs that work with spans of characters, expanding normalization beyond string types and helping to avoid unnecessary allocations. @@ -76,7 +76,7 @@ Numerical string comparison is a highly requested feature for comparing strings :::code language="csharp" source="../snippets/dotnet-10/csharp/snippets.cs" id="snippet_numericOrdering"::: -Note that this option is not valid for the following index-based string operations: `IndexOf`, `LastIndexOf`, `StartsWith`, `EndsWith`, `IsPrefix`, and `IsSuffix`. +This option isn't valid for the following index-based string operations: `IndexOf`, `LastIndexOf`, `StartsWith`, `EndsWith`, `IsPrefix`, and `IsSuffix`. ## New `TimeSpan.FromMilliseconds` overload with single parameter @@ -88,7 +88,7 @@ Although this works since the second parameter is optional, it causes a compilat Expression a = () => TimeSpan.FromMilliseconds(1000); ``` -The issue arises because LINQ expressions cannot handle optional parameters. To address this, .NET 10 introduces an overload takes a single parameter and modifying the existing method to make the second parameter mandatory: +The issue arises because LINQ expressions can't handle optional parameters. To address this, .NET 10 introduces an overload takes a single parameter and modifying the existing method to make the second parameter mandatory: ```csharp public readonly struct TimeSpan @@ -108,7 +108,7 @@ Second, the extraction of entries is now ## Additional `TryAdd` and `TryGetValue` overloads for `OrderedDictionary` - provides `TryAdd` and `TryGetValue` for addition and retrieval like any other `IDictionary` implementation. However, there are scenarios where you might want to perform additional operations, so new overloads have been added that return an index to the entry: + provides `TryAdd` and `TryGetValue` for addition and retrieval like any other `IDictionary` implementation. However, there are scenarios where you might want to perform more operations, so new overloads are added that return an index to the entry: ```csharp public class OrderedDictionary @@ -127,7 +127,7 @@ This new API is already used in and improves the p ## Allow specifying ReferenceHandler in `JsonSourceGenerationOptions` -When using source generators for JSON serialization, the generated context will throw when cycles are serialized or deserialized. This behavior can now be customized by specifying the in the . Here is an example using `JsonKnownReferenceHandler.Preserve`: +When you use source generators for JSON serialization, the generated context throws when cycles are serialized or deserialized. This behavior can now be customized by specifying the in the . Here's an example using `JsonKnownReferenceHandler.Preserve`: :::code language="csharp" source="../snippets/dotnet-10/csharp/snippets.cs" id="snippet_selfReference"::: @@ -142,3 +142,11 @@ public partial struct Matrix4x4 public static Matrix4x4 CreateConstrainedBillboardLeftHanded(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector) } ``` + +## Encryption algorithm can now be specified in PKCS\#12/PFX Export + +The new `ExportPkcs12` methods on allow callers to choose what encryption and digest algorithms are used to produce the output. +`Pkcs12ExportPbeParameters.Pkcs12TripleDesSha1` indicates the Windows XP-era de facto standard, +which produces an output supported by almost every library/platform that supports reading PKCS#12/PFX by choosing an older encryption algorithm. `Pkcs12ExportPbeParameters.Pbes2Aes256Sha256` indicates that AES should be used instead of 3DES (and SHA-2-256 instead of SHA-1), but the output may not be understood by all readers (such as Windows XP). + +Callers who want even more control can instead utilize the overload that accepts a . diff --git a/docs/core/whats-new/dotnet-10/overview.md b/docs/core/whats-new/dotnet-10/overview.md index 26f332ad051ad..fc75361c61f56 100644 --- a/docs/core/whats-new/dotnet-10/overview.md +++ b/docs/core/whats-new/dotnet-10/overview.md @@ -2,40 +2,57 @@ title: What's new in .NET 10 description: Learn about the new features introduced in .NET 10 for the runtime, libraries, and SDK. Also find links to what's new in other areas, such as ASP.NET Core. titleSuffix: "" -ms.date: 02/20/2025 +ms.date: 03/18/2025 ms.topic: whats-new ai-usage: ai-assisted --- # What's new in .NET 10 -Learn about the new features in .NET 10 and find links to further documentation. This page has been updated for Preview 1. +Learn about the new features in .NET 10 and find links to further documentation. This page is updated for Preview 2. -.NET 10, the successor to [.NET 9](../dotnet-9/overview.md), will be [supported for 3 years](https://dotnet.microsoft.com/platform/support/policy/dotnet-core) as a long-term support (LTS) release. You can [download .NET 10 here](https://get.dot.net/10). +.NET 10, the successor to [.NET 9](../dotnet-9/overview.md), is [supported for three years](https://dotnet.microsoft.com/platform/support/policy/dotnet-core) as a long-term support (LTS) release. You can [download .NET 10 here](https://get.dot.net/10). -Your feedback is important and appreciated. If you have questions or comments, please use the discussion on [GitHub](https://github.com/dotnet/core/discussions/categories/news). +Your feedback is important and appreciated. If you have questions or comments, use the discussion on [GitHub](https://github.com/dotnet/core/discussions/categories/news). ## .NET runtime -The .NET 10 runtime has introduced new features and performance improvements, which have been updated for Preview 1. One of the main focuses for .NET 10 is to reduce the abstraction overhead of popular language features. In order to achieve this goal, the JIT's ability to devirtualize method calls has been expanded to cover array interface methods. This means that the JIT can now optimize code that loops over an array, even if there are virtual calls involved. Additionally, the JIT now has the ability to stack-allocate small, fixed-sized arrays of value types that do not contain GC pointers, further reducing the abstraction penalty of reference types. +The .NET 10 runtime introduces new features and performance improvements. Key updates include: -Another new feature in .NET 10 is the support for Advanced Vector Extensions (AVX) 10.2 for x64-based processors. This is currently disabled by default as hardware supporting AVX10.2 is not yet available. Once it is available, the new intrinsics in the `System.Runtime.Intrinsics.X86.Avx10v2` class can be tested. These updates and improvements are part of the ongoing efforts to achieve performance parity between different implementations in .NET 10. +- **Array interface method devirtualization**: The JIT can now devirtualize and inline array interface methods, improving performance for array enumerations. +- **Array enumeration de-abstraction**: Enhancements to reduce abstraction overhead for array iteration via enumerators, enabling better inlining and stack allocation. +- **Inlining of late devirtualized methods**: The JIT can now inline methods that become eligible for devirtualization due to previous inlining. +- **Devirtualization based on inlining observations**: The JIT uses precise type information from inlining to devirtualize subsequent calls. +- **Stack allocation of arrays of value types**: Small, fixed-sized arrays of value types without GC pointers can now be stack-allocated. +- **AVX10.2 support**: Introduced support for Advanced Vector Extensions (AVX) 10.2 for x64-based processors, though currently disabled by default. +- **NativeAOT enhancements**: Support for casting and negation in NativeAOT's type preinitializer. For more information, see [What's new in the .NET 10 runtime](runtime.md). ## .NET libraries -The .NET 10 libraries introduce several new features and improvements. A new method `FindByThumbprint` allows finding certificates by thumbprints using hash algorithms other than SHA-1. Additionally, support has been added for reading PEM-encoded data directly from ASCII encoded files. The class now includes new method overloads to support the type. Unicode string normalization APIs have been enhanced to work with spans of characters, and a new `CompareOptions.NumericOrdering` option has been introduced for numerical string comparison. +The .NET 10 libraries introduce several new features and improvements, including: -Additionally, a new overload that takes a single parameter has been added. The performance and memory usage of [ZipArchive](xref:System.IO.Compression.ZipArchive) have been improved. New `TryAdd` and `TryGetValue` overloads for now return an index to the entry. JSON serialization has been enhanced by allowing the specification of in . Lastly, new APIs have been introduced for creating left-handed transformation matrices for billboard and constrained-billboard matrices. +- **Find certificates by thumbprints other than SHA-1**: A new method allows finding certificates using hash algorithms like SHA-256. +- **Find PEM-encoded data in ASCII/UTF-8**: PEM encoding APIs now support reading directly from ASCII/UTF-8 data. +- **ISOWeek support for DateOnly**: New overloads in the class support the type. +- **String normalization APIs for spans**: New APIs allow Unicode string normalization to work with spans of characters, reducing allocations. +- **Numeric ordering for string comparison**: A new option enables numerical string comparisons. +- **New TimeSpan.FromMilliseconds overload**: A single-parameter overload resolves issues with LINQ expressions. +- **ZipArchive performance improvements**: Optimizations reduce memory usage and improve performance for in `Update` mode and parallel extraction. +- **OrderedDictionary enhancements**: New `TryAdd` and `TryGetValue` overloads return an index for fast access. +- **JSON serialization updates**: Source generators now allow specifying `ReferenceHandler` in . +- **Left-handed matrix transformations**: New APIs for creating left-handed transformation matrices. +- **PKCS#12 export enhancements**: New methods allow specifying encryption and digest algorithms for PKCS#12/PFX export. For more information, see [What's new in the .NET 10 libraries](libraries.md). ## .NET SDK -The .NET 10 SDK introduces following new features and enhancements: +The .NET 10 SDK introduces the following new features and enhancements, including: -- [Pruning of Framework-provided Package References](sdk.md#pruning-of-framework-provided-package-references) +- **Pruning of framework-provided package references**: Automatically removes unused framework-provided package references, reducing build times and disk usage. +- **More consistent command order**: New noun-first aliases for `dotnet` CLI commands improve readability and consistency. For more information, see [What's new in the SDK for .NET 10](sdk.md). @@ -47,56 +64,166 @@ For more information, see [What's new in .NET Aspire 9.1](/dotnet/aspire/whats-n ## ASP.NET Core -Changes in ASP.NET Core 10.0 include: +The ASP.NET Core 10.0 release introduces several new features and enhancements, including: -- Blazor: Added new features for Blazor, including the QuickGrid RowClass parameter and Blazor script serving as a static web asset. -- SignalR: Added new features for SignalR. -- Minimal APIs: Added new features for minimal APIs. -- OpenAPI: Added support for generating OpenAPI version 3.1 documents and serving the generated OpenAPI document in YAML format. -- Authentication and authorization: Added new features for authentication and authorization. -- Miscellaneous: Added better support for testing apps with top-level statements and a new helper method for detecting local URLs. +- **Blazor enhancements**: + - Added the `ReconnectModal` component to the Blazor Web App project template for improved reconnection UI control. + - The `NavigateTo` method no longer scrolls to the top for same-page navigation. + - The `NavLink` component now ignores query strings and fragments when using `NavLinkMatch.All`. + - Added the `RowClass` parameter to `QuickGrid` for applying styles to rows based on their data. + - Added the `CloseColumnOptionsAsync` method to `QuickGrid` for programmatically closing column options. + - Blazor framework script is now served as a static web asset with precompression and fingerprinting enabled. + +- **OpenAPI improvements**: + - Added support for generating OpenAPI version 3.1 documents. + - Added support for serving OpenAPI documents in YAML format. + - Populated XML doc comments into OpenAPI documents. + +- **Minimal APIs**: + - Improved integration testing for apps using top-level statements. + - Empty strings in form posts are now treated as `null` for nullable value types. + +- **Authentication and authorization**: + - Added new metrics for authentication and authorization events. + +- **Miscellaneous**: + - Added the `RedirectHttpResult.IsLocalUrl` helper method for detecting local URLs. + - Added support for route syntax highlighting in the . For more information, see [What's new in ASP.NET Core for .NET 10](/aspnet/core/release-notes/aspnetcore-10.0). +## C# 14 + +C# 14 introduces several new features and enhancements to improve developer productivity and code quality. Key updates include: + +- **Field-backed properties**: Provides a smoother path from auto-implemented properties to writing custom `get` and `set` accessors. The compiler-generated backing field can now be accessed using the `field` contextual keyword. +- **Unbound generic support for `nameof`**: The `nameof` expression now supports unbound generic types, such as `List<>`, returning the name of the type without requiring type arguments. +- **Implicit span conversions**: Introduces first-class support for `Span` and `ReadOnlySpan` with new implicit conversions, enabling more natural programming with these types. +- **Modifiers on simple lambda parameters**: Allows parameter modifiers like `ref`, `in`, or `out` in lambda expressions without specifying parameter types. +- **Experimental feature - String literals in data section**: Enables emitting string literals as UTF-8 data into a separate section of the PE file, improving efficiency for certain scenarios. +- **Partial events and constructors**: Adds support for partial instance constructors and partial events, complementing partial methods and properties introduced in C# 13. + +For more information, see [What's new in C# 14](../../../csharp/whats-new/csharp-14.md). + ## .NET MAUI -This release was focused on quality improvements to .NET MAUI, .NET for Android, and .NET for iOS, Mac Catalyst, macOS, and tvOS. +The .NET MAUI updates in .NET 10 include several new features and quality improvements for .NET MAUI, .NET for Android, and .NET for iOS, Mac Catalyst, macOS, and tvOS. Key updates include: + +- **General improvements**: + - New `ShadowTypeConverter` for converting formatted strings to `Shadow` on `VisualElement`. + - Added `SpeechOptions.Rate` for controlling the playback rate in Text-to-Speech. + - Support for styling modals as popovers on iOS and Mac Catalyst. + - Added `Switch.OffColor` for customizing the color of the `Switch` control when off. + - Added `SearchBar.SearchIconColor` for customizing the search icon color. + - New `HybridWebView.InvokeJavascriptAsync` method for invoking JavaScript without requiring generic arguments. + +- **Deprecations**: + - The `FontImageExtension` XAML markup extension is deprecated. Use `FontImageSource` instead. + - `MessagingCenter` is now internal. Replace it with `WeakReferenceMessenger` from the `CommunityToolkit.Mvvm` package. + +- **.NET for Android**: + - Support for Android 16 (API-36) Beta 1. + - Updated recommended minimum supported Android API to 24 (Nougat). + - Support for building with JDK-21. + - Added support for `dotnet run` for Android projects. + - Enabled marshal methods by default for improved startup performance. + - Design-time builds no longer invoke `aapt2`, reducing build times. + +- **.NET for iOS, Mac Catalyst, macOS, tvOS**: + - Trimmer warnings are now enabled by default. + - Bundling of original resources in libraries is now opt-out. For more information, see [What's new in .NET MAUI in .NET 10](/dotnet/maui/whats-new/dotnet-10). ## EF Core -Changes for EF Core 10 include: +The EF Core 10 release introduces several new features and improvements, including: + +- **LINQ enhancements**: + - Added support for the `LeftJoin` operator, simplifying LINQ queries that require `LEFT JOIN` operations. + - Added support for the `RightJoin` operator, enabling LINQ queries that require `RIGHT JOIN` operations. + +- **ExecuteUpdateAsync improvements**: + - `ExecuteUpdateAsync` now accepts a regular, non-expression lambda, reducing verbosity when updating entities. + +- **Performance optimizations**: + - Improved translation for `DateOnly.ToDateTime(timeOnly)`. + - Optimized multiple consecutive `LIMIT` operations. + - Enhanced performance for `Count` operations on `ICollection`. + - Optimized `MIN`/`MAX` operations over `DISTINCT`. -- LINQ and SQL translation enhancements. -- ExecuteUpdateAsync now accepts a regular, non-expression lambda. +- **Miscellaneous**: + - Simplified parameter names in SQL queries (for example, from `@__city_0` to `city`). + - Added translation for date/time functions using `DatePart.Microsecond` and `DatePart.Nanosecond`. + - Made SQL Server scaffolding compatible with Azure Data Explorer. For more information, see [What's new in EF Core for .NET 10](/ef/core/what-is-new/ef-core-10.0/whatsnew). -## C# 14 +## F\# -C# 14 introduces several new features and enhancements to improve developer productivity and code quality. Some of the key updates include: +The F# updates in .NET 10 include several new features and improvements across the language, standard library, and compiler service. Key updates include: -- `nameof` in unbound generics. -- Implicit span conversions. -- `field` backed properties. -- Modifiers on simple lambda parameters. -- Experimental feature - String literals in data section. +- **F# Language**: + - New language features require enabling the `preview` project property in `.fsproj` files. These features become the default with the .NET 10 release. -For more information, see [What's new in C# 14](../../../csharp/whats-new/csharp-14.md). +- **FSharp.Core Standard Library**: + - Changes to the `FSharp.Core` standard library are applied automatically to projects compiled with the new SDK unless a lower `FSharp.Core` version is explicitly pinned. + +- **FSharp.Compiler.Service**: + - General improvements and bug fixes in the compiler implementation. + +For more information, see the [F# release notes](https://fsharp.github.io/fsharp-compiler-docs/release-notes/). + +## Visual Basic + +The Visual Basic updates in .NET 10 include the following features and enhancements: + +- **`unmanaged` constraint support**: The Visual Basic compiler now interprets and enforces the `unmanaged` generic constraint, enabling better compatibility with runtime APIs. +- **Honor overload resolution priority**: The Visual Basic compiler respects the , ensuring faster Span-based overloads are preferred and resolving ambiguities among method overloads. + +These updates ensure that Visual Basic can consume updated features in C# and the runtime, improving compatibility and performance. + +For more information, see [What's new in Visual Basic](https://learn.microsoft.com/dotnet/visual-basic/whats-new/). ## Windows Forms Changes in Windows Forms for .NET 10 include: -- Clipboard-related serialization and deserialization changes. -- Obsoleted Clipboard APIs. -- New Clipboard-related APIs. +- **Clipboard-related updates**: + - Introduced new APIs for JSON serialization and type-safe data retrieval from the Clipboard, such as `SetDataAsJson` and `TryGetData`. + - Marked several Clipboard-related APIs as obsolete to warn developers about potential `BinaryFormatter` usage. + - Added a configuration switch (`Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization`) to explicitly enable `BinaryFormatter` for Clipboard scenarios. + - Unified Clipboard code with WPF to enhance consistency and reliability. + +- **Ported UITypeEditors**: + - Ported several `UITypeEditors` from the .NET Framework, including `ToolStripCollectionEditor` and editors related to the `DataGridView` control. + +- **Quality enhancements**: + - Expanded unit test coverage and addressed various bug fixes to improve stability and performance. For more information, see [What's new in Windows Forms for .NET 10](/dotnet/desktop/winforms/whats-new/net100). -## See also +## WPF + +The WPF updates in .NET 10 include several performance improvements, Fluent style changes, bug fixes, and engineering health updates: + +- **Performance improvements**: + - Replaced data structures like `PartialList` with `ReadOnlyCollection` to enhance performance. + - Optimized UI automation and file dialog operations to minimize allocations. + - Improved pixel format conversion performance. + +- **Fluent style changes**: + - Updated the default style for `Label`. + - Fixed animation issues for `Expander` by adjusting a `KeyTime` value. + +- **Bug fixes**: + - Resolved issues with UI element cursor types and crashes when bitmap streams are null. + - Fixed localization issues for `ScrollViewer` and `ContextMenu`. + - Addressed minor bugs in `BitmapMetadata` and native dependencies. + +- **Engineering health**: + - Updated and synchronized **MilCodeGen** across WPF components. + - Removed deprecated .NET runtime references and unnecessary package dependencies. + - Conducted style cleanups and disabled code analysis for generated code to streamline builds. -- [.NET 10 Preview 1 container image updates](https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/containers.md) -- [F# updates in .NET 10 Preview 1](https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/fsharp.md) -- [Visual Basic updates in .NET 10 Preview 1](https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/visualbasic.md) +For more information, see [What's new in WPF in .NET 10](/dotnet/desktop/wpf/whats-new/net100). diff --git a/docs/core/whats-new/dotnet-10/runtime.md b/docs/core/whats-new/dotnet-10/runtime.md index 71dcce1203d55..be86518225750 100644 --- a/docs/core/whats-new/dotnet-10/runtime.md +++ b/docs/core/whats-new/dotnet-10/runtime.md @@ -2,17 +2,17 @@ title: What's new in .NET 10 runtime description: Learn about the new .NET features introduced in the .NET 10 runtime. titleSuffix: "" -ms.date: 02/20/2025 +ms.date: 03/18/2025 ms.topic: whats-new ai-usage: ai-assisted --- # What's new in the .NET 10 runtime -This article describes new features and performance improvements in the .NET runtime for .NET 10. It has been updated for Preview 1. +This article describes new features and performance improvements in the .NET runtime for .NET 10. It's updated for Preview 2. ## Array interface method devirtualization -One of the [focus areas](https://github.com/dotnet/runtime/issues/108988) for .NET 10 is to reduce the abstraction overhead of popular language features. In pursuit of this goal, the JIT's ability to devirtualize method calls has been expanded to cover array interface methods. +One of the [focus areas](https://github.com/dotnet/runtime/issues/108988) for .NET 10 is to reduce the abstraction overhead of popular language features. In pursuit of this goal, the JIT's ability to devirtualize method calls has expanded to cover array interface methods. Consider the typical approach of looping over an array: @@ -44,13 +44,25 @@ static int Sum(int[] array) } ``` -The type of the underlying collection is clear, and the JIT should be able to transform this snippet into the first one. However, array interfaces are implemented differently from "normal" interfaces, such that the JIT does not know how to devirtualize them. This means the enumerator calls in the `for-each` loop remain virtual, blocking multiple optimizations such as inlining and stack allocation. +The type of the underlying collection is clear, and the JIT should be able to transform this snippet into the first one. However, array interfaces are implemented differently from "normal" interfaces, such that the JIT doesn't know how to devirtualize them. This means the enumerator calls in the `for-each` loop remain virtual, blocking multiple optimizations such as inlining and stack allocation. Starting in .NET 10, the JIT can devirtualize and inline array interface methods. This is the first of many steps to achieve performance parity between the implementations, as detailed in the [.NET 10 de-abstraction plans](https://github.com/dotnet/runtime/issues/108913). +## Array enumeration de-abstraction + +Efforts to reduce the abstraction overhead of array iteration via enumerators have improved the JIT's inlining, stack allocation, and loop cloning abilities. For example, the overhead of enumerating arrays via `IEnumerable` is reduced, and conditional escape analysis now enables stack allocation of enumerators in certain scenarios. For more information, see [dotnet/runtime #108913](https://github.com/dotnet/runtime/issues/108913) and [dotnet/runtime #111473](https://github.com/dotnet/runtime/pull/111473). + +## Inlining of late devirtualized methods + +The JIT can now inline methods that become eligible for devirtualization due to previous inlining. This improvement allows the JIT to uncover more optimization opportunities, such as further inlining and devirtualization. For more information, see [dotnet/runtime #110827](https://github.com/dotnet/runtime/pull/110827). + +## Devirtualization based on inlining observations + +During inlining, the JIT now updates the type of temporary variables holding return values. If all return sites in a callee yield the same type, this precise type information is used to devirtualize subsequent calls. This enhancement complements the improvements in late devirtualization and array enumeration de-abstraction. For more information, see [dotnet/runtime #111948](https://github.com/dotnet/runtime/pull/111948). + ## Stack allocation of arrays of value types -In .NET 9, the JIT gained the ability to allocate objects on the stack, when the object is guaranteed to not outlive its parent method. Not only does stack allocation reduce the number of objects the GC has to track, but it also unlocks other optimizations. For example, after an object has been stack-allocated, the JIT can consider replacing it entirely with its scalar values. Because of this, stack allocation is key to reducing the abstraction penalty of reference types. +In .NET 9, the JIT gained the ability to allocate objects on the stack, when the object is guaranteed to not outlive its parent method. Not only does stack allocation reduce the number of objects the GC has to track, but it also unlocks other optimizations. For example, after an object is stack-allocated, the JIT can consider replacing it entirely with its scalar values. Because of this, stack allocation is key to reducing the abstraction penalty of reference types. In .NET 10, the JIT now stack-allocates small, fixed-sized arrays of value types that don't contain GC pointers when it can make the same lifetime guarantees described previously. Consider the following example: @@ -67,13 +79,16 @@ static void Sum() Console.WriteLine(sum); } - ``` Because the JIT knows `numbers` is an array of only three integers at compile time, and it doesn't outlive a call to `Sum`, it allocates it on the stack. ## AVX10.2 support -.NET 10 introduces support for the Advanced Vector Extensions (AVX) 10.2 for x64-based processors. The new intrinsics available in the `System.Runtime.Intrinsics.X86.Avx10v2` class can be tested once capable hardware is available. +.NET 10 introduces support for the Advanced Vector Extensions (AVX) 10.2 for x64-based processors. The new intrinsics available in the class can be tested once capable hardware is available. + +Because AVX10.2-enabled hardware isn't yet available, the JIT's support for AVX10.2 is currently disabled by default. + +## Support for casting and negation in NativeAOT's type preinitializer -Because AVX10.2-enabled hardware is not yet available, the JIT's support for AVX10.2 is currently disabled by default. +NativeAOT's type preinitializer now supports all variants of the `conv.*` and `neg` opcodes. This enhancement allows preinitialization of methods that include casting or negation operations, further optimizing runtime performance. For more information, see [dotnet/runtime #112073](https://github.com/dotnet/runtime/pull/112073). diff --git a/docs/core/whats-new/dotnet-10/sdk.md b/docs/core/whats-new/dotnet-10/sdk.md index 9147f9da6c927..05a30043f17e3 100644 --- a/docs/core/whats-new/dotnet-10/sdk.md +++ b/docs/core/whats-new/dotnet-10/sdk.md @@ -2,23 +2,39 @@ title: What's new in the SDK and tooling for .NET 10 description: Learn about the new .NET SDK features introduced in .NET 10. titleSuffix: "" -ms.date: 02/20/2025 +ms.date: 03/18/2025 ms.topic: whats-new ai-usage: ai-assisted --- # What's new in the SDK and tooling for .NET 10 -This article describes new features and enhancements in the .NET SDK for .NET 10. It has been updated for Preview 1. +This article describes new features and enhancements in the .NET SDK for .NET 10. It's updated for Preview 2. ## New features and enhancements - [Pruning of framework-provided package references](#pruning-of-framework-provided-package-references) +- [More consistent command order](#more-consistent-command-order) ## Pruning of framework-provided package references -Starting in .NET 10, the [NuGet Audit](/nuget/concepts/auditing-packages) feature can now [prune framework-provided package references](https://github.com/NuGet/Home/blob/451c27180d14214bca60483caee57f0dc737b8cf/accepted/2024/prune-package-reference.md) that aren't used by the project. This feature is enabled by default for all `net` target frameworks (for example, `net8.0` and `net10.0`) and .NET Standard 2.0 and greater target frameworks. This change helps to reduce the number of packages that are restored and analyzed during the build process, which can lead to faster build times and reduced disk space usage. It also can lead to a reduction in false positives from NuGet Audit and other dependency-scanning mechanisms. +Starting in .NET 10, the [NuGet Audit](/nuget/concepts/auditing-packages) feature can now [prune framework-provided package references](https://github.com/NuGet/Home/blob/451c27180d14214bca60483caee57f0dc737b8cf/accepted/2024/prune-package-reference.md) that aren't used by the project. This feature is enabled by default for all `net` target frameworks (for example, `net8.0` and `net10.0`) and .NET Standard 2.0 and greater target frameworks. This change helps reduce the number of packages that are restored and analyzed during the build process, which can lead to faster build times and reduced disk space usage. It also can lead to a reduction in false positives from NuGet Audit and other dependency-scanning mechanisms. -When this feature is enabled, you may see a reduction in the contents of your applications' generated *.deps.json* files. Any package references you might have had that are actually supplied by the .NET runtime you use are automatically removed from the generated dependency file. +When this feature is enabled, you may see a reduction in the contents of your applications' generated *.deps.json* files. Any package references supplied by the .NET runtime are automatically removed from the generated dependency file. While this feature is enabled by default for the listed TFMs, you can disable it by setting the `RestoreEnablePackagePruning` property to `false` in your project file or *Directory.Build.props* file. + +## More consistent command order + +Starting in .NET 10, the `dotnet` CLI tool includes new aliases for common commands to make them easier to remember and type. The new commands are: + +- `dotnet package add` +- `dotnet package list` +- `dotnet package remove` +- `dotnet reference add` +- `dotnet reference list` +- `dotnet reference remove` + +These commands are aliases for the existing verb-first forms: `dotnet add package`, `dotnet list package`, `dotnet remove package`, `dotnet add reference`, `dotnet list reference`, and `dotnet remove reference`. + +The new noun-first forms align with general CLI standards, making the `dotnet` CLI more consistent with other tools. While the verb-first forms continue to work, using the noun-first forms for improved readability and consistency in scripts and documentation is recommended. diff --git a/docs/csharp/advanced-topics/reflection-and-attributes/index.md b/docs/csharp/advanced-topics/reflection-and-attributes/index.md index fe48ca175dfff..3314666324872 100644 --- a/docs/csharp/advanced-topics/reflection-and-attributes/index.md +++ b/docs/csharp/advanced-topics/reflection-and-attributes/index.md @@ -1,65 +1,111 @@ --- -title: "Attributes and reflection" -description: Use attributes to associate metadata or declarative information with code in C#. An attribute can be queried at run time by using reflection. Reflection provides objects that describe assemblies, modules, and types in C#. If your code includes attributes, reflection enables you to access them. -ms.date: 03/15/2023 +title: Attributes and reflection +description: Use attributes to associate metadata or declarative information in C#. Query attributes at run time with reflection APIs that describe assemblies, modules, and types. +ms.date: 03/14/2025 --- # Attributes -Attributes provide a powerful method of associating metadata, or declarative information, with code (assemblies, types, methods, properties, and so forth). After an attribute is associated with a program entity, the attribute can be queried at run time by using a technique called *reflection*. +Attributes provide a powerful way to associate metadata, or declarative information, with code (assemblies, types, methods, properties, and so on). After you associate an attribute with a program entity, you can query the attribute at run time by using a technique called *reflection*. Attributes have the following properties: -- Attributes add metadata to your program. *Metadata* is information about the types defined in a program. All .NET assemblies contain a specified set of metadata that describes the types and type members defined in the assembly. You can add custom attributes to specify any additional information that is required. -- You can apply one or more attributes to entire assemblies, modules, or smaller program elements such as classes and properties. +- Attributes add metadata to your program. *Metadata* is information about the types defined in a program. All .NET assemblies contain a specified set of metadata that describes the types and type members defined in the assembly. You can add custom attributes to specify any other required information. +- Attributes can be applied to entire assemblies, modules, or smaller program elements, such as classes and properties. - Attributes can accept arguments in the same way as methods and properties. -- Your program can examine its own metadata or the metadata in other programs by using reflection. +- Attributes enable a program to examine its own metadata or metadata in other programs by using reflection. -[Reflection](../../../fundamentals/reflection/reflection.md) provides objects (of type ) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you're using attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). +## Work with reflection -Here's a simple example of reflection using the method - inherited by all types from the `Object` base class - to obtain the type of a variable: +[Reflection](../../../fundamentals/reflection/reflection.md) APIs provided by describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. When you use attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). + +Here's a simple example of reflection with the method. All types from the `Object` base class inherit this method, which is used to obtain the type of a variable: > [!NOTE] -> Make sure you add `using System;` and `using System.Reflection;` at the top of your *.cs* file. +> Make sure you add the `using System;` and `using System.Reflection;` statements at the top of your C# (*.cs*) code file. :::code language="csharp" source="./snippets/conceptual/Program.cs" id="GetTypeInformation"::: -The output is: `System.Int32`. +The output shows the type: + +```output +System.Int32 +``` The following example uses reflection to obtain the full name of the loaded assembly. :::code language="csharp" source="./snippets/conceptual/Program.cs" id="GetAssemblyInfo"::: -The output is something like: `System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e`. +The output is similar to the following example: -> [!NOTE] -> The C# keywords `protected` and `internal` have no meaning in Intermediate Language (IL) and are not used in the reflection APIs. The corresponding terms in IL are *Family* and *Assembly*. To identify an `internal` method using reflection, use the property. To identify a `protected internal` method, use the . +```output +System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e +``` -## Using attributes +### Keyword differences for IL + +The C# keywords `protected` and `internal` have no meaning in Intermediate Language (IL) and aren't used in the reflection APIs. The corresponding terms in IL are *Family* and *Assembly*. Here some ways you can use these terms: + +- To identify an `internal` method by using reflection, use the property. +- To identify a `protected internal` method, use the . + +## Work with attributes Attributes can be placed on almost any declaration, though a specific attribute might restrict the types of declarations on which it's valid. In C#, you specify an attribute by placing the name of the attribute enclosed in square brackets (`[]`) above the declaration of the entity to which it applies. -In this example, the attribute is used to apply a specific characteristic to a class: +In this example, you use the attribute to apply a specific characteristic to a class: :::code language="csharp" source="./snippets/conceptual/AttributesOverview.cs" id="Snippet1"::: -A method with the attribute is declared like the following example: +You can declare a method with the attribute: :::code language="csharp" source="./snippets/conceptual/AttributesOverview.cs" id="Snippet2"::: -More than one attribute can be placed on a declaration as the following example shows: +You can place multiple attributes on a declaration: :::code language="csharp" source="./snippets/conceptual/AttributesOverview.cs" id="Snippet4"::: -Some attributes can be specified more than once for a given entity. An example of such a multiuse attribute is : +Some attributes can be specified more than once for a given entity. The following example shows multiuse of the attribute: :::code language="csharp" source="./snippets/conceptual/AttributesOverview.cs" id="Snippet5"::: > [!NOTE] -> By convention, all attribute names end with the word "Attribute" to distinguish them from other items in the .NET libraries. However, you do not need to specify the attribute suffix when using attributes in code. For example, `[DllImport]` is equivalent to `[DllImportAttribute]`, but `DllImportAttribute` is the attribute's actual name in the .NET Class Library. +> By convention, all attribute names end with the suffix "Attribute" to distinguish them from other types in the .NET libraries. However, you don't need to specify the attribute suffix when you use attributes in code. For example, a `[DllImport]` declaration is equivalent to a `[DllImportAttribute]` declaration, but `DllImportAttribute` is the actual name of the class in the .NET Class Library. ### Attribute parameters -Many attributes have parameters, which can be positional, unnamed, or named. Any positional parameters must be specified in a certain order and can't be omitted. Named parameters are optional and can be specified in any order. Positional parameters are specified first. For example, these three attributes are equivalent: +Many attributes have parameters, which can be *positional*, *unnamed*, or *named*. The following table describes how to work with named and positional attributes: + +:::row::: +:::column span="2"::: +**Positional parameters** + +Parameters of the attribute constructor: +:::column-end::: +:::column span="2"::: +**Named parameters** + +Properties or fields of the attribute: +:::column-end::: +:::row-end::: + +:::row::: +:::column span="2"::: + +- Must specify, can't omit +- Always specify first +- Specify in **certain** order + +:::column-end::: +:::column span="2"::: + +- Always optional, omit when false +- Specify after positional parameters +- Specify in any order + +:::column-end::: +:::row-end::: + +For example, the following code shows three equivalent `DllImport` attributes: ```csharp [DllImport("user32.dll")] @@ -67,13 +113,11 @@ Many attributes have parameters, which can be positional, unnamed, or named. Any [DllImport("user32.dll", ExactSpelling=false, SetLastError=false)] ``` -The first parameter, the DLL name, is positional and always comes first; the others are named. In this case, both named parameters default to false, so they can be omitted. Positional parameters correspond to the parameters of the attribute constructor. Named or optional parameters correspond to either properties or fields of the attribute. Refer to the individual attribute's documentation for information on default parameter values. - -For more information on allowed parameter types, see the [Attributes](~/_csharpstandard/standard/attributes.md#2224-attribute-parameter-types) section of the [C# language specification](~/_csharpstandard/standard/README.md). +The first parameter, the DLL name, is positional and always comes first. The other instances are named parameters. In this scenario, both named parameters default to false, so they can be omitted. Refer to the individual attribute's documentation for information on default parameter values. For more information on allowed parameter types, see the [Attributes](~/_csharpstandard/standard/attributes.md#2224-attribute-parameter-types) section of the [C# language specification](~/_csharpstandard/standard/README.md). ### Attribute targets -The *target* of an attribute is the entity that the attribute applies to. For example, an attribute may apply to a class, a particular method, or an entire assembly. By default, an attribute applies to the element that follows it. But you can also explicitly identify, for example, whether an attribute is applied to a method, or to its parameter, or to its return value. +The *target* of an attribute is the entity that the attribute applies to. For example, an attribute can apply to a class, a method, or an assembly. By default, an attribute applies to the element that follows it. But you can also explicitly identify the element to associate, such as a method, a parameter, or the return value. To explicitly identify an attribute target, use the following syntax: @@ -81,7 +125,7 @@ To explicitly identify an attribute target, use the following syntax: [target : attribute-list] ``` -The list of possible `target` values is shown in the following table. +The following table shows the list of possible `target` values. | Target value | Applies to | |--------------|------------------------------------------------------------------------| @@ -95,9 +139,9 @@ The list of possible `target` values is shown in the following table. | `return` | Return value of a method, property indexer, or `get` property accessor | | `type` | Struct, class, interface, enum, or delegate | -You would specify the `field` target value to apply an attribute to the backing field created for an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md). +You can specify the `field` target value to apply an attribute to the backing field created for an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md). -The following example shows how to apply attributes to assemblies and modules. For more information, see [Common Attributes (C#)](../../language-reference/attributes/global.md). +The following example shows how to apply attributes to assemblies and modules. For more information, see [Common attributes (C#)](../../language-reference/attributes/global.md). ```csharp using System; @@ -111,42 +155,40 @@ The following example shows how to apply attributes to methods, method parameter :::code language="csharp" source="./snippets/conceptual/AttributesOverview.cs" id="Snippet6"::: > [!NOTE] -> Regardless of the targets on which `ValidatedContract` is defined to be valid, the `return` target has to be specified, even if `ValidatedContract` were defined to apply only to return values. In other words, the compiler will not use `AttributeUsage` information to resolve ambiguous attribute targets. For more information, see [AttributeUsage](../../language-reference/attributes/general.md). - -## Common uses for attributes +> Regardless of the targets on which the `ValidatedContract` attribute is defined to be valid, the `return` target has to be specified, even if the `ValidatedContract` attribute is defined to apply only to return values. In other words, the compiler doesn't use the `AttributeUsage` information to resolve ambiguous attribute targets. For more information, see [AttributeUsage](../../language-reference/attributes/general.md). -The following list includes a few of the common uses of attributes in code: +## Review ways to use attributes -- Marking methods using the `WebMethod` attribute in Web services to indicate that the method should be callable over the SOAP protocol. For more information, see . -- Describing how to marshal method parameters when interoperating with native code. For more information, see . -- Describing the COM properties for classes, methods, and interfaces. -- Calling unmanaged code using the class. -- Describing your assembly in terms of title, version, description, or trademark. -- Describing which members of a class to serialize for persistence. -- Describing how to map between class members and XML nodes for XML serialization. -- Describing the security requirements for methods. -- Specifying characteristics used to enforce security. -- Controlling optimizations by the just-in-time (JIT) compiler so the code remains easy to debug. -- Obtaining information about the caller to a method. +Here are some common ways to use attributes in code: -## Reflection overview +- Mark controller methods that respond to POST messages by using the `HttpPost` attribute. For more information, see the class. +- Describe how to marshal method parameters when interoperating with native code. For more information, see the class. +- Describe Component Object Model (COM) properties for classes, methods, and interfaces. +- Call unmanaged code by using the class. +- Describe your assembly in terms of title, version, description, or trademark. +- Describe which members of a class to serialize for persistence. +- Describe how to map between class members and XML nodes for XML serialization. +- Describe the security requirements for methods. +- Specify characteristics used to enforce security. +- Control optimizations with the just-in-time (JIT) compiler so the code remains easy to debug. +- Obtain information about the caller to a method. -Reflection is useful in the following situations: +## Review reflection scenarios -- When you have to access attributes in your program's metadata. For more information, see [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md). -- For examining and instantiating types in an assembly. -- For building new types at run time. Use classes in . -- For performing late binding, accessing methods on types created at run time. See the article [Dynamically Loading and Using Types](../../../fundamentals/reflection/dynamically-loading-and-using-types.md). +Reflection is useful in the following scenarios: -## Related sections +- Access attributes in your program's metadata. For more information, see [Retrieving information stored in attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md). +- Examine and instantiate types in an assembly. +- Build new types at run time by using classes in the namespace. +- Perform late binding and access methods on types created at run time. For more information, see [Dynamically loading and using types](../../../fundamentals/reflection/dynamically-loading-and-using-types.md). -For more information: +## Related links -- [Common Attributes (C#)](../../language-reference/attributes/global.md) -- [Caller Information (C#)](../../language-reference/attributes/caller-information.md) +- [Common attributes (C#)](../../language-reference/attributes/global.md) +- [Caller information (C#)](../../language-reference/attributes/caller-information.md) - [Attributes](../../../standard/attributes/index.md) - [Reflection](../../../fundamentals/reflection/reflection.md) -- [View Type Information](../../../fundamentals/reflection/viewing-type-information.md) -- [Reflection and Generic Types](../../../fundamentals/reflection/reflection-and-generic-types.md) +- [View type information](../../../fundamentals/reflection/viewing-type-information.md) +- [Reflection and generic types](../../../fundamentals/reflection/reflection-and-generic-types.md) - -- [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md) +- [Retrieving information stored in attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md) diff --git a/docs/csharp/asynchronous-programming/cancel-an-async-task-or-a-list-of-tasks.md b/docs/csharp/asynchronous-programming/cancel-an-async-task-or-a-list-of-tasks.md index 0669bbcf31cef..28059da54f4f7 100644 --- a/docs/csharp/asynchronous-programming/cancel-an-async-task-or-a-list-of-tasks.md +++ b/docs/csharp/asynchronous-programming/cancel-an-async-task-or-a-list-of-tasks.md @@ -19,11 +19,7 @@ This tutorial covers: ## Prerequisites -This tutorial requires the following: - -- [.NET 5 or later SDK](https://dotnet.microsoft.com/download/dotnet/5.0) -- Integrated development environment (IDE) - - [We recommend Visual Studio or Visual Studio Code](https://visualstudio.microsoft.com) +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ### Create example application diff --git a/docs/csharp/fundamentals/tutorials/classes.md b/docs/csharp/fundamentals/tutorials/classes.md index 6594a7f51b6ae..5ae6454e5bdef 100644 --- a/docs/csharp/fundamentals/tutorials/classes.md +++ b/docs/csharp/fundamentals/tutorials/classes.md @@ -9,7 +9,7 @@ In this tutorial, you'll build a console application and see the basic object-or ## Prerequisites -[!INCLUDE [Prerequisites](../../includes/prerequisites.md)] +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic-winget.md)] ## Create your application diff --git a/docs/csharp/fundamentals/tutorials/inheritance.md b/docs/csharp/fundamentals/tutorials/inheritance.md index d61a4eb53b50e..93e8aea687090 100644 --- a/docs/csharp/fundamentals/tutorials/inheritance.md +++ b/docs/csharp/fundamentals/tutorials/inheritance.md @@ -10,7 +10,7 @@ This tutorial introduces you to inheritance in C#. Inheritance is a feature of o ## Prerequisites -[!INCLUDE [Prerequisites](../../includes/prerequisites.md)] +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic-winget.md)] ## Running the examples diff --git a/docs/csharp/fundamentals/tutorials/pattern-matching.md b/docs/csharp/fundamentals/tutorials/pattern-matching.md index 4ff3827c87650..b134a13666f9f 100644 --- a/docs/csharp/fundamentals/tutorials/pattern-matching.md +++ b/docs/csharp/fundamentals/tutorials/pattern-matching.md @@ -17,7 +17,7 @@ In this tutorial, you'll learn how to: ## Prerequisites -[!INCLUDE [Prerequisites](../../includes/prerequisites.md)] +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic-winget.md)] This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET CLI. diff --git a/docs/csharp/includes/prerequisites.md b/docs/csharp/includes/prerequisites.md deleted file mode 100644 index 03174d3cbe825..0000000000000 --- a/docs/csharp/includes/prerequisites.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -author: BillWagner -ms.author: wiwagn -ms.topic: include -ms.date: 04/26/2022 ---- - -- We recommend [Visual Studio](https://visualstudio.com) for Windows. You can download a free version from the [Visual Studio downloads page](https://visualstudio.microsoft.com/downloads). Visual Studio includes the .NET SDK. -- You can also use the [Visual Studio Code](https://code.visualstudio.com) editor with the [C# DevKit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit). You'll need to install the latest [.NET SDK](https://dotnet.microsoft.com/download) separately. -- If you prefer a different editor, you need to install the latest [.NET SDK](https://dotnet.microsoft.com/download). diff --git a/docs/csharp/tour-of-csharp/tutorials/index.md b/docs/csharp/tour-of-csharp/tutorials/index.md index b766bd1c5d82d..2dff3021aefe6 100644 --- a/docs/csharp/tour-of-csharp/tutorials/index.md +++ b/docs/csharp/tour-of-csharp/tutorials/index.md @@ -41,6 +41,6 @@ This tutorial assumes that you've finished the lessons listed above. ## Set up your local environment -After you finish these tutorials, set up a development environment. +After you finish these tutorials, set up a development environment. You'll want: -[!INCLUDE [Prerequisites](../../includes/prerequisites.md)] +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic-winget.md)] diff --git a/docs/csharp/tutorials/console-teleprompter.md b/docs/csharp/tutorials/console-teleprompter.md index b9e4596d74e60..bc51f930eedad 100644 --- a/docs/csharp/tutorials/console-teleprompter.md +++ b/docs/csharp/tutorials/console-teleprompter.md @@ -21,8 +21,7 @@ There are a lot of features in this tutorial. Let's build them one by one. ## Prerequisites -- [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0). -- A code editor. +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Create the app diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index a60e4a2858cc6..442e0c2c7d86c 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -20,8 +20,7 @@ If you prefer to follow along with the [final sample](/samples/dotnet/samples/co ## Prerequisites -* [.NET SDK 6.0 or later](https://dotnet.microsoft.com/download/dotnet/6.0) -* A code editor such as [Visual Studio [Code](https://code.visualstudio.com/) (an open-source, cross-platform editor). You can run the sample app on Windows, Linux, or macOS, or in a Docker container. +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Create the client app diff --git a/docs/csharp/tutorials/nullable-reference-types.md b/docs/csharp/tutorials/nullable-reference-types.md index c888f7d09344a..04d01857d0102 100644 --- a/docs/csharp/tutorials/nullable-reference-types.md +++ b/docs/csharp/tutorials/nullable-reference-types.md @@ -19,7 +19,7 @@ In this tutorial, you'll learn how to: ## Prerequisites -You'll need to set up your machine to run .NET, including the C# compiler. The C# compiler is available with [Visual Studio 2022](https://visualstudio.microsoft.com/downloads), or the [.NET SDK](https://dotnet.microsoft.com/download/dotnet). +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET CLI. diff --git a/docs/csharp/tutorials/patterns-objects.md b/docs/csharp/tutorials/patterns-objects.md index 4bee55f93a004..b6b81678b6108 100644 --- a/docs/csharp/tutorials/patterns-objects.md +++ b/docs/csharp/tutorials/patterns-objects.md @@ -17,7 +17,7 @@ In this tutorial, you learn how to: ## Prerequisites -You need to set up your machine to run .NET. Download [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or the [.NET SDK](https://dotnet.microsoft.com/download). +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Build a simulation of a canal lock diff --git a/docs/csharp/tutorials/records.md b/docs/csharp/tutorials/records.md index c2777a6e2d85e..f7e3e21f065a1 100644 --- a/docs/csharp/tutorials/records.md +++ b/docs/csharp/tutorials/records.md @@ -17,7 +17,7 @@ In this tutorial, you learn how to: ## Prerequisites -You need to set up your machine to run .NET 6 or later. The C# compiler is available with [Visual Studio 2022](https://visualstudio.microsoft.com/vs) or the [.NET SDK](https://dotnet.microsoft.com/download). +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Characteristics of records diff --git a/docs/csharp/tutorials/top-level-statements.md b/docs/csharp/tutorials/top-level-statements.md index ca6738e43cbaf..9449895c66863 100644 --- a/docs/csharp/tutorials/top-level-statements.md +++ b/docs/csharp/tutorials/top-level-statements.md @@ -15,7 +15,7 @@ In this tutorial, you learn how to: ## Prerequisites -You need to set up your machine to run .NET 6 or later. The C# compiler is available starting with [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or [.NET SDK](https://dot.net/get-dotnet6). +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET CLI. diff --git a/docs/csharp/tutorials/working-with-linq.md b/docs/csharp/tutorials/working-with-linq.md index e5c1fac8d9ca2..1d9dfb0f9d36b 100644 --- a/docs/csharp/tutorials/working-with-linq.md +++ b/docs/csharp/tutorials/working-with-linq.md @@ -26,7 +26,7 @@ This tutorial has multiple steps. After each step, you can run the application a ## Prerequisites -You’ll need to set up your machine to run .NET core. You can find the installation instructions on the [.NET Core Download](https://dotnet.microsoft.com/download) page. You can run this application on Windows, Ubuntu Linux, or OS X, or in a Docker container. You’ll need to install your favorite code editor. The descriptions below use [Visual Studio Code](https://code.visualstudio.com/) which is an open source, cross-platform editor. However, you can use whatever tools you are comfortable with. +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Create the Application diff --git a/docs/csharp/whats-new/tutorials/primary-constructors.md b/docs/csharp/whats-new/tutorials/primary-constructors.md index a1e819f4ffce3..37f7329191b66 100644 --- a/docs/csharp/whats-new/tutorials/primary-constructors.md +++ b/docs/csharp/whats-new/tutorials/primary-constructors.md @@ -18,7 +18,7 @@ In this tutorial, you will learn: ## Prerequisites -You need to set up your machine to run .NET 8 or later, including the C# 12 or later compiler. The C# 12 compiler is available starting with [Visual Studio 2022 version 17.7](https://visualstudio.microsoft.com/vs) or the [.NET 8 SDK](https://dotnet.microsoft.com/download). +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic.md)] ## Primary constructors diff --git a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md b/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md index bcc76592bdf81..f1811e3b1260b 100644 --- a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md +++ b/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md @@ -18,7 +18,7 @@ In this tutorial, you'll learn how to: ## Prerequisites -You'll need to set up your machine to run .NET 7, which supports C# 11. The C# 11 compiler is available starting with [Visual Studio 2022, version 17.3](https://visualstudio.microsoft.com/downloads/) or the [.NET 7 SDK](https://dotnet.microsoft.com/download). +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic.md)] ## Static abstract interface methods diff --git a/docs/machine-learning/how-to-guides/install-model-builder.md b/docs/machine-learning/how-to-guides/install-model-builder.md index 9320b0467eb1b..896e3636458b7 100644 --- a/docs/machine-learning/how-to-guides/install-model-builder.md +++ b/docs/machine-learning/how-to-guides/install-model-builder.md @@ -15,8 +15,7 @@ Learn how to install ML.NET Model Builder to add machine learning to your .NET a ## Prerequisites -- Visual Studio 2022 or Visual Studio 2019. -- .NET Core 3.1 SDK or later. +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] ## Limitations diff --git a/docs/orleans/quickstarts/build-your-first-orleans-app.md b/docs/orleans/quickstarts/build-your-first-orleans-app.md index 87d1ccd1ffaac..02b249e1026ff 100644 --- a/docs/orleans/quickstarts/build-your-first-orleans-app.md +++ b/docs/orleans/quickstarts/build-your-first-orleans-app.md @@ -26,8 +26,7 @@ At the end of the quickstart, you have an app that creates and handles redirects # [Visual Studio Code](#tab/visual-studio-code) -- [.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) -- [Visual Studio Code](https://code.visualstudio.com/) +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] --- diff --git a/docs/standard/commandline/get-started-tutorial.md b/docs/standard/commandline/get-started-tutorial.md index 6e5f6e4ef8655..ce4f2f93d370d 100644 --- a/docs/standard/commandline/get-started-tutorial.md +++ b/docs/standard/commandline/get-started-tutorial.md @@ -31,8 +31,7 @@ In this tutorial, you learn how to: ## Prerequisites -* A code editor, such as [Visual Studio Code](https://code.visualstudio.com/) with the [C# extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp). -* The [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0). +[!INCLUDE [Prerequisites](../../../includes/prerequisites-basic.md)] Or diff --git a/includes/prerequisites-basic-winget.md b/includes/prerequisites-basic-winget.md new file mode 100644 index 0000000000000..c7d0bde509d88 --- /dev/null +++ b/includes/prerequisites-basic-winget.md @@ -0,0 +1,24 @@ +--- +author: BillWagner +ms.author: wiwagn +ms.topic: include +ms.date: 03/18/2025 +--- + +- The latest [.NET SDK](https://dotnet.microsoft.com/download) +- [Visual Studio Code](https://code.visualstudio.com) editor +- The [C# DevKit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) + +### Installation instructions + +On Windows, this [WinGet configuration file](https://builds.dotnet.microsoft.com/dotnet/install/dotnet_basic_config_docs.winget) to install all prerequisites. If you already have something installed, WinGet will skip that step. + +1. Download the file and double-click to run it. +1. Read the license agreement, type y, and select Enter when prompted to accept. +1. Be on the lookout for a flashing User Account Control (UAC) prompt in your Windows Taskbar, you may need to require administrator-level permissions to install. + +On other platforms, you need to install each of these components separately. + +1. Download the recommended installer from the [.NET SDK download page](https://dotnet.microsoft.com/download)and double-click to run it. The download page detects your platform and recommends the latest installer for your platform. +1. Download the latest installer from the [Visual Studio Code](https://code.visualstudio.com) home page and double click to run it. That page also detects your platform and the link should be correct for your system. +1. Click the "Install" button on the [C# DevKit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension page. That opens Visual Studio code, and asks if you want to install or enable the extension. Select "install". diff --git a/includes/prerequisites-basic.md b/includes/prerequisites-basic.md new file mode 100644 index 0000000000000..7e294467df41f --- /dev/null +++ b/includes/prerequisites-basic.md @@ -0,0 +1,10 @@ +--- +author: BillWagner +ms.author: wiwagn +ms.topic: include +ms.date: 03/18/2025 +--- + +- The latest [.NET SDK](https://dotnet.microsoft.com/download) +- [Visual Studio Code](https://code.visualstudio.com) editor +- The [C# DevKit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit)