<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: VzlDev</title>
    <description>The latest articles on DEV Community by VzlDev (@vzldev).</description>
    <link>https://dev.to/vzldev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1332510%2F83722690-7b45-43f0-8c71-cdf29ff25bce.jpg</url>
      <title>DEV Community: VzlDev</title>
      <link>https://dev.to/vzldev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vzldev"/>
    <language>en</language>
    <item>
      <title>Mastering Async and Await in C#</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Tue, 06 Aug 2024 11:00:35 +0000</pubDate>
      <link>https://dev.to/vzldev/mastering-async-and-await-in-c-3ndm</link>
      <guid>https://dev.to/vzldev/mastering-async-and-await-in-c-3ndm</guid>
      <description>&lt;h2&gt;
  
  
  Understanding the Async and Await Keywords
&lt;/h2&gt;

&lt;p&gt;The async and await keywords are essential tools in C# for asynchronous programming. They streamline the creation of non-blocking code, enhancing readability and maintainability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Async Keyword
&lt;/h4&gt;

&lt;p&gt;The async keyword is used to mark a method as asynchronous, indicating that the method can perform a non-blocking operation&lt;/p&gt;

&lt;h4&gt;
  
  
  Await Keyword
&lt;/h4&gt;

&lt;p&gt;The await keyword is used inside of an async method to temporarily suspend its execution and yield control back to the calling method until the awaited task is completed. This allows other tasks to continue executing in the meantime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Imagine you're a chef in a kitchen. Instead of waiting for each ingredient to be ready before moving on, you can do multiple tasks at the same time to improve the time of preparing a meal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Synchronous Code
&lt;/h4&gt;

&lt;p&gt;In a synchronous approach, each task waits for the previous one to complete before starting the next. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static void Main(string[] args)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    PrepareMeal();

    stopwatch.Stop();
    TimeSpan elapsed = stopwatch.Elapsed;
    Console.WriteLine($"Elapsed Time (Seconds): {elapsed.TotalSeconds} s");
    Console.ReadLine();
}

private static void PrepareMeal()
{
    Console.WriteLine("Preparing meal");
    CutVegetables();
    BoilWater();   
    CookVegetables();
}

private static void BoilWater()
{
    Console.WriteLine("Boiling water");
    Task.Delay(3000).Wait();
    Console.WriteLine("Water is boiling!");
}

private static void CutVegetables()
{
    Console.WriteLine("Cutting vegetables");
    Task.Delay(3000).Wait();
    Console.WriteLine("Vegetables are cut!");
}

private static void CookVegetables()
{
    Console.WriteLine("Put vegetables on boiling water");
    Task.Delay(5000).Wait();
    Console.WriteLine("Meal Done!");
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of the preparation of this meal will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Preparing meal
Boiling water
Water is boiling!
Cutting vegetables
Vegetables are cut!
Put vegetables on boiling water
Meal Done!
Final time - 11.03 seconds

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, each task must finish before the next one starts, leading to a longer overall completion time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Asynchronous Code
&lt;/h4&gt;

&lt;p&gt;Using async and await allows tasks to overlap, enhancing efficiency. Here’s the asynchronous version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static async Task Main(string[] args)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    await PrepareMealAsynchronously();

    stopwatch.Stop();
    TimeSpan elapsed = stopwatch.Elapsed;
    Console.WriteLine($"Elapsed Time (Seconds): {elapsed.TotalSeconds} s");
    Console.ReadLine();
}

private static async Task PrepareMealAsynchronously()
{
    Console.WriteLine("Preparing meal asynchronously");

    Task boilWaterTask = BoilWaterAsynchronously();
    Task cutVegetablesTask = CutVegetablesAsynchronously();

    await Task.WhenAll(boilWaterTask, cutVegetablesTask);

    await CookVegetablesAsynchronously();
}

private static async Task BoilWaterAsynchronously()
{
    Console.WriteLine("Boiling water");
    await Task.Delay(3000);
    Console.WriteLine("Water is boiling!");
}

private static async Task CutVegetablesAsynchronously()
{
    Console.WriteLine("Cutting vegetables");
    await Task.Delay(3000);
    Console.WriteLine("Vegetables are cut!");
}

