Skip to content

Commit 8d20f9e

Browse files
authored
Merge pull request #35391 from dotnet/main
2 parents 798d4fa + 3cd06be commit 8d20f9e

File tree

10 files changed

+150
-168
lines changed

10 files changed

+150
-168
lines changed

aspnetcore/client-side/bundling-and-minification.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: wadepickett
44
description: Learn how to optimize static resources in an ASP.NET Core web application by applying bundling and minification techniques.
55
ms.author: wpickett
66
ms.custom: mvc
7-
ms.date: 03/14/2021
7+
ms.date: 05/08/2025
88
uid: client-side/bundling-and-minification
99
---
1010
# Bundle and minify static assets in ASP.NET Core
@@ -21,11 +21,11 @@ Bundling and minification primarily improve the first page request load time. On
2121

2222
### Bundling
2323

24-
Bundling combines multiple files into a single file. Bundling reduces the number of server requests that are necessary to render a web asset, such as a web page. You can create any number of individual bundles specifically for CSS, JavaScript, etc. Fewer files mean fewer HTTP requests from the browser to the server or from the service providing your application. This results in improved first page load performance.
24+
Bundling combines multiple files into a single file. Bundling reduces the number of server requests necessary to render a web asset, such as a web page. You can create any number of individual bundles specifically for CSS, JavaScript, etc. Fewer files mean fewer HTTP requests from the browser to the server or from the service providing your application. This results in improved first page load performance.
2525

2626
### Minification
2727

28-
Minification removes unnecessary characters from code without altering functionality. The result is a significant size reduction in requested assets (such as CSS, images, and JavaScript files). Common side effects of minification include shortening variable names to one character and removing comments and unnecessary whitespace.
28+
Minification removes unnecessary characters from code without altering functionality. The result is a significant size reduction in requested assets (such as CSS, images, and JavaScript files). Common effects of minification include shortening variable names to one character and removing comments and unnecessary whitespace.
2929

3030
Consider the following JavaScript function:
3131

@@ -72,9 +72,7 @@ The test app used to generate the figures in the preceding table demonstrates ty
7272

7373
## Choose a bundling and minification strategy
7474

