When creating new pipelines I often need to inspect the contents of the workspace:
- powershell: |
tree "$(Pipeline.Workspace)" /F
displayName: 'Treeview of Pipeline.Workspace'
When creating new pipelines I often need to inspect the contents of the workspace:
- powershell: |
tree "$(Pipeline.Workspace)" /F
displayName: 'Treeview of Pipeline.Workspace'
To list all tags in your remote repository that include the word ‘Jenkins’ and end with a number:
git ls-remote --tags origin | awk '/Jenkins(.*)[0-9]$/{ print $2 }'
To delete all of those tags:
git ls-remote --tags origin | awk '/Jenkins(.*)[0-9]$/{ print ":" $2 }' | xargs git push origin
Tye’s promise:
dotnet tool install --global Microsoft.Tye --version 0.10.0-alpha.21420.1
Let’s create a new front-end project, and start it via Tye.
mkdir microservices
cd microservices
dotnet new razor -n frontend
tye run frontend
Here we can see Tye has built the project, configured HTTP bindings, and started it running. We can navigate to 127.0.0.1:8000 to view the Tye dashboard.
We can stop Tye with Ctrl+C.
Now suppose out front-end project needs to talk to a back-end API. We will create a solution file containing both projects
dotnet new webapi -n backend
dotnet new sln
dotnet sln add frontend backend
tye run
Now we have both services running.
We will wire up the two services using Tye’s service discovery.
WeatherForecast.cs
to the frontend
project, to match the similar class in backend
.
namespace frontend;
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
WeatherClient.cs
to the frontend
project:
namespace frontend;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
public class WeatherClient
{
private readonly JsonSerializerOptions options = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
private readonly HttpClient client;
public WeatherClient(HttpClient client)
{
this.client = client;
}
public async Task<WeatherForecast[]> GetWeatherAsync()
{
var responseMessage = await this.client.GetAsync("/weatherforecast");
var stream = await responseMessage.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<WeatherForecast[]>(stream, options);
}
}
4. Add a reference to the Microsoft.Tye.Extensions.Configuration
package to the frontend
project.
dotnet add frontend/frontend.csproj package Microsoft.Tye.Extensions.Configuration --version "0.2.0-*"
using frontend;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpClient<WeatherClient>(client =>
{
client.BaseAddress = builder.Configuration.GetServiceUri("backend");
});
builder.Services.AddRazorPages();
...
Forecasts
property to the Index
page model under Pages\Index.cshtml.cs
in the frontend
project.
public WeatherForecast[] Forecasts { get; set; }
OnGet
method to take the WeatherClient
to call the backend
service and store the result in the Forecasts
property:
public async Task OnGet([FromServices]WeatherClient client)
{
Forecasts = await client.GetWeatherAsync();
}
Forecasts
property in the Index.cshtml
razor view:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
Weather Forecast:
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in @Model.Forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
Now if we re-start the services with tye run
we should see the front-end service is displaying random weather data generated by the back-end.
Let’s generate Tye’s optional configuration file, tye.yaml
, for our solution:
tye init
Here we can re-configure the services, e.g., we can set specific bindings.
(Changing the name of the backend
service means we must also update the reference to it in the frontend Program.cs
).
Let’s change the WeatherForecastController.Get()
method in the backend
to cache weather information using an IDistributedCache
.
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
[HttpGet(Name = "GetWeatherForecast")]
public async Task<string> Get([FromServices]IDistributedCache cache)
{
var weather = await cache.GetStringAsync("weather");
if (weather == null)
{
var rng = new Random();
var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
weather = JsonSerializer.Serialize(forecasts);
await cache.SetStringAsync("weather", weather, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5)
});
}
return weather;
}
Microsoft.Extensions.Caching.StackExchangeRedis
cd backend/
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
cd ..
...
builder.Services.AddStackExchangeRedisCache(o =>
{
o.Configuration = builder.Configuration.GetConnectionString("redis");
});
builder.Services.AddControllers();
...
tye.yaml
to include redis as a dependency.
...
- name: redis
image: redis
bindings:
- port: 6379
connectionString: "${host}:${port}"
- name: redis-cli
image: redis
args: "redis-cli -h redis MONITOR"
We had a couple of databases stuck in the “Recovery Pending” state. The fix is straightforward:
ALTER DATABASE [DBName] SET EMERGENCY;
GO
ALTER DATABASE [DBName] SET SINGLE_USER
GO
DBCC CHECKDB ([DBName], REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS;
GO
ALTER DATABASE [DBName] SET MULTI_USER
GO
Create a copy-only backup from PowerShell:
Backup-SqlDatabase -ServerInstance 'SalesServer' -Database 'Sales' -BackupFile 'E:\BAK\Sales_Copy.bak' -CopyOnly