When you build a simple self-contained service and run it locally it feels so easy ๐คฉ. But when you have to develop, debug, and test on your local machine many services that would be challenging ๐ญ. First of all, you have to deal with unique ports mystery for each service you run. And if you would like to run that services in Kubernetes locally, promise me, it is no so straightforward ๐ค.
In the first quarter of 2020 Microsoft have started building the experimental ๐งช tool Tye with the idea to decrease microservices and distributed application developing, testing, and deployment complexity ๐. This project is part of .NET Foundation. The top three contributors for Tye project are rynowak, jkotalik, and davidfowl. ๐คฉ
Tye is a developer tool that makes developing, testing, and deploying microservices and distributed applications easier. Project Tye includes a local orchestrator to make developing microservices easier and the ability to deploy microservices to Kubernetes with minimal configuration.
Let`s try out tye tool!
Build steps:
- Install prerequisite tools
- Create Solution and multiple projects
- Run using
tyetool - Add Service discovery
Prerequisites ๐จ
Tools you have to install before create this example project:
- .NET Core 3.1 SDK - https://dotnet.microsoft.com/download/dotnet-core/3.1
- Visual Studio Code - https://code.visualstudio.com/
Installing tye
The installation consists of two steps. The first step is NuGet source registration and the second is tye tool installation.
Register NuGet source
Before installation, you have to add NuGet package source, because that package is placed in a different source, not https://nuget.org.
dotnet nuget add source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json --name dotnet5Using command dotnet nuget list source you can check if dotnet5 source was added.
Install tye tool
By executing the following command you will install tye tool in the global scope. The current version you can get in GitHub repository.
dotnet tool install -g Microsoft.Tye --version "0.4.0-alpha.20371.1"After installation completed check if command tye works correctly ๐.

tye command get summary help.Create a solution with multiple projects
We have to build one Solution file which contains multiple projects. For better illustration, I chose to build two backend projects and one frontend. Frontend makes a call to both backend APIs.
By executing the following sequence of commands you will create all projects you need for the next step โ๏ธ.
dotnet new sln -n SampleApplication
dotnet new webapi -n FirstBackend
dotnet new webapi -n SecondBackend
dotnet new web -n Frontenddotnet sln add .\Frontend\Frontend.csproj
dotnet sln add .\FirstBackend\FirstBackend.csproj
dotnet sln add .\SecondBackend\SecondBackend.csprojAt the end run dotnet build to check if all projects build successfully.
Run using tye tool
Without any changes let`s try to run all three projects using tye. ย By executing the following tye run command all three projects should be running โค๏ธ. In Tye terminology project names as services.

tye output after running commandIn output, we can see that tye reads Solution file and launches all projects they discovered. As we can identify that ports for each project are unique. If we check all addresses, we will see that all projects are working correctly.
Frontend- http://localhost:57778/ (outputsHello world!)FirstBackend- https://localhost:57775/WeatherForecast (outputs forecast JSON)SecondBackend- https://localhost:57775/WeatherForecast (outputs forecast JSON)
Tye has multiple choice of how you can run your projects. By default, it runs each project as a single process. But also you can run all projects like containers by executing tye run --docker.

Manage running processes in Dashboard ๐
When you run tye its starts Dashboard. The dashboard is built using Blazor. ย If you open address http://127.0.0.1:8000 you will see:
- services list
tyerunning and running type project or container - each service logs, by clicking on the
Viewlink in column Logs - each service metrics, by clicking on the link in column Name

