diff --git a/.github/ISSUE_TEMPLATE/customer-feedback.yml b/.github/ISSUE_TEMPLATE/customer-feedback.yml index 9a7ef031900f..ac66b8d7d973 100644 --- a/.github/ISSUE_TEMPLATE/customer-feedback.yml +++ b/.github/ISSUE_TEMPLATE/customer-feedback.yml @@ -44,4 +44,11 @@ body: required: true attributes: label: Article author - + - type: textarea + id: metadata + validations: + required: false + attributes: + label: Metadata + description: >- + Documentation metadata will be applied here diff --git a/.github/policies/close-issues.yml b/.github/policies/close-issues.yml new file mode 100644 index 000000000000..da7d8071bac2 --- /dev/null +++ b/.github/policies/close-issues.yml @@ -0,0 +1,44 @@ +name: Close issues +description: Close issues based on label +resource: repository +where: +configuration: + resourceManagementConfiguration: + scheduledSearches: + - frequencies: + - daily: + time: 12:00 + filters: + - isIssue + - isOpen + - hasLabel: + label: needs-more-info + - noActivitySince: + days: 14 + actions: + - addReply: + reply: This issue has been automatically closed due to no response from the original author. Feel free to reopen it if you have more information that can help us investigate the issue further. + - closeIssue + + eventResponderTasks: + - description: Remove needs-more-info label when author comments on issue + if: + - payloadType: Issue_Comment + - isAction: + action: Created + - isActivitySender: + issueAuthor: True + - hasLabel: + label: needs-more-info + - isOpen + then: + - removeLabel: + label: needs-more-info + + - description: Close issues labeled 'code-of-conduct' + if: + - payloadType: Issues + - hasLabel: + label: code-of-conduct + then: + - closeIssue diff --git a/.github/policies/issueManagement-emptyIssue.yml b/.github/policies/issueManagement-emptyIssue.yml new file mode 100644 index 000000000000..b2ab7705f633 --- /dev/null +++ b/.github/policies/issueManagement-emptyIssue.yml @@ -0,0 +1,25 @@ +id: issueManagement.emptyIssue +name: GitOps.EmptyIssue +description: Checks for an issue created via learn that has an empty description from the template. +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: Close an issue created with the learn template that has an empty body. + if: + - payloadType: Issues + - bodyContains: + pattern: '### Description[\n\r]+\[Enter feedback here\][\n\r]+###' + isRegex: true + then: + - addLabel: 'needs-more-info' + - removeLabel: ':watch: Not Triaged' + - closeIssue + + triggerOnOwnActions: false + +onFailure: +onSuccess: diff --git a/.github/policies/issueManagement-notTriaged.yml b/.github/policies/issueManagement-notTriaged.yml new file mode 100644 index 000000000000..67af06d5b1d5 --- /dev/null +++ b/.github/policies/issueManagement-notTriaged.yml @@ -0,0 +1,54 @@ +id: issueManagement.notTriaged +name: GitOps.NotTriagedHandler +description: Ensures the Not Triaged label is added or removed when appropriate +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: >- + Add "not triaged" label when: + * Issue is opened + * Issue is reopened + * 'needs-more-info' label removed + if: + - payloadType: Issues + - or: + + - or: + - isAction: + action: Opened + - isAction: + action: Reopened + + - labelRemoved: + label: 'needs-more-info' + then: + - addLabel: ':watch: Not Triaged' + triggerOnOwnActions: false + + - description: >- + Remove "not triaged" label when: + * Issue author closes the issue + * reQUEST label is added + if: + - payloadType: Issues + - hasLabel: + label: ':watch: Not Triaged' + - or: + - and: + - isAction: + action: Closed + - isActivitySender: + issueAuthor: true + + - labelAdded: + label: 'reQUEST' + then: + - removeLabel: ':watch: Not Triaged' + triggerOnOwnActions: false + +onFailure: +onSuccess: diff --git a/.github/policies/labelAdded-areaLabels.yml b/.github/policies/labelAdded-areaLabels.yml new file mode 100644 index 000000000000..21463fdf4789 --- /dev/null +++ b/.github/policies/labelAdded-areaLabels.yml @@ -0,0 +1,32 @@ +id: labelAdded.areaLabels +name: GitOps.AreaLabelHandler +description: Handles when specific area labels are added +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: >- + When the label "grpc/subsvc" is added to an issue + * Add label "gRPC" + if: + - payloadType: Issues + - labelAdded: + label: 'grpc/subsv' + then: + - addLabel: 'gRPC' + + - description: >- + When the label "aspnetcore-signalr/subsvc" is added to an issue + * Add label "SignalR" + if: + - payloadType: Issues + - labelAdded: + label: 'aspnetcore-signalr/subsvc' + then: + - addLabel: 'SignalR' + +onFailure: +onSuccess: diff --git a/.github/policies/labelAdded-mapQuest.yml b/.github/policies/labelAdded-mapQuest.yml new file mode 100644 index 000000000000..c760b7c7fe33 --- /dev/null +++ b/.github/policies/labelAdded-mapQuest.yml @@ -0,0 +1,25 @@ +id: labelAdded.mapQuest +name: GitOps.MapQuestHandler +description: Handles when "mapQUEST" label is added +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: >- + When the label "mapQUEST" is added to an issue + * Remove label "mapQUEST" + if: + - or: + - payloadType: Issues + - payloadType: Pull_Request + + - labelAdded: + label: 'mapQUEST' + then: + - removeLabel: 'mapQUEST' + triggerOnOwnActions: true +onFailure: +onSuccess: diff --git a/.github/policies/pullRequestManagement-labelFiles.yml b/.github/policies/pullRequestManagement-labelFiles.yml new file mode 100644 index 000000000000..a6d8e6607dc9 --- /dev/null +++ b/.github/policies/pullRequestManagement-labelFiles.yml @@ -0,0 +1,56 @@ +id: pullRequestManagement.labelFiles +name: GitOps.PullRequestLabelFiles +description: Checks the files touched by a pull request and assigns a reviewer +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: Modify PRs that touch certain files + triggerOnOwnActions: false + if: + - payloadType: Pull_Request + - or: + - isAction: + action: Opened + - isAction: + action: Synchronize + - not: + targetsBranch: + branch: live + then: + - if: + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/blazor/hybrid/.*' + then: + - requestReview: + reviewer: guardrex + - addLabel: + label: 'blazor-hybrid/subsvc' + - if: + - or: + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/blazor/.*' + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/client-side/dotnet-interop/index.md' + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/client-side/dotnet-interop/wasm-browser-app.md' + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/mvc/views/tag-helpers/built-in/component-tag-helper.md' + - filesMatchPattern: + matchAny: true + pattern: '(?i).*/mvc/views/tag-helpers/built-in/persist-component-state.md' + then: + - requestReview: + reviewer: guardrex + - addLabel: + label: 'blazor/subsvc' +onFailure: +onSuccess: diff --git a/.github/workflows/issue-processing.yml b/.github/workflows/issue-processing.yml deleted file mode 100644 index bae690717316..000000000000 --- a/.github/workflows/issue-processing.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Issue processing -on: - issues: - types: - - labeled -jobs: - process-grpc-issue: - if: github.event.label.name == 'grpc/subsvc' - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/github-script@v6 - with: - script: | - await github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ["gRPC"] - }) - - process-signalr-issue: - if: github.event.label.name == 'aspnetcore-signalr/subsvc' - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/github-script@v6 - with: - script: | - await github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ["SignalR"] - }) diff --git a/.repoman.yml b/.repoman.yml index 9236e3ba4c15..71cd1e437aef 100644 --- a/.repoman.yml +++ b/.repoman.yml @@ -1,4 +1,4 @@ -revision: 5 +revision: 6 schema-version: 5 owner-ms-alias: adegeo @@ -10,29 +10,11 @@ config: ParserRegex: "^\\* (.*): (.*)$" ContentUrlRegex: - - "### Page URL\n\n(.*)" + - "### Page URL\n\n(.*)" issues: opened: - # New issue opened, add Not Triaged - - labels-add: [":watch: Not Triaged"] - - # Try to detect an empty issue - - check: - - type: comment-body - value: "### Description[\\n\\r]+\\[Enter feedback here\\][\\n\\r]+###" - pass: - - labels-add: ["needs-more-info"] - - labels-remove: [":watch: Not Triaged"] - - close - - # default for doc comment - - check: - - type: metadata-exists - pass: - - labels-add: ["Source - Docs.ms"] - - svc_subsvc_labels: true # Add links to related issues if it's a doc issue - check: @@ -42,14 +24,12 @@ issues: pass: - link-related-issues - labeled: - - # Temporary label to mark issues as updated for Quest. The label is instantly removed + # If it's an issue from docs feedback, add svc/subsvc and source labels. - check: - - type: query - value: "length(Issue.Labels[?Name == 'mapQuest']) != `0`" + - type: metadata-exists pass: - - labels-remove: ["mapQuest"] + - labels-add: ["Source - Docs.ms"] + - svc_subsvc_labels: true projects_v2_item: diff --git a/README.md b/README.md index a7f624ec7d3c..c7783973251d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ This repository contains the [ASP.NET Core documentation](https://learn.microsoft.com/aspnet/core/introduction-to-aspnet-core). See the [Contributing Guide](CONTRIBUTING.md) and the [issues list](https://github.com/dotnet/AspNetCore.Docs/issues) if you would like to help. -To provide comments and suggestions on [learn.microsoft.com](https://learn.microsoft.com) site functionality, open an issue in the [`MicrosoftDocs/feedback` GitHub repository](https://github.com/MicrosoftDocs/feedback). - ASP.NET 4.x documentation changes are made in the [`dotnet/AspNetDocs` GitHub repository](https://github.com/dotnet/AspNetDocs). ## How to open an issue diff --git a/aspnetcore/blazor/blazor-ef-core.md b/aspnetcore/blazor/blazor-ef-core.md index 03b0ef4930ab..cd535e63103e 100644 --- a/aspnetcore/blazor/blazor-ef-core.md +++ b/aspnetcore/blazor/blazor-ef-core.md @@ -46,8 +46,6 @@ For Microsoft Azure services, we recommend using *managed identities*. Managed i The sample app was built as a reference for server-side Blazor apps that use EF Core. The sample app includes a grid with sorting and filtering, delete, add, and update operations. -The sample demonstrates use of EF Core to handle optimistic concurrency. However, [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens) aren't supported for SQLite databases, which is the database provider for the sample app. To demonstrate concurrency with the sample app, adopt a different database provider that supports database-generated concurrency tokens (for example, the [SQL Server provider](/ef/core/providers/sql-server)). - :::moniker range=">= aspnetcore-8.0" [View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)): Select the folder that matches the version of .NET that you're adopting. Within the version folder, access the sample named `BlazorWebAppEFCore`. @@ -60,7 +58,58 @@ The sample demonstrates use of EF Core to handle optimistic concurrency. However :::moniker-end -The sample uses a local [SQLite](https://www.sqlite.org/index.html) database so that it can be used on any platform. The sample also configures database logging to show the SQL queries that are generated. This is configured in `appsettings.Development.json`: +### Use the sample with SQLite + +The sample uses a local [SQLite](https://www.sqlite.org/index.html) database so that it can be used on any platform. + +The sample demonstrates use of EF Core to handle optimistic concurrency. However, [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens) aren't supported for SQLite databases, which is the database provider for the sample app. To demonstrate concurrency with the sample app, adopt a different database provider that supports database-generated concurrency tokens (for example, the [SQL Server provider](/ef/core/providers/sql-server)). You can adopt SQL Server for the sample app by following the guidance in the next section, *Use the sample with SQL Server and optimistic concurrency*. + +### Use the sample with SQL Server and optimistic concurrency + +The sample demonstrates use of EF Core to handle optimistic concurrency but only for a database provider that uses [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens), which is a feature supported for SQL Server. To demonstrate concurrency with the sample app, the sample app can be converted from the SQLite provider to use the [SQL Server provider](/ef/core/providers/sql-server) with a new SQL Server database created using .NET scaffolding. + +Use the following guidance to adopt SQL Server for the sample app using Visual Studio. + +Open the `Program` file (`Program.cs`) and comment out the lines that add the database context factory with the SQLite provider: + +```diff +- builder.Services.AddDbContextFactory(opt => +- opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); ++ //builder.Services.AddDbContextFactory(opt => ++ // opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); +``` + +Save the `Program.cs` file. + +Right-click the project in **Solution Explorer** and select **Add** > **New Scaffolded Item**. + +In the **Add New Scaffolded Item** dialog, select **Installed** > **Common** > **Blazor** > **Razor Component** > **Razor Components Using Entity Framework (CRUD)**. Select the **Add** button. + +In the **Add Razor Components Using Entity Framework (CRUD)** dialog, use the following settings: + +* **Template**: Use the default selection (**CRUD**). +* **Model class**: Select the `Contact` model from the dropdown list. +* **DbContext class**: Select the plus sign (`+`) and select **Add** using the default context class name generated by the scaffolder. +* **Database provider**: Use the default selection (**SQL Server**). + +Select **Add** to scaffold the model and create the SQL Server database. + +When the scaffolding operation completes, delete the generated context class from the `Data` folder (`Data/{PROJECT NAME}Context.cs`, where the `{PROJECT NAME}` placeholder is the project's name/namespace). + +Delete the `ContactPages` folder from the `Components/Pages` folder, which contains [QuickGrid](xref:blazor/components/quickgrid)-based pages for contact management. For a complete demonstration of QuickGrid-based pages for managing data, use the tutorial. + +Open the `Program` file (`Program.cs`) and find the line that scaffolding added to create a database context factory using the SQL Server provider. Change the context from the generated context class (deleted earlier) to the app's existing `ContactContext` class: + +```diff +- builder.Services.AddDbContextFactory(options => ++ builder.Services.AddDbContextFactory(options => +``` + +At this point, the app is using the SQL Server provider and a SQL Server database created for the `Contact` model class. Optimistic concurrency works using [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens) that are already implemented in the sample app's `ContactContext` class. + +### Database logging + +The sample also configures database logging to show the SQL queries that are generated. This is configured in `appsettings.Development.json`: :::moniker range=">= aspnetcore-9.0" diff --git a/aspnetcore/blazor/components/prerender.md b/aspnetcore/blazor/components/prerender.md index 7cf923522ba1..ebf870ccea0a 100644 --- a/aspnetcore/blazor/components/prerender.md +++ b/aspnetcore/blazor/components/prerender.md @@ -34,7 +34,7 @@ Consider the following `PrerenderedCounter1` counter component. The component se Run the app and inspect logging from the component. The following is example output. > [!NOTE] -> If the app adopts interactive (enhanced) routing and the page is reached via an internal navigation, prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter1` component to see the following output. +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter1` component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. > :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter1[0]"::: > :::no-loc text=" currentCount set to 41"::: @@ -101,7 +101,7 @@ The following counter component example persists counter state during prerenderi When the component executes, `currentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. > [!NOTE] -> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal navigation, prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter2` component to see the following output. +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter2` component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. > :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: > :::no-loc text=" currentCount set to 96"::: @@ -128,9 +128,23 @@ For components embedded into a page or view of a Razor Pages or MVC app, you mus ## Interactive routing and prerendering -Internal navigation for [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests. +When the `Routes` component doesn't define a render mode, the app is using per-page/component interactivity and navigation. Using per-page/component navigation, internal† navigation is handled by [enhanced routing](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) after the app becomes interactive. †*Internal* in this context means that the URL destination of the navigation event is a Blazor endpoint inside the app. -The service only works on the initial page load and not across [enhanced page navigation events](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). If the app performs a full (non-enhanced) navigation to a page utilizing persistent component state, the persisted state is made available for the app to use when it becomes interactive. But if an interactive circuit has already been established and an enhanced navigation is performed to a page that renders persisted component state, that state isn't made available in the existing circuit. The service isn't aware of enhanced navigation, and there's no mechanism to deliver state updates to components that are already running. +The service only works on the initial page load and not across internal enhanced page navigation events. + +If the app performs a full (non-enhanced) navigation to a page utilizing persistent component state, the persisted state is made available for the app to use when it becomes interactive. + +If an interactive circuit has already been established and an enhanced navigation is performed to a page utilizing persistent component state, the state *isn't made available in the existing circuit for the component to use*. There's no prerendering for the internal page request, and the service isn't aware that an enhanced navigation has occurred. There's no mechanism to deliver state updates to components that are already running on an existing circuit. The reason for this is that Blazor only supports passing state from the server to the client at the time the runtime initializes, not after the runtime has started. + +Additional work on the Blazor framework to address this scenario is under consideration for .NET 10 (November, 2025). For more information and community discussion of *unsupported workarounds*‡, see [Support persistent component state across enhanced page navigations (`dotnet/aspnetcore` #51584)](https://github.com/dotnet/aspnetcore/issues/51584). ‡Unsupported workarounds aren't sanctioned by Microsoft for use in Blazor apps. *Use third-party packages, approaches, and code at your own risk.* + +Disabling enhanced navigation, which reduces performance but also avoids the problem of loading state with for internal page requests, is covered in . + + ## Prerendering guidance diff --git a/aspnetcore/blazor/fundamentals/configuration.md b/aspnetcore/blazor/fundamentals/configuration.md index 83aa25d22d2b..62fd424799db 100644 --- a/aspnetcore/blazor/fundamentals/configuration.md +++ b/aspnetcore/blazor/fundamentals/configuration.md @@ -315,9 +315,63 @@ For more information on how background updates are handled by PWAs, see ( - builder.Configuration.GetSection("MyOptions")); +builder.Services.Configure( + builder.Configuration.GetSection("OptionsExample")); +``` + +The following Razor component retrieves the settings with the [`@inject`](xref:mvc/views/razor#inject) directive or [`[Inject]` attribute](xref:Microsoft.AspNetCore.Components.InjectAttribute). + +`Options.razor`: + +```razor +@page "/options" +@using Microsoft.Extensions.Options +@inject IOptions? OptionsExample1 + +