75-
ASP.NET Core is compatible with WebOptimizer, an open-source bundling and minification solution. For set up instructions and sample projects, see [WebOptimizer](https://github.com/ligershark/WebOptimizer). ASP.NET Core doesn't provide a native bundling and minification solution.
76-
77-
Third-party tools, such as [Gulp](https://gulpjs.com) and [Webpack](https://webpack.js.org), provide workflow automation for bundling and minification, as well as linting and image optimization. By using bundling and minification, the minified files are created prior to the app's deployment. Bundling and minifying before deployment provides the advantage of reduced server load. However, it's important to recognize that bundling and minification increases build complexity and only works with static files.
75+
ASP.NET Core doesn't provide a native bundling and minification solution. Third-party tools, such as [Gulp](https://gulpjs.com) and [Webpack](https://webpack.js.org), provide workflow automation for bundling and minification, as well as linting and image optimization. Bundling and minifying before deployment provides the advantage of reduced server load. However, bundling and minification increase build complexity and only work with static files.
7876

7977
## Environment-based bundling and minification
8078

aspnetcore/fundamentals/minimal-apis/responses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ The following method does not compile, because `TypedResults.Ok` and `TypedResul
9797

9898
:::code language="csharp" source="~/tutorials/min-web-api/samples/7.x/todo/Program.cs" id="snippet_111":::
9999

100-
To use `TypedResults`, the return type must be fully declared, which when asynchronous requires the `Task<>` wrapper. Using `TypedResults` is more verbose, but that's the trade-off for having the type information be statically available and thus capable of self-describing to OpenAPI:
100+
To use `TypedResults`, the return type must be fully declared; when the method is asynchronous, the declaration requires wrapping the return type in a `Task<>`. Using `TypedResults` is more verbose, but that's the trade-off for having the type information be statically available and thus capable of self-describing to OpenAPI:
101101

102102
:::code language="csharp" source="~/tutorials/min-web-api/samples/7.x/todo/Program.cs" id="snippet_1b":::
103103

aspnetcore/fundamentals/openapi/using-openapi-documents.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ The `Swashbuckle.AspNetCore.SwaggerUi` package provides a bundle of Swagger UI's
2525

2626
As a security best practice on limiting information disclosure, ***OpenAPI user interfaces (Swagger UI, ReDoc, Scalar) should only be enabled in development environments.*** For example, see [Swagger OAuth 2.0 configuration](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/).
2727

28+
Launch the app and navigate to `https://localhost:<port>/swagger` to view the Swagger UI.
29+
30+
To automatically launch the app at the Swagger UI URL using the `https` profile of `Properties/launchSettings.json`:
31+
32+
* Confirm that `launchBrowser` is enabled (`true`).
33+
* Set the `launchUrl` to `swagger`.
34+
35+
```json
36+
"launchBrowser": true,
37+
"launchUrl": "swagger",
38+
```
39+
2840
## Use Scalar for interactive API documentation
2941

3042
[Scalar](https://scalar.com/) is an open-source interactive document UI for OpenAPI. Scalar can integrate with the OpenAPI endpoint provided by ASP.NET Core. To configure Scalar, install the `Scalar.AspNetCore` package.
@@ -33,6 +45,16 @@ As a security best practice on limiting information disclosure, ***OpenAPI user
3345

3446
Launch the app and navigate to `https://localhost:<port>/scalar/v1` to view the Scalar UI.
3547

48+
To automatically launch the app at the Scalar UI URL using the `https` profile of `Properties/launchSettings.json`:
49+
50+
* Confirm that `launchBrowser` is enabled (`true`).
51+
* Set the `launchUrl` to `scalar/v1`.
52+
53+
```json
54+
"launchBrowser": true,
55+
"launchUrl": "scalar/v1",
56+
```
57+
3658
## Lint generated OpenAPI documents with Spectral
3759

3860
[Spectral](https://stoplight.io/open-source/spectral) is an open-source OpenAPI document linter. Spectral can be incorporated into an app build to verify the quality of generated OpenAPI documents. Install Spectral according to the [package installation directions](https://github.com/stoplightio/spectral#-installation).

aspnetcore/performance/caching/hybrid.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ Notice that the inline interpolated string syntax (`$"..."` in the preceding exa
8686

8787
* Keys can be restricted to valid maximum lengths. For example, the default `HybridCache` implementation (via `AddHybridCache(...)`) restricts keys to 1024 characters by default. That number is configurable via `HybridCacheOptions.MaximumKeyLength`, with longer keys bypassing the cache mechanisms to prevent saturation.
8888
* Keys must be valid Unicode sequences. If invalid Unicode sequences are passed, the behavior is undefined.
89-
* When using an out-of-process secondary cache such as `IDistributedCache`, the specific backend implementation may impose additional restrictions. As a hypothetical example, a particular backend might use case-insensitive key logic. The default `HybridCache` (via `AddHybridCache(...)`) detects this scenario to prevent confusion attacks, however it may still result in conflicting keys becoming overwritten or evicted sooner than expected.
89+
* When using an out-of-process secondary cache such as `IDistributedCache`, the backend implementation may impose additional restrictions. As a hypothetical example, a particular backend might use case-insensitive key logic. The default `HybridCache` (via `AddHybridCache(...)`) detects this scenario to prevent confusion attacks or alias attacks (using bitwise string equality). However, this scenario might still result in conflicting keys becoming overwritten or evicted sooner than expected.
9090

9191
### The alternative `GetOrCreateAsync` overload
9292

@@ -117,7 +117,16 @@ Set tags when calling `GetOrCreateAsync`, as shown in the following example:
117117

118118
Remove all entries for a specified tag by calling <xref:Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveByTagAsync%2A> with the tag value. An overload lets you specify a collection of tag values.
119119

120-
When an entry is removed, it is removed from both the primary and secondary caches.
120+
Neither `IMemoryCache` nor `IDistributedCache` has direct support for the concept of tags, so tag-based invalidation is a *logical* operation only. It does not actively remove values from either local or distributed cache. Instead, it ensures that when receiving data with such tags, the data will be treated as a cache-miss from both the local and remote cache. The values will expire from `IMemoryCache` and `IDistributedCache` in the usual way based on the configured lifetime.
121+
122+
## Removing all cache entries
123+
124+
The asterisk tag (`*`) is reserved as a wildcard and is disallowed against individual values. Calling `RemoveByTagAsync("*")` has the effect of invalidating *all* `HybridCache` data, even data that does not have any tags. As with individual tags, this is a *logical* operation, and individual values continue to exist until they expire naturally. Glob-style matches are not supported. For example, you can't use `RemoveByTagAsync("foo*")` to remove everything starting with `foo`.
125+
126+
### Additional tag considerations
127+
128+
* The system doesn't limit the number of tags you can use, but large sets of tags might negatively impact performance.
129+
* Tags can't be empty, just whitespace, or the reserved value `*`.
121130

122131
## Options
123132

aspnetcore/test/integration-tests.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Integration tests ensure that an app's components function correctly at a level
1616

1717
:::moniker range=">= aspnetcore-10.0"
1818

19-
This article assumes a basic understanding of unit tests. If unfamiliar with test concepts, see the [Unit Testing in .NET Core and .NET Standard](/dotnet/core/testing/) article and its linked content.
19+
This article assumes a basic understanding of unit tests. If unfamiliar with test concepts, see the [Testing in .NET](/dotnet/core/testing/) article and its linked content.
2020

2121
[View or download sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/test/integration-tests/10.x/IntegrationTestsSample) ([how to download](xref:index#how-to-download-a-sample))
2222

@@ -325,4 +325,4 @@ The SUT's database context is registered in `Program.cs`. The test app's `builde
325325
[!INCLUDE[](~/test/integration-tests/includes/integration-tests5.md)]
326326
[!INCLUDE[](~/test/integration-tests/includes/integration-tests7.md)]
327327
[!INCLUDE[](~/test/integration-tests/includes/integration-tests8.md)]
328-
[!INCLUDE[](~/test/integration-tests/includes/integration-tests9.md)]
328+
[!INCLUDE[](~/test/integration-tests/includes/integration-tests9.md)]

aspnetcore/test/troubleshoot.md

Lines changed: 4 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: tdykstra
44
description: Understand and troubleshoot warnings and errors with ASP.NET Core projects.
55
ms.author: tdykstra
66
ms.custom: mvc
7-
ms.date: 07/10/2019
7+
ms.date: 5/2/2025
88
uid: test/troubleshoot
99
---
1010
# Troubleshoot and debug ASP.NET Core projects
@@ -77,87 +77,9 @@ If an app is capable of responding to requests, you can obtain the following dat
7777

7878
Place the following [middleware](xref:fundamentals/middleware/index#create-a-middleware-pipeline-with-iapplicationbuilder) code at the beginning of the `Startup.Configure` method's request processing pipeline. The environment is checked before the middleware is run to ensure that the code is only executed in the Development environment.
7979

80-
To obtain the environment, use either of the following approaches:
81-
82-
* Inject the `IHostingEnvironment` into the `Startup.Configure` method and check the environment with the local variable. The following sample code demonstrates this approach.
83-
84-
* Assign the environment to a property in the `Startup` class. Check the environment using the property (for example, `if (Environment.IsDevelopment())`).
85-
86-
```csharp
87-
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
88-
IConfiguration config)
89-
{
90-
if (env.IsDevelopment())
91-
{
92-
app.Run(async (context) =>
93-
{
94-
var sb = new StringBuilder();
95-
var nl = System.Environment.NewLine;
96-
var rule = string.Concat(nl, new string('-', 40), nl);
97-
var authSchemeProvider = app.ApplicationServices
98-
.GetRequiredService<IAuthenticationSchemeProvider>();
99-
100-
sb.Append($"Request{rule}");
101-
sb.Append($"{DateTimeOffset.Now}{nl}");
102-
sb.Append($"{context.Request.Method} {context.Request.Path}{nl}");
103-
sb.Append($"Scheme: {context.Request.Scheme}{nl}");
104-
sb.Append($"Host: {context.Request.Headers["Host"]}{nl}");
105-
sb.Append($"PathBase: {context.Request.PathBase.Value}{nl}");
106-
sb.Append($"Path: {context.Request.Path.Value}{nl}");
107-
sb.Append($"Query: {context.Request.QueryString.Value}{nl}{nl}");
108-
109-
sb.Append($"Connection{rule}");
110-
sb.Append($"RemoteIp: {context.Connection.RemoteIpAddress}{nl}");
111-
sb.Append($"RemotePort: {context.Connection.RemotePort}{nl}");
112-
sb.Append($"LocalIp: {context.Connection.LocalIpAddress}{nl}");
113-
sb.Append($"LocalPort: {context.Connection.LocalPort}{nl}");
114-
sb.Append($"ClientCert: {context.Connection.ClientCertificate}{nl}{nl}");
115-
116-
sb.Append($"Identity{rule}");
117-
sb.Append($"User: {context.User.Identity.Name}{nl}");
118-
var scheme = await authSchemeProvider
119-
.GetSchemeAsync(IISDefaults.AuthenticationScheme);
120-
sb.Append($"DisplayName: {scheme?.DisplayName}{nl}{nl}");
121-
122-
sb.Append($"Headers{rule}");
123-
foreach (var header in context.Request.Headers)
124-
{
125-
sb.Append($"{header.Key}: {header.Value}{nl}");
126-
}
127-
sb.Append(nl);
128-
129-
sb.Append($"WebSockets{rule}");
130-
if (context.Features.Get<IHttpUpgradeFeature>() != null)
131-
{
132-
sb.Append($"Status: Enabled{nl}{nl}");
133-
}
134-
else
135-
{
136-
sb.Append($"Status: Disabled{nl}{nl}");
137-
}
138-
139-
sb.Append($"Configuration{rule}");
140-
foreach (var pair in config.AsEnumerable())
141-
{
142-
sb.Append($"{pair.Path}: {pair.Value}{nl}");
143-
}
144-
sb.Append(nl);
145-
146-
sb.Append($"Environment Variables{rule}");
147-
var vars = System.Environment.GetEnvironmentVariables();
148-
foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key,
149-
StringComparer.OrdinalIgnoreCase))
150-
{
151-
var value = vars[key];
152-
sb.Append($"{key}: {value}{nl}");
153-
}
154-
155-
context.Response.ContentType = "text/plain";
156-
await context.Response.WriteAsync(sb.ToString());
157-
});
158-
}
159-
}
160-
```
80+
Get the environment from the `Environment` property of `WebApplication`. For example, `if (app.Environment.IsDevelopment())` as in the following sample code.
81+
82+
:::code language="csharp" source="~/test/troubleshoot/code/9.x/Program.cs" highlight="13-85":::
16183

16284
## Debug ASP.NET Core apps
16385

aspnetcore/test/troubleshoot/code/5.x/Program.cs

Lines changed: 0 additions & 75 deletions
This file was deleted.

0 commit comments

Comments
 (0)