tye DashboardWhat I found out interesting that tye attaches all metrics counters out of the box without any changes in the project, that`s nice. You can call URLs multiple times and check if metrics are changing, for example, Microsoft.AspNetCore.Hosting/total-requests.
Debug project by attaching to tye running process ๐
Running multiple projects using only a single command looks amazing, but this tool is for the development phase, so we need to debug our projects. We can attach to the process from Visual Studio Code. By using .NET Core Attach configuration profile you could choose the process tye are running and debug your project easy way. ๐

tye running processAdd Service discovery
If you run tye run multiple times you will see that endpoint ports are changing each time dynamically. We have one frontend application that calls two APIs. So we have to figure out the URI of APIs ๐ค. Tye provides us the possibility to discover running services URIs using environment variables.
Add service discovery extension library
To enable service discovery we need to add NuGet package to our frontend project by executing a command.
dotnet add .\Frontend\Frontend.csproj package Microsoft.Tye.Extensions.Configuration --version 0.4.0-alpha.20371.1Change Startup.cs to add inject IConfiguration and output discovered URIs for backend.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Frontend
{
public class Startup
{
/// Inject IConfiguration
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
var firstBackendUri = Configuration.GetServiceUri("FirstBackend");
var secondBackendUri = Configuration.GetServiceUri("SecondBackend");
await context.Response.WriteAsync($"FirstBackend uri: {firstBackendUri} \n");
await context.Response.WriteAsync($"SecondBackend uri: {secondBackendUri} \n");
await context.Response.WriteAsync("\nFrontend!");
});
});
}
}
}tye configurationAfter Startup.cs modification try to run again tye run and take a look at the frontend output. You will see that URIs were discovered successfully. In the next steps we will modify our backend APIs and try to call from frontend.

Add backend controllers
In FirstBackend project create new controller BackendController.cs in the Controllers directory and copy the following code.
using Microsoft.AspNetCore.Mvc;
namespace FirstBackend.Controllers
{
[ApiController]
[Route("[controller]")]
public class BackendController : ControllerBase
{
[HttpGet]
public string Get() => "First backend";
}
}In SecondBackend project create new controller BackendController.cs in the Controllers directory and copy the following code.
using Microsoft.AspNetCore.Mvc;
namespace SecondBackend.Controllers
{
[ApiController]
[Route("[controller]")]
public class BackendController : ControllerBase
{
[HttpGet]
public string Get() => "Second backend";
}
}Call APIs from frontend
Copy following code to Frontend project Startup.cs file.
using System.Net.Http;
...
namespace Frontend
{
public class Startup
{
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
var firstBackendUri = Configuration.GetServiceUri("FirstBackend");
var secondBackendUri = Configuration.GetServiceUri("SecondBackend");
var client = new HttpClient
{
BaseAddress = firstBackendUri
};
var firstBackendResponse = await client.GetAsync("/backend");
var firstBackendResponseContent = await firstBackendResponse.Content.ReadAsStringAsync();
client = new HttpClient
{
BaseAddress = secondBackendUri
};
var secondBackendResponse = await client.GetAsync("/backend");
var secondBackendResponseContent = await secondBackendResponse.Content.ReadAsStringAsync();
await context.Response.WriteAsync($"FirstBackend uri: {firstBackendUri} \n");
await context.Response.WriteAsync($"response: {firstBackendResponseContent} \n\n");
await context.Response.WriteAsync($"SecondBackend uri: {secondBackendUri} \n");
await context.Response.WriteAsync($"response: {secondBackendResponseContent} \n\n");
await context.Response.WriteAsync("\nFrontend!");
});
});
}After Startup.cs modification try to run again tye run and take a look at the frontend output. You will see a response from both backend APIs.

In the first moment that looks like magic ๐งโโ๏ธ. In a nutshell, tye does the following steps:
- Find
.sln(other extensions also are supported:tye.yaml,tye.yml,*.csproj,*.fsproj,*.sln) - Extract solution metadata and build, configure collection of services to run (unique ports are assigned using by
PortAssigner.cs) - All URIs are registered using Environment variables in
ProcessRunner.csclass when you run your projects as independent processes (process runner is used by default) - At the end frontend project reads that values using extension method
GetServiceUri
Summary ๐ฌ
In this post, we have tried out tye tool for developers to increase productivity when developing a microservices architecture application. As we saw tye simplify application running locally task a lot. Using only one command you can run, debug, test locally whole application without any inconvenience. Tye has a lot more features like: add tye configuration, run dependencies like database, deploy to ย Kubernetes cluster on-premise, or direct to cloud. The tool is open source and written on .NET Core, you have to clone that repository because there is a lot of interesting stuff and techniques to learn.
Have fun and perform better with tye! ๐ฆ
[eof]