Posted in:

Over the past few weeks I've been playing with Tye, and I've been really impressed so far. Tye is designed to simplify the process of developing microservices with ASP.NET Core.

It is able to detect all of the microservices in a solution and start them all up with a single tye run command, enabling them to easily discover each other. It provides some great added-value features as well, such as a dashboard showing you all of the services and enabling you to access their logs.

But the feature I want to focus on in this post, is the ability for Tye to automatically start containerized dependencies. This means I can automate starting up a SQL database (following on from my recent post about containerizing SQL databases).

Tye Configuration

For Tye to know what containerized dependencies your microservices rely on, you do need to specify a configuration file. This is easily generated with the tye init command, and good effort has been made to keep the contents minimal (as many of us have had enough of YAML overload).

Here's a section I added under the services: part of my tye.yaml file. It specifies that we want to run the SQL Server Docker image, giving it the name of sqlserver, and providing the environment variables we want to use.

With bindings, I can say what port I want to expose on the container, and what is really nice is that I can construct a connection string that will be automatically made available to all other microservices via an environment variable.

- name: sqlserver
  image: mcr.microsoft.com/mssql/server:2019-latest 
  env:
  - name: SA_PASSWORD
    value: "V0teM!cr0s3rv!ce"
  - name: ACCEPT_EULA
    value: 'Y'
  bindings:
    - port: 1433
      connectionString: Server=${host};User Id=sa;Database=VoteDB;Password=${env:SA_PASSWORD};

Using a Volume

It's probably a good idea to store the SQL database data in a volume, so that we can tear down our containers without losing our data. That can easily be set up by adding another section to the sqlserver service in our tye.yaml file.

  volumes:
  - name: vote-storage
    target: /var/opt/mssql

Named bindings

So far, so easy, but I wanted to use my SQL container to host two databases, and so generate separate connection strings for each database. That proved tricky as you need to create what are called "named" bindings in Tye, and documentation is somewhat lacking in this area.

Eventually I discovered the syntax to create named bindings, allowing me to set up two connection string bindings. To make this work, I also had to give a name to the default binding. Exploring the Tye source code, it looks like this binding should be called "http".

  bindings:
  - name: http # think this is the name needed for the port
    port: 1433
  - name: voteDb
    connectionString: Server=${host};User Id=sa;Database=VoteDB;Password=${env:SA_PASSWORD};
  - name: queueDb
    connectionString: Server=${host};User Id=sa;Database=VoteQueueDb;Password=${env:SA_PASSWORD};

With this in place, any microservice that wants to access one of these named bindings can do so with a simple call to the GetConnectionString extension method provided by Tye:

config.GetConnectionString("sqlserver", "queueDb");

Summary

Tye is a really simple and powerful way to start up multiple ASP.NET Core microservices, along with all their dependencies and configure everything to communicate with each other. I recommend experimenting with it if you are embarking on a microservices project with ASP.NET Core.

For reference, here's the entire tye.yaml file I used in my demo app:

name: VoteTye
ingress:
  - name: ingress
    bindings:
      - port: 8080
    rules:
      - path: /vote
        service: voteweb
      - path: /results
        service: resultsweb
services:
- name: VoteService
  project: VoteService/VoteService.csproj
- name: voteweb
  project: VoteWebApp/VoteWebApp.csproj
- name: resultsweb
  project: ResultWebApp/ResultWebApp.csproj
- name: sqlserver
  image: mcr.microsoft.com/mssql/server:2019-latest 
  env:
  - name: SA_PASSWORD
    value: "V0teM!cr0s3rv!ce"
  - name: ACCEPT_EULA
    value: 'Y'
  volumes:
  - name: vote-storage
    target: /var/opt/mssql
  bindings:
  - name: http # think this is the name needed for the port
    port: 1433
  - name: voteDb
    connectionString: Server=${host};User Id=sa;Database=VoteDB;Password=${env:SA_PASSWORD};
  - name: queueDb
    connectionString: Server=${host};User Id=sa;Database=VoteQueueDb;Password=${env:SA_PASSWORD};
Want to learn more about how to architect and build microservices applications? Be sure to check out my Pluralsight course Microservices Fundamentals