Options

+ +

+ @inject approach +

+ +
    +
  • @OptionsExample1?.Value.Option1
  • +
  • @OptionsExample1?.Value.Option2
  • +
+ +

+ [Inject] approach +

+ +
    +
  • @OptionsExample2?.Value.Option1
  • +
  • @OptionsExample2?.Value.Option2
  • +
+ +@code { + [Inject] + public IOptions? OptionsExample2 { get; set; } +} ``` Not all of the ASP.NET Core Options features are supported in Razor components. For example, and configuration is supported, but recomputing option values for these interfaces isn't supported outside of reloading the app by either requesting the app in a new browser tab or selecting the browser's reload button. Merely calling [`StateHasChanged`](xref:blazor/components/lifecycle#state-changes-statehaschanged) doesn't update snapshot or monitored option values when the underlying configuration changes. diff --git a/aspnetcore/fundamentals/static-files.md b/aspnetcore/fundamentals/static-files.md index 79a0f98ecfbe..a70eb721adf9 100644 --- a/aspnetcore/fundamentals/static-files.md +++ b/aspnetcore/fundamentals/static-files.md @@ -49,7 +49,9 @@ Creating performant web apps requires optimizing asset delivery to the browser. * Use a [CDN](/microsoft-365/enterprise/content-delivery-networks?view=o365-worldwide&preserve-view=true) to serve the assets closer to the user. * Minimize the size of assets served to the browser. This optimization doesn't include minification. - are routing endpoint conventions that optimize the delivery of static assets in an app. It's designed to work with all UI frameworks, including Blazor, Razor Pages, and MVC. +: +* Integrates the information gathered about static web assets during the build or publish process with a runtime library that processes this information to optimize file serving to the browser. +* Are routing endpoint conventions that optimize the delivery of static assets in an app. It's designed to work with all UI frameworks, including Blazor, Razor Pages, and MVC. [`UseStaticFiles`](/dotnet/api/microsoft.aspnetcore.builder.staticfileextensions.usestaticfiles) also serves static files, but it doesn't provide the same level of optimization as `MapStaticAssets`. For a comparison of `UseStaticFiles` and `MapStaticAssets`, see [Optimizing static web asset delivery ](xref:aspnetcore-9#optimizing-static-web-asset-delivery). diff --git a/aspnetcore/grpc/troubleshoot.md b/aspnetcore/grpc/troubleshoot.md index c0ee84eb844d..4d6c284006a5 100644 --- a/aspnetcore/grpc/troubleshoot.md +++ b/aspnetcore/grpc/troubleshoot.md @@ -15,7 +15,7 @@ By [James Newton-King](https://twitter.com/jamesnk) [!INCLUDE[](~/includes/not-latest-version.md)] -:::moniker range="= aspnetcore-8.0" +:::moniker range=">= aspnetcore-8.0" This document discusses commonly encountered problems when developing gRPC apps on .NET. diff --git a/aspnetcore/razor-pages/ui-class.md b/aspnetcore/razor-pages/ui-class.md index 8f7067942b14..32e9e60afeb0 100644 --- a/aspnetcore/razor-pages/ui-class.md +++ b/aspnetcore/razor-pages/ui-class.md @@ -122,26 +122,17 @@ In the following example, the `lib.css` stylesheet in the `wwwroot` folder isn't To include TypeScript files in an RCL: -1. Reference the [`Microsoft.TypeScript.MSBuild`](https://www.nuget.org/packages/Microsoft.TypeScript.MSBuild) NuGet package in the project. +* Reference the [`Microsoft.TypeScript.MSBuild`](https://www.nuget.org/packages/Microsoft.TypeScript.MSBuild) NuGet package in the project. [!INCLUDE[](~/includes/package-reference.md)] -1. Place the TypeScript files (`.ts`) outside of the `wwwroot` folder. For example, place the files in a `Client` folder. +* Place the TypeScript files (`.ts`) outside of the `wwwroot` folder. For example, place the files in a `Client` folder. +* Add the following markup to the project file: + * Configure the TypeScript build output for the `wwwroot` folder with the `TypescriptOutDir` property. + * Include the TypeScript target as a dependency of the `PrepareForBuildDependsOn` target. + * Remove the output in the `wwwroot folder`. -1. Configure the TypeScript build output for the `wwwroot` folder. Set the `TypescriptOutDir` property inside of a `PropertyGroup` in the project file: - - ```xml - wwwroot - ``` - -1. Include the TypeScript target as a dependency of the `PrepareForBuildDependsOn` target by adding the following target inside of a `PropertyGroup` in the project file: - - ```xml - - CompileTypeScript; - GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn) - - ``` +[!code-xml[](~/razor-pages/ui-class/remove.xml?highlight=6-10,14)] ### Consume content from a referenced RCL diff --git a/aspnetcore/razor-pages/ui-class/remove.xml b/aspnetcore/razor-pages/ui-class/remove.xml new file mode 100644 index 000000000000..7b98ee50acc5 --- /dev/null +++ b/aspnetcore/razor-pages/ui-class/remove.xml @@ -0,0 +1,17 @@ + + + + + // Markup removed for brevity. + wwwroot + + CompileTypeScriptWithTSConfig; + GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn) + + + + + + + +