Posted in:

Dapr supports "service invocation" out of the box, allowing you to easily make requests to another microservice, addressing it by name, without needing to know the IP address. So for example, simply by making a request to my Dapr sidecar on localhost port 3500, I can direct a request through to the "catalog" microservice like this, and let Dapr work out where it is:


When you're running Dapr in "self-hosted" mode, it uses mDNS as the name resolution service, and if you're running on Kubernetes, then it makes use of the Kubernetes DNS service.

mDNS problems

Unfortunately, there has been a long-standing issue that certain VPN or networking software commonly found on corporate developer machines can interfere with the mDNS name resolution. Some people have been able to work around this by temporarily disabling their VPN or networking software.

However, on one of my development environments it has not been possible to work around the issue, and as of Dapr v1.8 the only alternative is to switch to using Consul for name resolution.

This is especially unfortunate for those new to Dapr as this results in a poor initial experience where the basic quickstart demos don't work at all, and it is non-trivial to set up Consul. I'm hopeful that Dapr will resolve this by offering a simple alternative to mDNS for local development scenarios.

Using Consul for name resolution

Although there are some basic instructions to configure Consul, I found they were not sufficient to get it working on my machine.

In the rest of this post, I'll run through the steps I took to get round the mDNS issue by configuring Dapr to use Consul for name resolution.

Running Consul locally with Docker

First of all we need to start the Consul container locally with the following command:

docker run -d -p 8500:8500 --name=dev-consul -e CONSUL_BIND_INTERFACE=eth0 consul

n.b. I happen to be using Rancher Desktop, but doubt the command would need to change if you're using something different such as Docker Desktop

The important thing is making sure that port 8500 is accessible. If not the Dapr Consul name resolution component will fail to initialize and you'll get crashes in your Dapr process with null reference exceptions in Dapr sidecar (I'm hoping that they'll fix that and make it handle the error more gracefully in the future).

You can check that Consul is running successfully locally by visiting

Create a configuration file

By default, when you run locally, Dapr uses your global config file which is found in %USERPROFILE%\.dapr\config.yaml

You could of course change set up Consul globally for your machine, but I chose to create my own daprConfig.yaml file specific to my application. The contents I used are the same as the default config.yaml file, but with the extra nameResolution section. Note that it's very important to include selfRegister: true - this was missing from some of the guides I read, but it won't work without it.

kind: Configuration
  name: daprConfig
    component: "consul"
      selfRegister: true
    samplingRate: "1"
      endpointAddress: http://localhost:9411/api/v2/spans

Create a Consul component definition file

Now create a consul.yaml file in your local components folder with the following contents. I wasn't sure what I was supposed to put for datacenter but it seems that dc1 is the default value for Consul so I recommend leaving it as is:

kind: Component
  name: consul
  namespace: default
  type: state.consul
  version: v1
  - name: datacenter
    value: dc1 # Required. Example: dc1
  - name: httpAddr
    value: # Required. Example: "consul.default.svc.cluster.local:8500"

Pass correct arguments to dapr run

Now when you call dapr run for each microservice, it needs to point to the updated config and components folder, with the --config and --components-path arguments. Here's an example PowerShell script I used for my GloboTicket Dapr demo application:

dapr run `
    --app-id frontend `
    --app-port 5266 `
    --dapr-http-port 3500 `
    --components-path ../dapr/components `
    --config ../dapr/components/daprConfig.yaml `
    dotnet run

Check its working

Now all that remains is to start all your services. Hopefully it will be obvious that it's working because you can make service to service invocations.

You can also test by directly making a network request to a Dapr sidecar, passing in the target application name (in this example "catalog") and method (in this example "products")


You can also use the Dapr CLI to try it out with the dapr invoke command, again passing in the application and method names. You can also pass in the HTTP verb if it's not the default of POST.

dapr invoke -a catalog -m event -v GET

Finally, you can use the Consul UI to check that each service has correctly registered itself by visiting Here's what it looks like for my GloboTicket Dapr sample app:

Consul Service List


In an ideal world, you wouldn't need to change the name resolution component in Dapr from its default, but it's nice that you can, and it's a helpful workaround until the mDNS issue is finally resolved.

If you'd like to take a look at a version of my app that uses this approach, you can look here on the "consul" branch.

Want to get up learn more about how Dapr can greatly simplify the task of building microservices? Be sure to check out my Pluralsight course, Dapr 1 Fundamentals.


Comment by alkapa

Dear Mark, Thank you for great courses about darp on Pluralsight!
I was impress after watching it and thought it could help me to start migrate my monolith to microservices. I have .net framework web api app and would like to start using service invocation component. I run several instances of app on different machines. I also can't use kubernates right now because app is not .net core yet. I would like to ask for some example/description of how will service invocation work with self-hosted mode if my service instances are running on separate machines?