Questi contenuti non sono ancora disponibili nella tua lingua.
One of the advantages of developing with Aspire is that it enables you to develop, test, and debug cloud-native apps locally. Inner-loop networking is a key aspect of Aspire that allows your apps to communicate with each other in your development environment. In this article, you learn how Aspire handles various networking scenarios with proxies, endpoints, endpoint configurations, and container networking.
The inner loop is the process of developing and testing your app locally before deploying it to a target environment. Aspire provides several tools and features to simplify and enhance the networking experience in the inner loop, such as:
Endpoints/Endpoint configurations: Endpoints are the connections between your app and the services it depends on, such as databases, message queues, or APIs. Endpoints provide information such as the service name, host port, scheme, and environment variable. Aspire can create endpoints automatically from resource configuration, and you can also add them explicitly by calling WithEndpoint.
Proxies: Aspire automatically launches a proxy for each proxied service binding you add to your app, and assigns a port for the proxy to listen on. The proxy then forwards the requests to the port that your app listens on, which might be different from the proxy port. This way, you can avoid port conflicts and access your app and services using consistent and predictable URLs.
Proxyless endpoints: Endpoints with IsProxied set to false connect directly to the resource instead of routing through an Aspire-managed proxy. Starting in Aspire 13.4, endpoints on persistent resources are proxyless by default. Proxyless endpoints must specify a target port so Aspire knows which port the resource listens on.
Container networks: Aspire creates and manages dedicated networks for container resources so containers can discover and communicate with each other during local development.
A service binding in Aspire involves two integrations: a service representing an external resource your app requires (for example, a database, message queue, or API), and a binding that establishes a connection between your app and the service and provides necessary information.
Aspire can create service bindings automatically from resource configuration, and you can create additional bindings explicitly by using WithEndpoint.
Upon creating a proxied binding, whether implicit or explicit, Aspire launches a lightweight reverse proxy on a specified port, handling routing and load balancing for requests from your app to the service. The proxy is an Aspire implementation detail, requiring no configuration or management concern.
To help visualize how endpoints work, consider the Aspire starter templates inner-loop networking diagram:
When you add one or more container resources, Aspire creates a dedicated container bridge network to enable service discovery between containers. This bridge network is a virtual network that lets containers communicate with each other and provides a DNS server for container-to-container service discovery using DNS names.
The network’s lifetime depends on the container resources:
If all containers have a session lifetime, the network is also session-based and is cleaned up when the AppHost process ends.
If any container has a persistent lifetime, the network is persistent and remains running after the AppHost process terminates. Aspire reuses this network on subsequent runs, allowing persistent containers to keep communicating even when the AppHost isn’t running.
Each AppHost instance gets its own network resources. The only differences are the network’s lifetime and name; service discovery works the same way for both.
Containers register themselves on the network using their resource name. Aspire uses this name for service discovery between containers. For example, a pgadmin container can connect to a database resource named postgres using postgres:5432.
By default, containers are accessible on the container network using their resource name as a DNS alias. For example, a container added with AddContainer("mydb", ...) is reachable at mydb:5432 from other containers.
Sometimes you need additional aliases—for example, when a third-party tool expects a specific hostname, or when migrating from an existing Docker Compose setup. Use WithContainerNetworkAlias to add custom DNS names:
Now other containers can connect to Redis using any of these names:
cache:6379 (default resource name)
redis-primary:6379 (custom alias)
session-store:6379 (custom alias)
When containers need to reach host-based services, Aspire uses the container tunnel to provide reliable connectivity. For more information, see Container networking.
Some endpoint behavior depends on the resource type. Keep those details with the docs for that resource type instead of duplicating them in this overview.
When defining a proxied service binding, the host port is given to the proxy that sits in front of the service. This allows single or multiple replicas of a service to behave similarly. Additionally, resource dependencies that use the WithReference API rely on the proxied endpoint from the environment variable unless the endpoint is configured as proxyless.
The same proxy pattern applies when a service runs multiple replicas. The browser still connects to one stable host port while the proxy fans out traffic to whichever replica is available:
The preceding code results in the following networking diagram:
The preceding diagram depicts the following:
A web browser as an entry point to the app.
A host port of 5066.
The frontend proxy sitting between the web browser and the frontend service replicas, listening on port 5066.
The frontend_0 frontend service replica listening on the randomly assigned port 65001.
The frontend_1 frontend service replica listening on the randomly assigned port 65002.
For a JavaScript app that reads its listener port from an environment variable, expose a stable host port like this:
Most endpoints are proxied by default. A proxyless endpoint skips the Aspire-managed proxy and exposes the resource’s listener directly. Use a proxyless endpoint when a proxy would interfere with the resource’s lifetime or networking behavior.
Starting in Aspire 13.4, endpoints on persistent resources are proxyless by default. This lets the persistent resource keep using its direct endpoint across AppHost runs instead of depending on a new proxy instance each time. This also ensures that the ports your service is reachable on stay stable whether the AppHost is running or not.
Because there’s no proxy to listen on one port and forward to another, every proxyless endpoint must include a target port. The target port tells Aspire which port the resource listens on. You can also set port when you need a specific host port, but targetPort is still required for proxyless endpoints.
For proxied endpoints, when you omit the host port, Aspire generates a random port for both host and service port. This is useful when you want to avoid port conflicts and don’t care about the host or service port. Consider the following code:
When you add a container resource, Aspire automatically assigns a random port to the container. To specify a container port, configure the container resource with the desired port:
Any resource that implements the IResourceWithEndpoints interface can use the WithEndpoint extension methods. There are several overloads of this extension, allowing you to specify the scheme, container port, host port, environment variable name, and whether the endpoint is proxied.
There’s also an overload that allows you to specify a delegate to configure the endpoint. This is useful when you need to configure the endpoint based on the environment or other factors. Consider the following code:
The preceding code provides a callback delegate to configure the endpoint. The endpoint is named admin and configured to use the http scheme and transport, as well as the 17003 host port. Consumers can reference this endpoint by name with a URI such as http://_admin.apiservice. The _ sentinel indicates that the admin segment is the endpoint name belonging to the apiservice service. For more information, see Service discovery.
When calling the WithEndpoint extension method, the callback overload exposes the raw EndpointAnnotation, which allows the consumer to customize many aspects of the endpoint.
The AllocatedEndpoint property allows you to get or set the endpoint for a service. The IsExternal and IsProxied properties determine how the endpoint is managed and exposed: IsExternal decides if it should be publicly accessible, while IsProxied ensures DCP manages it, allowing for internal port differences and replication.
The Name property identifies the service, whereas the Port and TargetPort properties specify the desired and listening ports, respectively. TargetPort is required for proxyless endpoints, including endpoints with IsProxied set to false and, starting in Aspire 13.4, endpoints on persistent resources by default.
For network communication, the Protocol property supports TCP and UDP, with potential for more in the future, and the Transport property indicates the transport protocol (HTTP, HTTP2, HTTP3). Lastly, if the service is URI-addressable, the UriScheme property provides the URI scheme for constructing the service URI.
By default, every endpoint on a resource is included when another resource references it via WithReference(resource). Some resources expose auxiliary endpoints—such as admin dashboards or health-check ports—that consumer services should not discover automatically. Use the ExcludeReferenceEndpoint property on EndpointAnnotation to opt an endpoint out of the default reference set:
Gets or sets a value indicating whether the endpoint is excluded from the default reference set.
setExcludeReferenceEndpoint(true);
});
When ExcludeReferenceEndpoint is true, the endpoint is not injected into dependent services by a plain WithReference(resource) call. It can still be referenced explicitly by name: