Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dotnet-client-libraries/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@ This section contains the topics about the client libraries in .NET.
- [Multi-Source Data Integration With Strawberry Shake Subscriptions](https://code-maze.com/dotnetcore-multi-source-data-integration-with-strawberry-shake-subscriptions/)
- [Introduction to the Wolverine Library in .NET](https://code-maze.com/dotnet-wolverine-library/)
- [Comparison of Rebus, NServiceBus, and MassTransit in .NET](https://code-maze.com/aspnetcore-comparison-of-rebus-nservicebus-and-masstransit/)
- [Polly in .NET: Retry, Circuit Breaker, and Fallback](https://code-maze.com/creating-resilient-microservices-in-net-with-polly/)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using AuthorsService.Data;
using AuthorsService.Models;
using Microsoft.AspNetCore.Mvc;

namespace AuthorsService.Controllers;

[ApiController]
[Route("[controller]")]
public class AuthorsController(Repository repository) : ControllerBase
{
[HttpGet]
public Task<IEnumerable<Author>> Get() => repository.GetAuthorsAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using AuthorsService.Models;

namespace AuthorsService.Data;

public class Repository
{
private readonly IEnumerable<Author> _authors =
[
new Author { AuthorId = 1, Name = "John Doe", Country = "Australia" },
new Author { AuthorId = 2, Name = "Jane Smith", Country = "United States" }
];

private readonly DateTime _startTime = DateTime.UtcNow;
private bool _shouldFail = true;

public async Task<IEnumerable<Author>> GetAuthorsAsync()
{
if (_shouldFail)
{
_shouldFail = false;

throw new InvalidOperationException("Oops!");
}

if (_startTime.AddMinutes(1) > DateTime.UtcNow)
{
await Task.Delay(TimeSpan.FromSeconds(5));

throw new TimeoutException("Timeout!");
}

return _authors;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace AuthorsService.Models;

public class Author
{
public int AuthorId { get; set; }
public required string Name { get; set; }
public required string Country { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using AuthorsService.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<Repository>();
builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();
app.MapControllers();

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"AuthorsService": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using BooksService.Data;
using BooksService.Models;
using Microsoft.AspNetCore.Mvc;

namespace BooksService.Controllers;

[ApiController]
[Route("[controller]")]
public class BooksController(Repository repository) : ControllerBase
{
[HttpGet]
public IEnumerable<Book> Get() => repository.GetBooks();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using BooksService.Models;

namespace BooksService.Data;

public class Repository
{
private readonly IEnumerable<Book> _books =
[
new Book { BookId = 1, AuthorId = 1, Name = "The Fallen Shore", NumberOfPages = 123 },
new Book { BookId = 2, AuthorId = 1, Name = "Harmony of Joy", NumberOfPages = 211 },
new Book { BookId = 3, AuthorId = 2, Name = "Aliens vs Robots", NumberOfPages = 345 }
];

public IEnumerable<Book> GetBooks() => _books;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace BooksService.Models;

public class Book
{
public int BookId { get; set; }
public int AuthorId { get; set; }
public required string Name { get; set; }
public int NumberOfPages { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using BooksService.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<Repository>();
builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();
app.MapControllers();

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"BooksService": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "https://localhost:6001;http://localhost:6000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Polly.Extensions" Version="8.7.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using Monolith.Resilience;
using Polly;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options => options.AddDefaultPolicy(policy => policy.AllowAnyOrigin()));
builder.Services.AddHttpClient();
builder.Services.AddControllers();

builder.Services.AddResiliencePipeline<string, IActionResult>(
ProxyPipeline.Name,
(pipeline, _) => ProxyPipeline.Configure(pipeline));

var app = builder.Build();

app.UseHttpsRedirection();
app.UseCors();
app.MapControllers();

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Monolith": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "https://localhost:7001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Mvc;
using Monolith.Resilience;
using Polly;
using Polly.Registry;

namespace Monolith;

[Route("[action]")]
[ApiController]
public class ProxyController : ControllerBase
{
private readonly HttpClient _httpClient;
private readonly ResiliencePipeline<IActionResult> _pipeline;

public ProxyController(IHttpClientFactory httpClientFactory,
ResiliencePipelineProvider<string> pipelineProvider)
{
_httpClient = httpClientFactory.CreateClient();
_pipeline = pipelineProvider.GetPipeline<IActionResult>(ProxyPipeline.Name);
}

[HttpGet]
public Task<IActionResult> Books() => ProxyTo("https://localhost:6001/books");

[HttpGet]
public Task<IActionResult> Authors() => ProxyTo("https://localhost:5001/authors");

private async Task<IActionResult> ProxyTo(string url)
=> await _pipeline.ExecuteAsync(
async token => (IActionResult)Content(await _httpClient.GetStringAsync(url, token)),
HttpContext.RequestAborted);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Mvc;
using Polly;
using Polly.CircuitBreaker;
using Polly.Fallback;
using Polly.Retry;

namespace Monolith.Resilience;

public static class ProxyPipeline
{
public const string Name = "proxy";

public const string FallbackMessage =
"Sorry, we are currently experiencing issues. Please try again later";

public static void Configure(ResiliencePipelineBuilder<IActionResult> builder) =>
builder
.AddFallback(new FallbackStrategyOptions<IActionResult>
{
ShouldHandle = new PredicateBuilder<IActionResult>().Handle<Exception>(),
FallbackAction = static _ => Outcome.FromResultAsValueTask<IActionResult>(
new ContentResult { Content = FallbackMessage })
})
.AddRetry(new RetryStrategyOptions<IActionResult>
{
ShouldHandle = new PredicateBuilder<IActionResult>().Handle<Exception>(),
MaxRetryAttempts = 1,
Delay = TimeSpan.Zero
})
.AddCircuitBreaker(new CircuitBreakerStrategyOptions<IActionResult>
{
ShouldHandle = new PredicateBuilder<IActionResult>().Handle<Exception>(),
FailureRatio = 1.0,
MinimumThroughput = 2,
SamplingDuration = TimeSpan.FromSeconds(30),
BreakDuration = TimeSpan.FromMinutes(1)
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<html>
<head></head>
<body>
<button onclick="callAPI('books')">Get Books</button>
<button onclick="callAPI('authors')">Get Authors</button>
</body>
<script type="text/javascript">
function callAPI(path) {
let request = new XMLHttpRequest();
request.open("GET", "https://localhost:7001/" + path);
request.send();
request.onload = () => {
if (request.status === 200) {
alert(request.response);
} else {
alert(`Error: ${request.status} ${request.responseText}`);
}
}
}
</script>
</html>
Loading
Loading