private static async Task CookVegetablesAsynchronously()
{
    Console.WriteLine("Put vegetables on boiling water");
    await Task.Delay(5000);
    Console.WriteLine("Meal done!");
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of the preparation of this meal will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Preparing meal asynchronously
Boiling water
Cutting vegetables
Water is boiling!
Vegetables are cut!
Put vegetables on boiling water
Done cooking!
Final time - 8.01 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this asynchronous approach, tasks like boiling water and chopping vegetables can proceed simultaneously, reducing the overall cooking time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Asynchronous Approach
&lt;/h2&gt;

&lt;p&gt;Asynchronous cooking, or programming, allows tasks to be executed concurrently, making better use of time and resources. This results in faster completion of tasks, as the system can handle multiple operations at once. For instance, while waiting for the water to boil, you can simultaneously chop vegetables, significantly cutting down the total time needed.&lt;/p&gt;

&lt;p&gt;And that's it guys, a simple explanation and example of asynchronous calls with .net. &lt;br&gt;
There's still plenty more to learn, I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Integrating PostgreSQL with a .NET: A Step-by-Step Guide</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Thu, 27 Jun 2024 12:54:47 +0000</pubDate>
      <link>https://dev.to/vzldev/integrating-postgresql-with-a-net-a-step-by-step-guide-3hep</link>
      <guid>https://dev.to/vzldev/integrating-postgresql-with-a-net-a-step-by-step-guide-3hep</guid>
      <description>&lt;p&gt;In today's world of ever-evolving technologies, PostgreSQL stands out as a powerful, open-source relational database management system that is robust, reliable, and feature-rich. Integrating PostgreSQL with a .NET API can open up a lot of opportunities for building scalable and high-performance applications. In this guide, we'll walk you through the process of setting up and integrating PostgreSQL with a .NET API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we dive in, ensure you have the following installed on your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;.NET SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Set Up Your .NET Project
&lt;/h2&gt;

&lt;p&gt;First things first, create a .NET Project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install Required Packages
&lt;/h2&gt;

&lt;p&gt;Next, we need to install the necessary packages to work with PostgreSQL in .NET. &lt;br&gt;
Install the following nuGet package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Npgsql.EntityFrameworkCore.PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This package allows Entity Framework Core to communicate with PostgreSQL.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Configure the Database Connection
&lt;/h2&gt;

&lt;p&gt;Open appsettings.json and add your PostgreSQL connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Database=mydatabase;Username=postgres;Password=yourpassword"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Create a Data Context Class
&lt;/h2&gt;

&lt;p&gt;Create a new class named MyDbContext.cs in the Models directory (create the directory if it doesn't exist). Define your DbContext class as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.EntityFrameworkCore;

namespace MyApi.Models
{
    public class MyDbContext : DbContext
    {
        public MyDbContext(DbContextOptions&amp;lt;MyDbContext&amp;gt; options) : base(options) { }

        public DbSet&amp;lt;User&amp;gt; Users { get; set; }
    }

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Configure Services in Program.cs
&lt;/h2&gt;

&lt;p&gt;Open program.cs and configure the services to use PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; services.AddDbContext&amp;lt;MyDbContext&amp;gt;(options =&amp;gt;     options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 6: Create and Apply Migrations&lt;/strong&gt;&lt;br&gt;
To keep your database schema in sync with your EF Core models, use migrations. Open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet ef migrations add InitialCreate
dotnet ef database update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Create API Endpoints
&lt;/h2&gt;

&lt;p&gt;Create a new controller named UsersController.cs in the Controllers directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyApi.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    private readonly MyDbContext _context;

    public UsersController(MyDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task&amp;lt;ActionResult&amp;lt;IEnumerable&amp;lt;User&amp;gt;&amp;gt;&amp;gt; GetUsers()
    {
        return await _context.Users.ToListAsync();
    }

    [HttpGet("{id}")]
    public async Task&amp;lt;ActionResult&amp;lt;User&amp;gt;&amp;gt; GetUser(int id)
    {
        var user = await _context.Users.FindAsync(id);

        if (user == null)
        {
            return NotFound();
        }

        return user;
    }

    [HttpPost]
    public async Task&amp;lt;ActionResult&amp;lt;User&amp;gt;&amp;gt; PostUser(User user)
    {
        _context.Users.Add(user);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
    }

    [HttpPut("{id}")]
    public async Task&amp;lt;IActionResult&amp;gt; PutUser(int id, User user)
    {
        if (id != user.Id)
        {
            return BadRequest();
        }

        _context.Entry(user).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!UserExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task&amp;lt;IActionResult&amp;gt; DeleteUser(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null)
        {
            return NotFound();
        }

        _context.Users.Remove(user);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool UserExists(int id)
    {
        return _context.Users.Any(e =&amp;gt; e.Id == id);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Run the Application
&lt;/h2&gt;

&lt;p&gt;To manage postgreSQL databases, I use the pgAdmin 4, so you can see here an example of a user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rmj7fi8zk2f6kfouuny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rmj7fi8zk2f6kfouuny.png" alt="Image description" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it guys, a very very very simple case of postgreSQL integration with .net, there's still plenty more to learn, I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>postgressql</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>First experience with graphQL</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Thu, 27 Jun 2024 10:14:58 +0000</pubDate>
      <link>https://dev.to/vzldev/first-experience-with-graphql-38m5</link>
      <guid>https://dev.to/vzldev/first-experience-with-graphql-38m5</guid>
      <description>&lt;p&gt;As developers, we're constantly seeking efficient and flexible ways to manage data and interactions in our applications. For many years, RESTful APIs have been the standard for handling these interactions. However, a new contender has emerged in recent years, promising more flexibility and efficiency: GraphQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GraphQL?
&lt;/h2&gt;

&lt;p&gt;GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features of GraphQL:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Declarative Data Fetching&lt;/strong&gt;: Clients can request exactly the data they need, and nothing more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single Endpoint&lt;/strong&gt;: All interactions are routed through a single endpoint, simplifying network architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strongly Typed Schema&lt;/strong&gt;: The API's schema is defined using types, ensuring clients know exactly what data is available and how it can be used.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up GraphQL with .NET
&lt;/h2&gt;

&lt;p&gt;To give you a practical taste, let's set up a simple GraphQL API.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Install Required Packages
&lt;/h4&gt;

&lt;p&gt;First, install the necessary NuGet packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;GraphQL.Server.Transports.AspNetCore&lt;/li&gt;
&lt;li&gt;GraphQL.Server.Ui.GraphiQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Define Your Data Models
&lt;/h4&gt;

&lt;p&gt;Create your data models. For instance, let's define Author and Book models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List&amp;lt;Book&amp;gt; Books { get; set; }
}

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Create Your DbContext
&lt;/h4&gt;

&lt;p&gt;Define your LibraryContext:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LibraryContext : DbContext
{
    public LibraryContext(DbContextOptions&amp;lt;LibraryContext&amp;gt; options) : base(options) { }

    public DbSet&amp;lt;Book&amp;gt; Books { get; set; }
    public DbSet&amp;lt;Author&amp;gt; Authors { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Setup your repository
&lt;/h4&gt;

&lt;p&gt;Create your repository class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface ILibraryRepository
{
    IEnumerable&amp;lt;Book&amp;gt; GetBooks();
    Book GetBookById(int id);
    Book AddBook(string title, int authorId);
    IEnumerable&amp;lt;Author&amp;gt; GetAuthors();

    Author GetAuthorById(int id);

    Author AddAuthor(Author author);
}

public class LibraryRepository : ILibraryRepository
{
    private readonly LibraryContext _context;

    public LibraryRepository(LibraryContext context)
    {
        _context = context;
    }

    public IEnumerable&amp;lt;Book&amp;gt; GetBooks() =&amp;gt; _context.Books.Include(b =&amp;gt; b.Author).ToList();

    public Book GetBookById(int id) =&amp;gt; _context.Books.Include(b =&amp;gt; b.Author).FirstOrDefault(b =&amp;gt; b.Id == id);

    public Book AddBook(string title, int authorId)
    {
        var book = new Book { Title = title, AuthorId = authorId };
        _context.Books.Add(book);
        _context.SaveChanges();
        return book;
    }

    public IEnumerable&amp;lt;Author&amp;gt; GetAuthors() =&amp;gt; _context.Authors.Include(a =&amp;gt; a.Books).ToList();

    public Author GetAuthorById(int id) =&amp;gt; _context.Authors.Include(a =&amp;gt; a.Books).FirstOrDefault(b =&amp;gt; b.Id == id);

    public Author AddAuthor(Author author)
    {
        _context.Authors.Add(author);
        _context.SaveChanges();
        return author;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 5: Set Up GraphQL Types
&lt;/h4&gt;

&lt;p&gt;Create GraphQL types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AuthorType : ObjectGraphType&amp;lt;Author&amp;gt;
{
    public AuthorType()
    {
        Field(x =&amp;gt; x.Id);
        Field(x =&amp;gt; x.Name);
        Field&amp;lt;ListGraphType&amp;lt;BookType&amp;gt;&amp;gt;("books", resolve: context =&amp;gt; context.Source.Books);
    }
}


public class BookType : ObjectGraphType&amp;lt;Book&amp;gt;
{
    public BookType()
    {
        Field(x =&amp;gt; x.Id);
        Field(x =&amp;gt; x.Title);
        Field&amp;lt;AuthorType&amp;gt;("author", resolve: context =&amp;gt; context.Source.Author);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 6: Define Queries and Mutations
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LibraryQuery : ObjectGraphType
{
    public LibraryQuery(ILibraryRepository repository)
    {
        Field&amp;lt;ListGraphType&amp;lt;BookType&amp;gt;&amp;gt;(
            "books",
            resolve: context =&amp;gt; repository.GetBooks());

        Field&amp;lt;BookType&amp;gt;(
            "book",
            arguments: new QueryArguments(new QueryArgument&amp;lt;IntGraphType&amp;gt; { Name = "id" }),
            resolve: context =&amp;gt; repository.GetBookById(context.GetArgument&amp;lt;int&amp;gt;("id")));

        Field&amp;lt;ListGraphType&amp;lt;AuthorType&amp;gt;&amp;gt;(
            "authors",
            resolve: context =&amp;gt; repository.GetAuthors());

        Field&amp;lt;AuthorType&amp;gt;(
            "author",
            arguments: new QueryArguments(new QueryArgument&amp;lt;IntGraphType&amp;gt; { Name = "id" }),
            resolve: context =&amp;gt; repository.GetAuthorById(context.GetArgument&amp;lt;int&amp;gt;("id")));
    }
}

public class LibraryMutation : ObjectGraphType
{
    public LibraryMutation(ILibraryRepository repository)
    {
        Field&amp;lt;BookType&amp;gt;(
            "addBook",
            arguments: new QueryArguments(
                new QueryArgument&amp;lt;NonNullGraphType&amp;lt;StringGraphType&amp;gt;&amp;gt; { Name = "title" },
                new QueryArgument&amp;lt;NonNullGraphType&amp;lt;IntGraphType&amp;gt;&amp;gt; { Name = "authorId" }),
            resolve: context =&amp;gt;
            {
                var title = context.GetArgument&amp;lt;string&amp;gt;("title");
                var authorId = context.GetArgument&amp;lt;int&amp;gt;("authorId");
                return repository.AddBook(title, authorId);
            });

        Field&amp;lt;AuthorType&amp;gt;(
            "addAuthor",
            arguments: new QueryArguments(
                new QueryArgument&amp;lt;NonNullGraphType&amp;lt;StringGraphType&amp;gt;&amp;gt; { Name = "name" }),
            resolve: context =&amp;gt;
            {
                var name = context.GetArgument&amp;lt;string&amp;gt;("name");
                var author = new Author
                {
                    Name = name,
                    Books = new List&amp;lt;Book&amp;gt;() // Initialize books list as needed
                };
                return repository.AddAuthor(author);
            });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 7: Define Schema
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LibrarySchema : Schema
{
    public LibrarySchema(IServiceProvider provider) : base(provider)
    {
        Query = provider.GetRequiredService&amp;lt;LibraryQuery&amp;gt;();
        Mutation = provider.GetRequiredService&amp;lt;LibraryMutation&amp;gt;();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 8: Configure program.cs
&lt;/h4&gt;

&lt;p&gt;In your program.cs file add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var connectionString = builder.Configuration.GetConnectionString("LibraryContext");
builder.Services.AddDbContext&amp;lt;LibraryContext&amp;gt;(options =&amp;gt;
        options.UseSqlServer(connectionString));

builder.Services.AddScoped&amp;lt;ILibraryRepository, LibraryRepository&amp;gt;();

builder.Services.AddScoped&amp;lt;BookType&amp;gt;();
builder.Services.AddScoped&amp;lt;AuthorType&amp;gt;();
builder.Services.AddScoped&amp;lt;LibraryQuery&amp;gt;();
builder.Services.AddScoped&amp;lt;LibraryMutation&amp;gt;();
builder.Services.AddScoped&amp;lt;ISchema, LibrarySchema&amp;gt;();

builder.Services.AddGraphQL(b =&amp;gt; b.AddSystemTextJson());

pp.UseGraphQL&amp;lt;ISchema&amp;gt;();
app.UseGraphQLGraphiQL();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 9: Test API
&lt;/h4&gt;

&lt;p&gt;To test the graphQL API, I used GraphiQL. You must run your api and append '/ui/graphiql' to the API url to launch the playground.&lt;/p&gt;

&lt;p&gt;An example of a mutation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8pv78nid49y0mnddjt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8pv78nid49y0mnddjt5.png" alt="Image description" width="800" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example of a query:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k3tx8zvtrnf1fhgzd64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k3tx8zvtrnf1fhgzd64.png" alt="Image description" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it guys, a simple use of graphQL, I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>learning</category>
      <category>graphql</category>
    </item>
    <item>
      <title>First experience with gRPC</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 21 Jun 2024 14:30:34 +0000</pubDate>
      <link>https://dev.to/vzldev/first-experience-with-grpc-497n</link>
      <guid>https://dev.to/vzldev/first-experience-with-grpc-497n</guid>
      <description>&lt;p&gt;I heard some colleagues talking about gRPC framework and its benefits and advantages regarding Rest, so I dig a little in the gRPC world and its concepts to learn new ways to develop an API.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is gRPC?
&lt;/h3&gt;

&lt;p&gt;gRPC is an open-source API architecture and system. It’s based on the Remote Procedure Call (RPC) model. While the RPC model is broad, gRPC is a specific implementation.&lt;br&gt;
gRPC is a system that implements traditional RPC with several optimizations. For instance, gRPC uses Protocol Buffers and HTTP 2 for data transmission. It also abstracts the data exchange mechanism from the developer.&lt;/p&gt;
&lt;h3&gt;
  
  
  gRPC vs REST
&lt;/h3&gt;

&lt;p&gt;The following image compares the basics of REST APIs and gRPC:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2egdqgsezavydvnc7dx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2egdqgsezavydvnc7dx2.png" alt="Image description" width="793" height="192"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;To better learn the gRPC concepts, I created a simple chat room scenario.&lt;/p&gt;
&lt;h4&gt;
  
  
  Project Setup
&lt;/h4&gt;

&lt;p&gt;We'll create two projects within a solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ChatAppServer: The gRPC server that handles chat room logic.&lt;/li&gt;
&lt;li&gt;ChatAppClient: The client application that users will run to join chat rooms and send messages (This is a console App project).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we'll install the following nuget packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grpc.AspNetCore&lt;/li&gt;
&lt;li&gt;Grpc.Tools&lt;/li&gt;
&lt;li&gt;Grpc.AspNetCore.Server.ClientFactory (this one only on the ChatAppClient project)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Proto file
&lt;/h4&gt;

&lt;p&gt;We'll need to create a '.proto' file to define the gRPC service. This file specifies the service methods and message types.&lt;br&gt;
This is my chat.proto file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

option csharp_namespace = "ChatApp";

package chat;

service ChatService {
  rpc JoinRoom (JoinRoomRequest) returns (JoinRoomResponse);
  rpc SendMessage (SendMessageRequest) returns (SendMessageResponse);
  rpc ReceiveMessages (ReceiveMessagesRequest) returns (stream ChatMessage);
}

message JoinRoomRequest {
  string username = 1;
  string room = 2;
}

message JoinRoomResponse {
  bool success = 1;
}

message SendMessageRequest {
  string username = 1;
  string room = 2;
  string message = 3;
}

message SendMessageResponse {
  bool success = 1;
}

message ReceiveMessagesRequest {
  string room = 1;
}

message ChatMessage {
  string username = 1;
  string message = 2;
  int64 timestamp = 3;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;We have to include the .proto file on the .csproj so we can enable the code generator&lt;/strong&gt;, so on the ChatAppServer.csproj file add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobuf Include="Protos\chat.proto" GrpcServices="Server" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on the ChatAppClient.csproj add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobuf Include="Protos\chat.proto" GrpcServices="Client" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, if we clean, restore and build the projects, the code will be generated and you can check it out on the path "obj\Debug\net6.0\Protos".&lt;/p&gt;

&lt;h4&gt;
  
  
  Implement the server
&lt;/h4&gt;

&lt;p&gt;In the server project, implement the ChatService.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using ChatApp;
using Grpc.Core;
using Microsoft.Extensions.Logging;

namespace ChatAppServer.Services
{
    public class ChatServiceImpl : ChatService.ChatServiceBase
    {
        private static readonly ConcurrentDictionary&amp;lt;string, List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;&amp;gt; _rooms = new ConcurrentDictionary&amp;lt;string, List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;&amp;gt;();

        public override Task&amp;lt;JoinRoomResponse&amp;gt; JoinRoom(JoinRoomRequest request, ServerCallContext context)
        {
            if (!_rooms.ContainsKey(request.Room))
            {
                _rooms[request.Room] = new List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;();
            }
            return Task.FromResult(new JoinRoomResponse { Success = true });
        }

        public override Task&amp;lt;SendMessageResponse&amp;gt; SendMessage(SendMessageRequest request, ServerCallContext context)
        {
            if (_rooms.TryGetValue(request.Room, out var clients))
            {
                var message = new ChatMessage
                {
                    Username = request.Username,
                    Message = request.Message,
                    Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
                };

                foreach (var client in clients)
                {
                    client.WriteAsync(message);
                }
            }
            return Task.FromResult(new SendMessageResponse { Success = true });
        }

        public override async Task ReceiveMessages(ReceiveMessagesRequest request, IServerStreamWriter&amp;lt;ChatMessage&amp;gt; responseStream, ServerCallContext context)
        {
            if (_rooms.TryGetValue(request.Room, out var clients))
            {
                clients.Add(responseStream);
                try
                {
                    await Task.Delay(Timeout.Infinite, context.CancellationToken);
                }
                finally
                {
                    clients.Remove(responseStream);
                }
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we need to add the following on the Progra.cs file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddGrpc();
app.MapGrpcService&amp;lt;ChatServiceImpl&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implement the client
&lt;/h4&gt;

&lt;p&gt;Modify the Program.cs file of the client project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;
using System.Threading.Tasks;
using Grpc.Net.Client;
using ChatApp;
using Grpc.Core;

class Program
{
    static async Task Main(string[] args)
    {
        // Create a channel to the gRPC server
        var channel = GrpcChannel.ForAddress("https://localhost:7187");
        var client = new ChatService.ChatServiceClient(channel);

        Console.WriteLine("Enter your username:");
        var username = Console.ReadLine();

        Console.WriteLine("Enter the room you want to join:");
        var room = Console.ReadLine();

        // Join the specified room
        var joinResponse = await client.JoinRoomAsync(new JoinRoomRequest
        {
            Username = username,
            Room = room
        });

        if (joinResponse.Success)
        {
            Console.WriteLine($"Joined room: {room}");
        }
        else
        {
            Console.WriteLine("Failed to join room");
            return;
        }

        // Task for receiving messages
        var receiveTask = Task.Run(async () =&amp;gt;
        {
            using var call = client.ReceiveMessages(new ReceiveMessagesRequest { Room = room });
            await foreach (var message in call.ResponseStream.ReadAllAsync())
            {
                Console.WriteLine($"[{message.Username}] {message.Message}");
            }
        });

        // Loop to send messages
        while (true)
        {
            var message = Console.ReadLine();
            if (message.ToLower() == "exit") break;

            var sendMessageResponse = await client.SendMessageAsync(new SendMessageRequest
            {
                Username = username,
                Room = room,
                Message = message
            });

            if (!sendMessageResponse.Success)
            {
                Console.WriteLine("Failed to send message");
            }
        }

        // Wait for the receiving task to complete
        await receiveTask;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the application
&lt;/h2&gt;

&lt;p&gt;Use the &lt;strong&gt;dotnet run&lt;/strong&gt; command to run the projects.&lt;br&gt;
Open 2 terminals of clients to interact with each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j6vq2nrz2bsxzi3recj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j6vq2nrz2bsxzi3recj.png" alt="Image description" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbctzuv8ufntv8r8hw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbctzuv8ufntv8r8hw3.png" alt="Image description" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is still a very simple case of implementing gRPC framework to develop an API, and I still have a lot to work on and learn about this, I'm very excited!&lt;/p&gt;

&lt;p&gt;And that's it guys, I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>grpc</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>learning</category>
    </item>
    <item>
      <title>First experience with gRPC</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 21 Jun 2024 14:30:34 +0000</pubDate>
      <link>https://dev.to/vzldev/first-experience-with-grpc-1bhb</link>
      <guid>https://dev.to/vzldev/first-experience-with-grpc-1bhb</guid>
      <description>&lt;p&gt;I heard some colleagues talking about gRPC framework and its benefits and advantages regarding Rest, so I dig a little in the gRPC world and its concepts to learn new ways to develop an API.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is gRPC?
&lt;/h3&gt;

&lt;p&gt;gRPC is an open-source API architecture and system. It’s based on the Remote Procedure Call (RPC) model. While the RPC model is broad, gRPC is a specific implementation.&lt;br&gt;
gRPC is a system that implements traditional RPC with several optimizations. For instance, gRPC uses Protocol Buffers and HTTP 2 for data transmission. It also abstracts the data exchange mechanism from the developer.&lt;/p&gt;
&lt;h3&gt;
  
  
  gRPC vs REST
&lt;/h3&gt;

&lt;p&gt;The following image compares the basics of REST APIs and gRPC:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2egdqgsezavydvnc7dx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2egdqgsezavydvnc7dx2.png" alt="Image description" width="793" height="192"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;To better learn the gRPC concepts, I created a simple chat room scenario.&lt;/p&gt;
&lt;h4&gt;
  
  
  Project Setup
&lt;/h4&gt;

&lt;p&gt;We'll create two projects within a solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ChatAppServer: The gRPC server that handles chat room logic.&lt;/li&gt;
&lt;li&gt;ChatAppClient: The client application that users will run to join chat rooms and send messages (This is a console App project).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we'll install the following nuget packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grpc.AspNetCore&lt;/li&gt;
&lt;li&gt;Grpc.Tools&lt;/li&gt;
&lt;li&gt;Grpc.AspNetCore.Server.ClientFactory (this one only on the ChatAppClient project)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Proto file
&lt;/h4&gt;

&lt;p&gt;We'll need to create a '.proto' file to define the gRPC service. This file specifies the service methods and message types.&lt;br&gt;
This is my chat.proto file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

option csharp_namespace = "ChatApp";

package chat;

service ChatService {
  rpc JoinRoom (JoinRoomRequest) returns (JoinRoomResponse);
  rpc SendMessage (SendMessageRequest) returns (SendMessageResponse);
  rpc ReceiveMessages (ReceiveMessagesRequest) returns (stream ChatMessage);
}

message JoinRoomRequest {
  string username = 1;
  string room = 2;
}

message JoinRoomResponse {
  bool success = 1;
}

message SendMessageRequest {
  string username = 1;
  string room = 2;
  string message = 3;
}

message SendMessageResponse {
  bool success = 1;
}

message ReceiveMessagesRequest {
  string room = 1;
}

message ChatMessage {
  string username = 1;
  string message = 2;
  int64 timestamp = 3;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;We have to include the .proto file on the .csproj so we can enable the code generator&lt;/strong&gt;, so on the ChatAppServer.csproj file add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobuf Include="Protos\chat.proto" GrpcServices="Server" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on the ChatAppClient.csproj add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobuf Include="Protos\chat.proto" GrpcServices="Client" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, if we clean, restore and build the projects, the code will be generated and you can check it out on the path "obj\Debug\net6.0\Protos".&lt;/p&gt;

&lt;h4&gt;
  
  
  Implement the server
&lt;/h4&gt;

&lt;p&gt;In the server project, implement the ChatService.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using ChatApp;
using Grpc.Core;
using Microsoft.Extensions.Logging;

namespace ChatAppServer.Services
{
    public class ChatServiceImpl : ChatService.ChatServiceBase
    {
        private static readonly ConcurrentDictionary&amp;lt;string, List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;&amp;gt; _rooms = new ConcurrentDictionary&amp;lt;string, List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;&amp;gt;();

        public override Task&amp;lt;JoinRoomResponse&amp;gt; JoinRoom(JoinRoomRequest request, ServerCallContext context)
        {
            if (!_rooms.ContainsKey(request.Room))
            {
                _rooms[request.Room] = new List&amp;lt;IServerStreamWriter&amp;lt;ChatMessage&amp;gt;&amp;gt;();
            }
            return Task.FromResult(new JoinRoomResponse { Success = true });
        }

        public override Task&amp;lt;SendMessageResponse&amp;gt; SendMessage(SendMessageRequest request, ServerCallContext context)
        {
            if (_rooms.TryGetValue(request.Room, out var clients))
            {
                var message = new ChatMessage
                {
                    Username = request.Username,
                    Message = request.Message,
                    Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
                };

                foreach (var client in clients)
                {
                    client.WriteAsync(message);
                }
            }
            return Task.FromResult(new SendMessageResponse { Success = true });
        }

        public override async Task ReceiveMessages(ReceiveMessagesRequest request, IServerStreamWriter&amp;lt;ChatMessage&amp;gt; responseStream, ServerCallContext context)
        {
            if (_rooms.TryGetValue(request.Room, out var clients))
            {
                clients.Add(responseStream);
                try
                {
                    await Task.Delay(Timeout.Infinite, context.CancellationToken);
                }
                finally
                {
                    clients.Remove(responseStream);
                }
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we need to add the following on the Progra.cs file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddGrpc();
app.MapGrpcService&amp;lt;ChatServiceImpl&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implement the client
&lt;/h4&gt;

&lt;p&gt;Modify the Program.cs file of the client project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;
using System.Threading.Tasks;
using Grpc.Net.Client;
using ChatApp;
using Grpc.Core;

class Program
{
    static async Task Main(string[] args)
    {
        // Create a channel to the gRPC server
        var channel = GrpcChannel.ForAddress("https://localhost:7187");
        var client = new ChatService.ChatServiceClient(channel);

        Console.WriteLine("Enter your username:");
        var username = Console.ReadLine();

        Console.WriteLine("Enter the room you want to join:");
        var room = Console.ReadLine();

        // Join the specified room
        var joinResponse = await client.JoinRoomAsync(new JoinRoomRequest
        {
            Username = username,
            Room = room
        });

        if (joinResponse.Success)
        {
            Console.WriteLine($"Joined room: {room}");
        }
        else
        {
            Console.WriteLine("Failed to join room");
            return;
        }

        // Task for receiving messages
        var receiveTask = Task.Run(async () =&amp;gt;
        {
            using var call = client.ReceiveMessages(new ReceiveMessagesRequest { Room = room });
            await foreach (var message in call.ResponseStream.ReadAllAsync())
            {
                Console.WriteLine($"[{message.Username}] {message.Message}");
            }
        });

        // Loop to send messages
        while (true)
        {
            var message = Console.ReadLine();
            if (message.ToLower() == "exit") break;

            var sendMessageResponse = await client.SendMessageAsync(new SendMessageRequest
            {
                Username = username,
                Room = room,
                Message = message
            });

            if (!sendMessageResponse.Success)
            {
                Console.WriteLine("Failed to send message");
            }
        }

        // Wait for the receiving task to complete
        await receiveTask;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the application
&lt;/h2&gt;

&lt;p&gt;Use the &lt;strong&gt;dotnet run&lt;/strong&gt; command to run the projects.&lt;br&gt;
Open 2 terminals of clients to interact with each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j6vq2nrz2bsxzi3recj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2j6vq2nrz2bsxzi3recj.png" alt="Image description" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbctzuv8ufntv8r8hw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbctzuv8ufntv8r8hw3.png" alt="Image description" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is still a very simple case of implementing gRPC framework to develop an API, and I still have a lot to work on and learn about this, I'm very excited!&lt;/p&gt;

&lt;p&gt;And that's it guys, I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>grpc</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>learning</category>
    </item>
    <item>
      <title>Use Kafka in your Web Api</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 14 Jun 2024 17:34:26 +0000</pubDate>
      <link>https://dev.to/vzldev/use-kafka-in-your-web-api-38ha</link>
      <guid>https://dev.to/vzldev/use-kafka-in-your-web-api-38ha</guid>
      <description>&lt;p&gt;Hello guys!&lt;br&gt;
Today I challenged myself to learn a little bit about event streaming, so I created an example using Kafka.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is event streaming?
&lt;/h2&gt;

&lt;p&gt;Event streaming is the practice of capturing data in real-time from event sources like databases, sensors, mobile devices, cloud services, and software applications in the form of streams of events; storing these event streams durably for later retrieval; manipulating, processing, and reacting to the event streams in real-time as well as retrospectively; and routing the event streams to different destination technologies as needed. (&lt;a href="https://kafka.apache.org/intro"&gt;https://kafka.apache.org/intro&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Kafka?
&lt;/h2&gt;

&lt;p&gt;Kafka is an event streaming platform, that allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write/read data.&lt;/li&gt;
&lt;li&gt;Store data.&lt;/li&gt;
&lt;li&gt;Process data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Key Kafka Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event&lt;/strong&gt;, the events in a nutshell are the data that we'll store. It can also be called record or message. When you read or write data to Kafka, you do this in the form of events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Topic&lt;/strong&gt;, is the place where the events will be stored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Producers&lt;/strong&gt; are those client applications that publish (write) events to Kafka&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumers&lt;/strong&gt;are those that subscribe to (read and process) events&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my project, i made changes to my EventsAPI, so that now when a user is registered in an event, i will store some data in a topic, that a new LogsApi will read and store in a db.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using Kafka step by step
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;To start using Kafka I recommend using an image container and run that image in the docker container.&lt;br&gt;
After you pull the image, run it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;p&gt;In your Producer and Consumer API install the following nuget package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confluent.Kafka&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzk8wzosc2mvlxgnqx48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzk8wzosc2mvlxgnqx48.png" alt="Image description" width="800" height="56"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;p&gt;Update your producer api to write data to a kafka topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Route("[controller]")]
[ApiController]
public class EventEnrollmentController : ControllerBase
{
    protected IEventsRepository _repository;
    private readonly IProducer&amp;lt;string, string&amp;gt; _producer;

    public EventEnrollmentController(IEventsRepository repository)
    {
        _repository = repository;
        var config = new ProducerConfig { BootstrapServers = "localhost:9092" };
        _producer = new ProducerBuilder&amp;lt;string, string&amp;gt;(config).Build();
    }

    [HttpPut("{eventId}/register")]
    public async Task&amp;lt;ActionResult&amp;lt;bool&amp;gt;&amp;gt; AddUserToEvent(Guid userId, Guid eventId)
    {
        Event evento = await _repository.GetEventById(eventId);

        if (evento == null)
        {
            return NotFound();
        }

        evento.Users.Add(userId);

        LogEntry log = new LogEntry()
        {
            Id = Guid.NewGuid(),
            EventTitle = evento.Title,
            UserId = userId,
            RegistrationTime = DateTime.UtcNow,
        };

        await _producer.ProduceAsync("user-event-registrations", new Message&amp;lt;string, string&amp;gt;
        {
            Key = "UserEventRegistered",
            Value = JsonConvert.SerializeObject(log)
        });

        return await _repository.UpdateEvent(evento);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, a topic called &lt;em&gt;user-event-registrations&lt;/em&gt; is created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;p&gt;On your consumer API, do the following changes, so it will consume data of the &lt;em&gt;user-event-registrations&lt;/em&gt; topic&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LogService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IConsumer&amp;lt;string, string&amp;gt; _consumer;
    private readonly ILogger&amp;lt;LogService&amp;gt; _logger;

    public LogService(IServiceProvider serviceProvider, ILogger&amp;lt;LogService&amp;gt; logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;

        var config = new ConsumerConfig
        {
            GroupId = "log-group",
            BootstrapServers = "localhost:9092",
            AutoOffsetReset = AutoOffsetReset.Earliest
        };
        _consumer = new ConsumerBuilder&amp;lt;string, string&amp;gt;(config).Build();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _consumer.Subscribe("user-event-registrations");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                var consumeResult = _consumer.Consume(stoppingToken);
                var registration = JsonConvert.DeserializeObject&amp;lt;LogEntry&amp;gt;(consumeResult.Message.Value);

                using (var scope = _serviceProvider.CreateScope())
                {
                    var context = scope.ServiceProvider.GetRequiredService&amp;lt;LogContext&amp;gt;();

                    context.LogEntries.Add(registration);
                    await context.SaveChangesAsync(stoppingToken);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing Kafka message.");
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to add the dependencies to your Program.cs file.&lt;/p&gt;

&lt;p&gt;And that's it guys, a simple use case of event streaming using Kafka. I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create a API Gateway using Ocelot</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 14 Jun 2024 17:10:30 +0000</pubDate>
      <link>https://dev.to/vzldev/create-a-api-gateway-using-ocelot-3nh3</link>
      <guid>https://dev.to/vzldev/create-a-api-gateway-using-ocelot-3nh3</guid>
      <description>&lt;p&gt;Hello guys!&lt;br&gt;
Today I challenged myself to learn a little bit about Api Gateway, so I created one in my project using Ocelot.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is an API Gateway?
&lt;/h2&gt;

&lt;p&gt;An API gateway is a server that acts as an intermediary between clients and backend services. It functions as a reverse proxy to accept all application programming interface (API) calls, aggregate the various services required to fulfill them, and return the appropriate result.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Ocelot?
&lt;/h2&gt;

&lt;p&gt;Ocelot is an open-source API Gateway built on the .NET platform. It is designed to manage and secure the flow of traffic between clients and backend services, particularly in microservices architectures. Ocelot provides a range of features to facilitate the handling of API requests and responses.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to create an API Gateway using Ocelot step by step?
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;First of all, you need to set up 2 different API's&lt;/strong&gt;, in my project I created an UsersAPI and an EventsAPI&lt;br&gt;
I have the following endpoints for the 2 controllers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://localhost:7235/Events"&gt;https://localhost:7235/Events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://localhost:7239/Users"&gt;https://localhost:7239/Users&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;p&gt;Next you'll need to create a new api for the gateway, and do not add any controller.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;p&gt;Add the Ocelot package to your gateway api.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4xmrzucgjscs6vqieu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4xmrzucgjscs6vqieu7.png" alt="Image description" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;strong&gt;ocelot.json&lt;/strong&gt; in your gateway api.&lt;br&gt;
Here's mine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Routes": [
    {
      "DownstreamPathTemplate": "/users/{everything}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7239
        }
      ],
      "UpstreamPathTemplate": "/api/users/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
    },
    {
      "DownstreamPathTemplate": "/events/{everything}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7235
        }
      ],
      "UpstreamPathTemplate": "/api/events/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:7174"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the GlobalConfiguration section, the BaseUrl is the URL of the API Gateway. When running the API Gateway it will run on this base URL and the users will interact with this URL.&lt;/li&gt;
&lt;li&gt;The UpStreamPathTemplate section represents the API Gateway endpoint, this will be the public endpoint for the users to ping.&lt;/li&gt;
&lt;li&gt;The DownStreamTemplate section represents the APIs endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the above configuration, when you hit the endpoint &lt;a href="http://localhost:7174/api/events"&gt;http://localhost:7174/api/events&lt;/a&gt;, it will be redirected to API endpoint &lt;a href="http://localhost:7235/Events"&gt;http://localhost:7235/Events&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5
&lt;/h2&gt;

&lt;p&gt;In your program.cs file, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

builder.Services.AddOcelot(builder.Configuration);

app.UseOcelot();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6
&lt;/h2&gt;

&lt;p&gt;Try yourself and enjoy!&lt;/p&gt;

&lt;p&gt;And that's it guys, a simple use case of using an api gateway with ocelot. I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>apigateway</category>
      <category>ocelot</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Create a Web API with MongoDB</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 14 Jun 2024 16:45:18 +0000</pubDate>
      <link>https://dev.to/vzldev/create-a-web-api-with-mongodb-16kn</link>
      <guid>https://dev.to/vzldev/create-a-web-api-with-mongodb-16kn</guid>
      <description>&lt;p&gt;Hello guys!&lt;br&gt;
Today I challenged myself to learn a little bit about MongoDB, so I created an API that will connect to a MongoDB database.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is MongoDB?
&lt;/h2&gt;

&lt;p&gt;MongoDB is a NOSQL database and NOSQL means "Not Only SQL". This is because MongoDB is not only a relational database. NOSQL can store unstructured data.&lt;/p&gt;

&lt;p&gt;MongoDB is a document database. It stores data in a type of JSON format called BSON. A record in MongoDB is a document, which is a data structure composed of key value pairs similar to the structure of JSON objects.&lt;br&gt;
And this documents are stored in collections (you can compare a collection like as a table in SQL Relational databases). And all this collections are stored in a database!&lt;/p&gt;
&lt;h2&gt;
  
  
  MongoDB Setup
&lt;/h2&gt;

&lt;p&gt;To start using MongoDB the first thing that you need is the MongoDB "engine". For that I recommend using a image container and run that image in the docker container.&lt;/p&gt;

&lt;p&gt;After pull the image and run it, you need a way to interact with the database. I used MongoDB Compass.&lt;/p&gt;
&lt;h2&gt;
  
  
  MongoDB integration
&lt;/h2&gt;

&lt;p&gt;To integrate your MongoDB database with your .NET API, you'll need to install the following nuget package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB.Driver
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg4r360duwi5qw20rij9.png" alt="Image description" width="800" height="70"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have in the Model folder a Event class that represent the document in MongoDB.&lt;br&gt;
Important thing to notice here is there is specific Data Annotations to handle MongoDB data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Event
{
    [BsonId]
    public Guid EventId { get; set; }

    [BsonElement("title")]
    public string Title { get; set; }

    [BsonElement("description")]
    public string Description { get; set; }

    [BsonElement("location")]
    public string Location { get; set; }

    [BsonElement("date")]
    public DateTime Date { get; set; }

    [BsonElement("users")]
    public List&amp;lt;Guid&amp;gt; Users { get; set; } // List of users associated with the event
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing you need is to establish connection to the MongoDB. In this example I create a factory class to do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MongoDbConnection : IMongoDbConnection
{
    private readonly IConfiguration _configuration;

    public MongoDbConnection(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public IMongoDatabase GetDatabase()
    {
        var connectionString = _configuration.GetSection("MyDb").GetValue&amp;lt;string&amp;gt;("ConnectionString");
        var databaseName = _configuration.GetSection("MyDb").GetValue&amp;lt;string&amp;gt;("DatabaseName");

        var url = MongoUrl.Create(connectionString);
        var client = new MongoClient(url);
        var database = client.GetDatabase(databaseName);

        return database;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on the appsettings.json file, I added the connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"MyDb": {
  "ConnectionString": "mongodb://localhost:27017",
  "DatabaseName": "Eventsdb",
  "EventsCollectionName": "events"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created a repository class to interact with the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class EventsRepository : IEventsRepository
{
    private readonly IMongoDbConnection _connection;
    private readonly IMongoCollection&amp;lt;Event&amp;gt; _collection;

    public EventsRepository(IMongoDbConnection connection)
    {
        _connection = connection;

        var database = _connection.GetDatabase();
        _collection = database.GetCollection&amp;lt;Event&amp;gt;("events");
    }

    public async Task&amp;lt;bool&amp;gt; CreateEvent(Event evento)
    {
        try
        {
            await _collection.InsertOneAsync(evento);
            return true;
        }
        catch (Exception)
        {
            throw;
        }
    }

    public async Task&amp;lt;bool&amp;gt; DeleteEvent(Guid id)
    {
        var filterDefinition = Builders&amp;lt;Event&amp;gt;.Filter.Eq(a =&amp;gt; a.EventId, id);
        var result = await _collection.DeleteOneAsync(filterDefinition);
        return result.DeletedCount &amp;gt; 0;
    }

    public async Task&amp;lt;List&amp;lt;Event&amp;gt;&amp;gt; GetAllEvents()
    {
        return await _collection.Find(Builders&amp;lt;Event&amp;gt;.Filter.Empty).ToListAsync();
    }

    public async Task&amp;lt;Event&amp;gt; GetEventById(Guid id)
    {
        var filterDefinition = Builders&amp;lt;Event&amp;gt;.Filter.Eq(a =&amp;gt; a.EventId, id);
        return await _collection.Find(filterDefinition).FirstAsync();
    }

    public async Task&amp;lt;bool&amp;gt; UpdateEvent(Event evento)
    {
        var filterDefinition = Builders&amp;lt;Event&amp;gt;.Filter.Eq(a =&amp;gt; a.EventId, evento.EventId);
        var result = await _collection.ReplaceOneAsync(filterDefinition, evento);
        return result.ModifiedCount &amp;gt; 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it guys, a simple use case of using a api with mongodb. I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>dotnet</category>
      <category>api</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Redis Cache in .NET</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Mon, 18 Mar 2024 11:33:01 +0000</pubDate>
      <link>https://dev.to/vzldev/redis-cache-in-net-eoo</link>
      <guid>https://dev.to/vzldev/redis-cache-in-net-eoo</guid>
      <description>&lt;p&gt;Hello guys!&lt;/p&gt;

&lt;p&gt;Today I'll demonstrate how to implement Redis Cache in a .NET project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Redis Cache?
&lt;/h2&gt;

&lt;p&gt;Redis is an open source (BSD licensed), in-memory data structure store that can be used as a database, cache, message broker, and streaming engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Redis?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All Redis data resides in memory, which enables low latency and high throughput data access. Unlike traditional databases, In-memory data stores don’t require a trip to disk, reducing engine latency to microseconds. Because of this, in-memory data stores can support an order of magnitude more operations and faster response times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High availability and scalability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Source.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexible data structures.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You need to configure your Redis server. For that you can download and run an image of Redis in a docker container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytgm0laj7jbo6pqtggxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytgm0laj7jbo6pqtggxf.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once your Redis server is up and running you need to install the following nuget package&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft.Extensions.Caching.StackExchangeRedis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;On the ConnectionStrings section of the appsettings.json file, add the following entry&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "ConnectionStrings": {
    "Redis" : "localhost:6379"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Then you need to configure your connection to the Redis server in the &lt;code&gt;Program.cs&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddStackExchangeRedisCache(redisOptions =&amp;gt;
{
    string connection = builder.Configuration.GetConnectionString("Redis");
    redisOptions.Configuration = connection;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;On your controller, you'll need to inject &lt;code&gt;IDistributedCache&lt;/code&gt;via Dependency Injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        private readonly IDistributedCache? _cache;

        public TvShowsController(TvShowContext context, IDistributedCache cache)
        {
            _context = context;
            _cache = cache;
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Finally is time to store and retrieve values to and from your Redis Cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpGet]
        public ActionResult&amp;lt;IEnumerable&amp;lt;TvShow&amp;gt;&amp;gt; GetTvShows()
        {
            string cachedData = _cache.GetString("cachedData");
            if (string.IsNullOrEmpty(cachedData))
            {
                var tvShows = _context.TvShows.ToList();
                string serializedObject = JsonConvert.SerializeObject(tvShows);
                _cache.SetString("cachedData", serializedObject, new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) });
                return tvShows;
            }

            return JsonConvert.DeserializeObject&amp;lt;List&amp;lt;TvShow&amp;gt;&amp;gt;(cachedData);
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing Entity Framework: Code-First Approach</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 15 Mar 2024 15:52:10 +0000</pubDate>
      <link>https://dev.to/vzldev/implementing-entity-framework-code-first-approach-3lec</link>
      <guid>https://dev.to/vzldev/implementing-entity-framework-code-first-approach-3lec</guid>
      <description>&lt;p&gt;Hello guys! In this post I'm talk a little bit about Entity Framework (&lt;strong&gt;EF&lt;/strong&gt;), and how to implement it using the code-first approach.&lt;/p&gt;

&lt;p&gt;Entity Framework is an open-source object-relational mapping (ORM) framework for .NET applications developed by Microsoft. It simplifies the process of interaction with databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why choosing Entity Framework?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Using EF has several advantages like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Simplifies the interactions with databases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provides a high-level abstraction over the underlying database, hiding complex SQL queries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supports LINQ (Language Integrated Query).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supports multiple database providers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets start with the implementation of Entity Framework. For this tutorial I will use a scenario of TV Shows and store them in a db, with the possibility to execute CRUD operations on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;First of all you need to create a new .NET project.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Install the Entity Framework Core in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Add the Connection string to the Appsettings.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"ConnectionStrings": {
    "TvShowContext": "Server=(localdb)\\MSSQLLocalDB;Database=TvShows;Integrated Security=True;"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You need to create your model (for this tutorial only the TvShow.cs will be created)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class TvShow
    {
        [Key]
        public int Id { get; set; }

        public string Name { get; set; }

        public double ImdbRating { get; set; }

        public TvShow()
        {
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When you complete the creation of your model, it's time to set up the database context. This is the class that will allow interactions with the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public partial class TvShowContext : DbContext
    {
        public TvShowContext(DbContextOptions
        &amp;lt;TvShowContext&amp;gt; options)
            : base(options)
        {
        }
        public DbSet&amp;lt;TvShow&amp;gt; TvShows { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity&amp;lt;TvShow&amp;gt;(entity =&amp;gt;
            {
                entity.HasKey(k =&amp;gt; k.Id);
            });
            OnModelCreatingPartial(modelBuilder);
        }
        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now you need to update your Program.cs to add the database connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

//Add your connectionString and DBContext
var connectionString = builder.Configuration.GetConnectionString("TvShowContext");
builder.Services.AddDbContext&amp;lt;TvShowContext&amp;gt;(options =&amp;gt; options.UseSqlServer(connectionString));

builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this step you will run the first database migration, to create your database and table if it doesn't exist.&lt;br&gt;
Open the Package Manager Console in the Visual Studio and run the following command:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ADD-MIGRATION {MigrationName}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command will create a new folder "Migrations" in your project containing the migration files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6je7xo2xsnljwc05a5fs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6je7xo2xsnljwc05a5fs.png" alt="Image description" width="329" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the migration is created you must apply the migration to the database using the following command:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update-Database&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can go check the changes to your database.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step 8&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that you have all set up, it's time to create your controller to handle the requests for CRUD operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Route("[controller]")]
    [ApiController]
    public class TvShowsController : ControllerBase
    {
        private readonly TvShowContext _context;

        public TvShowsController(TvShowContext context)
        {
            _context = context;
        }

        [HttpGet]
        public ActionResult&amp;lt;IEnumerable&amp;lt;TvShow&amp;gt;&amp;gt; GetTvShows()
        {
            return _context.TvShows.ToList();
        }

        [HttpGet("{id}")]
        public ActionResult&amp;lt;TvShow&amp;gt; GetTvShow(int id)
        {
            var tvshow = _context.TvShows.Find(id);
            if (tvshow == null)
            {
                return NotFound();
            }
            return tvshow;
        }

        [HttpPost]
        public ActionResult&amp;lt;TvShow&amp;gt; CreateTvShow(TvShow tvShow)
        {
            if (tvShow == null)
            {
                return BadRequest();
            }
            _context.TvShows.Add(tvShow);
            _context.SaveChanges();
            return Ok();
        }

        [HttpDelete("{id}")]
        public ActionResult DeleteTvShow(int id)
        {
            var tvshow = _context.TvShows.Find(id);
            if (tvshow == null)
            {
                return NotFound();
            }
            _context.TvShows.Remove(tvshow);
            _context.SaveChanges();
            return NoContent();
        }

        [HttpPut("{id}")]
        public ActionResult&amp;lt;TvShow&amp;gt; UpdateTvShow(int id, TvShow tvShow)
        {
            var existingTvShow = _context.TvShows.Find(id);
            if (existingTvShow == null)
            {
                return NotFound();
            }

            existingTvShow.Name = tvShow.Name;
            existingTvShow.ImdbRating = tvShow.ImdbRating;

            _context.SaveChanges();
            return NoContent();
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Step 9&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Finally you can run your projects and use postman to do your requests, like for example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx1pgl2ipr6mnfx4d1p3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx1pgl2ipr6mnfx4d1p3.png" alt="Image description" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqf90hsv7tf6uj56f5rds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqf90hsv7tf6uj56f5rds.png" alt="Image description" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you liked it, stay tuned for more!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Bridge Pattern</title>
      <dc:creator>VzlDev</dc:creator>
      <pubDate>Fri, 15 Mar 2024 10:36:36 +0000</pubDate>
      <link>https://dev.to/vzldev/bridge-pattern-95c</link>
      <guid>https://dev.to/vzldev/bridge-pattern-95c</guid>
      <description>&lt;p&gt;Hello, today i'm gonna talk about a structural design pattern, more specifically about the Bridge design pattern and its advantages.&lt;/p&gt;

&lt;p&gt;The Bridge Pattern decouples an abstraction from its implementation, allowing them to vary independently. It is particularly useful when there are multiple dimensions of variability in a system. The pattern achieves this by creating two separate class hierarchies: one for the abstraction and another for the implementation. These hierarchies are then connected by composition rather than inheritance.&lt;/p&gt;

&lt;p&gt;Let's imagine that we go watch a movie, and the cinema have a promotion that is selling movie licenses, and we have the option to buy a 2 days movie license and a lifetime movie license. In top of that when purchasing these licenses, discounts may be applied, such as "Military discount" and "Senior Discount".&lt;br&gt;
So right now our code structure would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06u15e6n9ifhwi3e94po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06u15e6n9ifhwi3e94po.png" alt="Image description" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that doesn't seem correct. If the cinema wants to introduce here a 5 day movie license or imagine, a discount for students and another for their own workers, the code structure would be very confuse and hard to maintain.&lt;br&gt;
So we have to separate our concerns and divide the movie license and the movie discount, and our code structure should be something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyo4pv1l8re80kotahyzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyo4pv1l8re80kotahyzb.png" alt="Image description" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way is very easy to maintain our code and to introduce new licenses or discounts.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
