{"id":28351045,"url":"https://github.com/c5m7b4/kubernetes-net","last_synced_at":"2026-05-07T02:36:12.176Z","repository":{"id":78967420,"uuid":"561584698","full_name":"C5m7b4/kubernetes-net","owner":"C5m7b4","description":"Creating Microservices using .NET Core 6","archived":false,"fork":false,"pushed_at":"2022-11-08T22:37:22.000Z","size":7256,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-20T22:38:45.340Z","etag":null,"topics":["docker","grpc","kubernettes","nginx","rabbitqm","vscode"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/C5m7b4.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-11-04T02:25:27.000Z","updated_at":"2022-11-08T21:57:25.000Z","dependencies_parsed_at":"2023-05-02T19:31:45.791Z","dependency_job_id":null,"html_url":"https://github.com/C5m7b4/kubernetes-net","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/C5m7b4/kubernetes-net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C5m7b4%2Fkubernetes-net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C5m7b4%2Fkubernetes-net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C5m7b4%2Fkubernetes-net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C5m7b4%2Fkubernetes-net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/C5m7b4","download_url":"https://codeload.github.com/C5m7b4/kubernetes-net/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C5m7b4%2Fkubernetes-net/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32720524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","grpc","kubernettes","nginx","rabbitqm","vscode"],"created_at":"2025-05-27T22:08:56.978Z","updated_at":"2026-05-07T02:36:12.165Z","avatar_url":"https://github.com/C5m7b4.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kubernetes for .net cor apis\r\n\r\nfirstly I want to give a shoutout to a guy named Les Jackson. He put a video up on youtube that is an 11 hour course on microservices. If you have not watched, you can find it [here](https://www.youtube.com/watch?v=DgVjEo3OGBI)\r\n\r\nI really wanted to drive some of these concepts home for myself and possible others in the future, so I documented my entire 11 hour journey into this repo. Again, this not my work, but an inspiration, and something that can refer back to in the future when implementing microservices.\r\n\r\nfirstly we are going to create a blank folder in our dev directory\r\n\r\nthen we are going to initialize it\r\n\r\n```js\r\nnpm init -y\r\n```\r\n\r\nthen let's create a README.md in the root of the directory for our notes.\r\n\r\nnow we are going to create a file in the root called .gitignore. We'll add stuff to it as we see the need. This is not going to be a typical node project, so we won't use npx gitignore node.\r\n\r\nnow initial the git repository\r\n\r\n```js\r\ngit init\r\ngit add .\r\ngit commit -m \"initial commit\"\r\n```\r\n\r\nthen we are going to go ahead and link this up with our github repo. Refresh the page and we should see our readme and our repo should be setup and we are ready to get started.\r\n\r\nfirstly, we will create our first branch to work off of\r\n\r\n```js\r\ngit checkout -b branch1\r\n```\r\n\r\n## branch 1\r\n\r\n\r\n\r\nHere we are going to take a look at slides 01 through 03. I am not a powerpoint guy, but I give my best shot:\r\n\r\nnow we should play through the service architechture powerpoint presention:\r\n![alt service-archiceture](images/01-service-architecture.png)\r\n\r\nnow we should play through the platform service Architecture presention:\r\n\r\n![alt platform-service-architecture](images/02-platform-architecture.png)\r\n\r\nnow we should play through the command service Architecture presentation:\r\n\r\n![alt commmand-architecture](images/02-command-acrhitecture.png)\r\n\r\nthats it for our introduction into what we are going to build, so let's commit this sad powerpoint work and get to writing some code.\r\n\r\n## branch 4\r\n\r\nlet's get started by creating a few projects\r\n\r\nfirst lets check out version of .NET to make sure everything is cozy, so let's run\r\n\r\n```js\r\ndotnet --version\r\n```\r\n\r\n![alt dotnet-version](images/03-dotnet-version.png)\r\n\r\nfor our first project, we are going to run this command\r\n\r\n```js\r\ndotnet new webapi -n PlatformService\r\n```\r\n\r\nnow our folder structure should look something like this:\r\n\r\n![alt folder-structure](images/04-folder-structure.png)\r\n\r\nwe can open that folder in vscode by typing\r\n\r\n```js\r\ncode -r PlatformService\r\n```\r\n\r\nnow when this opens, you may see a prompt like this:\r\n\r\n![alt prompt](images/05-install%20prompt.png)\r\n\r\ndefinately choose yes, becuase this will give you the ability to debug your applications with ease.\r\n\r\nnow your folder structure inside of platform service should look like this:\r\n\r\n![alt platformservice-structure](images/06-platformservice-structure.png)\r\n\r\nthe first thing we are going to do with this project is to delete the WeatherForecast.csl file and delete the Controller for that as well.\r\n\r\nlet's open the PlatformService.csproj file so we can make sure that as we install our dependencies, that they actually get installed. This will be helpfull fo sure. So, let's install some dependencies:\r\n\r\n```js\r\ndotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection\r\ndotnet add package Microsoft.EntityFrameworkCore\r\ndotnet add package Microsoft.EntityFrameworkCore.Design\r\ndotnet add package Microsoft.EntityFrameworkCore.InMemory\r\ndotnet add package Microsoft.EntityFrameworkCore.SqlServer\r\n```\r\n\r\nnow your PlatformService.csproj should look like this:\r\n\r\n![alt packages](images/07-packages.png)\r\n\r\njust for clarity, i'll put the code here are well\r\n\r\n```js\r\n\u003cProject Sdk=\"Microsoft.NET.Sdk.Web\"\u003e\r\n\r\n  \u003cPropertyGroup\u003e\r\n    \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\r\n    \u003cNullable\u003eenable\u003c/Nullable\u003e\r\n    \u003cImplicitUsings\u003eenable\u003c/ImplicitUsings\u003e\r\n  \u003c/PropertyGroup\u003e\r\n\r\n  \u003cItemGroup\u003e\r\n    \u003cPackageReference Include=\"AutoMapper.Extensions.Microsoft.DependencyInjection\" Version=\"12.0.0\" /\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"6.0.10\" /\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"6.0.10\"\u003e\r\n      \u003cIncludeAssets\u003eruntime; build; native; contentfiles; analyzers; buildtransitive\u003c/IncludeAssets\u003e\r\n      \u003cPrivateAssets\u003eall\u003c/PrivateAssets\u003e\r\n    \u003c/PackageReference\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore.InMemory\" Version=\"6.0.10\" /\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore.SqlServer\" Version=\"6.0.10\" /\u003e\r\n    \u003cPackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.2.3\" /\u003e\r\n  \u003c/ItemGroup\u003e\r\n\r\n\u003c/Project\u003e\r\n\r\n```\r\n\r\n## branch 5\r\n\r\nnow, create a folder in the root of our project called Models and create a file inside of there called Platform.cs. This is what this file should look like. Its pretty straight forward\r\n\r\nas a side note, once your are in a class, you can add properties with the shortcut by just typing prop, and then you will get intellisence which will help you out.\r\n\r\n![alt shortcut](images/08-shortcut.png)\r\n\r\n```js\r\nnamespace PlatformService.Models\r\n{\r\n  public class Platform\r\n  {\r\n    public int Id { get; set; }\r\n    public string? Name { get; set; }\r\n    public string? Publisher { get; set; }\r\n    public string? Cost { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow we are going to add some annotations to this, but we are going to get some squigglies, so let's take a look at how to fix those squigglies:\r\n\r\n![alt squigglies](images/09-squigglies.png)\r\n\r\nso, to fix this, just put the cursor inside of the offending word, and press ctrl-. and you will get some intellisense that will allow you to import the correct using statement that you need.\r\n\r\n![alt helpers](images/010-helpers.png)\r\n\r\nso, now our class should look like this:\r\n\r\n```js\r\nusing System.ComponentModel.DataAnnotations;\r\n\r\nnamespace PlatformService.Models\r\n{\r\n  public class Platform\r\n  {\r\n    [Key]\r\n    [Required]\r\n    public int Id { get; set; }\r\n    [Required]\r\n\r\n    public string? Name { get; set; }\r\n    [Required]\r\n    public string? Publisher { get; set; }\r\n    [Required]\r\n    public string? Cost { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow, we are going to create our DbContext. Create a folder in the root of the project called Data and add a file inside of that called AppDbContext.cs\r\n\r\nanother shortcut that you can use is for creating constructors, so you just basically just type ctor and vscode will help you out. just press tab and vscode will automatically create a constructor for you.\r\n\r\n![alt ctor](images/011-ctor.png)\r\n\r\n```js\r\nusing Microsoft.EntityFrameworkCore;\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Data\r\n{\r\n  public class AppDbContext : DbContext\r\n  {\r\n    public AppDbContext(DbContextOptions\u003cAppDbContext\u003e opt) : base(opt)\r\n    {\r\n\r\n    }\r\n\r\n    public DbSet\u003cPlatform\u003e Platforms { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nthen we need to wire this up on our Program.cs file\r\n\r\n```js\r\nbuilder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e opt.UseInMemoryDatabase(\"InMem\"));\r\n```\r\n\r\n## branch 6\r\n\r\nnow we are going to add our repository. let's create an interface in the data folder. make a file named IPlatformRepo.cs\r\n\r\n```js\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Data\r\n{\r\n  public interface IPlatformRepo\r\n  {\r\n    bool SaveChanges();\r\n\r\n    IEnumerable\u003cPlatform\u003e GetAllPlatforms();\r\n    Platform GetPlatformById(int id);\r\n    void CreatePlatform(Platform plat);\r\n  }\r\n}\r\n```\r\n\r\nnow create the concrete class to inherit from out interface. Create a filed called PlatformRepo.cs in the data folder\r\n\r\none thing you will notice right off, is that vscode is not happy with us:\r\n\r\n![alt interfaces](images/012-interfaces.png)\r\n\r\nwe can use the same technique by putting the cursor inside of the word IPlatformRepo and pressing ctrl-. to get some intellisense:\r\n\r\n![alt implement-interface](images/013-implement-interface.png)\r\n\r\nafter you click on implement interface, vscode will automatically stub out all of the methods that you need in order to fulfill the contract between the two.\r\n\r\nit should not look like this:\r\n\r\n```js\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Data\r\n{\r\n  public class PlatformRepo : IPlatformRepo\r\n  {\r\n    public void CreatePlatform(Platform plat)\r\n    {\r\n      throw new NotImplementedException();\r\n    }\r\n\r\n    public IEnumerable\u003cPlatform\u003e GetAllPlatforms()\r\n    {\r\n      throw new NotImplementedException();\r\n    }\r\n\r\n    public Platform GetPlatformById(int id)\r\n    {\r\n      throw new NotImplementedException();\r\n    }\r\n\r\n    public bool SaveChanges()\r\n    {\r\n      throw new NotImplementedException();\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nlet's start to fill this file out. we should start with a constructor first. don't forget about the ctor shortcut\r\n\r\nlet's look at a stub for this what we will use a lot in the upcoming exercises\r\n\r\n![alt context](images/014-context.png)\r\n\r\nto fix this, put the cursor in the _context word and press ctrl-. and select create private read-only field:\r\n\r\n![alt read-only](images/015-read-only.png)\r\n\r\nlet's start at the bottom and fill out this class\r\n\r\n```js\r\n    public bool SaveChanges()\r\n    {\r\n      return (_context.SaveChanges() \u003e= 0);\r\n    }\r\n```\r\n\r\n```js\r\n    public IEnumerable\u003cPlatform\u003e GetAllPlatforms()\r\n    {\r\n      return _context.Platforms.ToList();\r\n    }\r\n```\r\n\r\n```js\r\n    public Platform GetPlatformById(int id)\r\n    {\r\n      var platform = _context.Platforms.FirstOrDefault(p =\u003e p.Id == id);\r\n      if (platform == null)\r\n      {\r\n        return new Platform { };\r\n      }\r\n      else\r\n      {\r\n        return platform;\r\n      }\r\n    }\r\n```\r\n\r\n```js\r\n    public void CreatePlatform(Platform plat)\r\n    {\r\n      if (plat == null)\r\n      {\r\n        throw new ArgumentNullException(nameof(plat));\r\n      }\r\n\r\n      _context.Platforms.Add(plat);\r\n    }\r\n```\r\n\r\nnow our final PlatformRepo.cs should look like this:\r\n\r\n```js\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Data\r\n{\r\n  public class PlatformRepo : IPlatformRepo\r\n  {\r\n    private readonly AppDbContext _context;\r\n\r\n    public PlatformRepo(AppDbContext context)\r\n    {\r\n      _context = context;\r\n    }\r\n    public void CreatePlatform(Platform plat)\r\n    {\r\n      if (plat == null)\r\n      {\r\n        throw new ArgumentNullException(nameof(plat));\r\n      }\r\n\r\n      _context.Platforms.Add(plat);\r\n    }\r\n\r\n    public IEnumerable\u003cPlatform\u003e GetAllPlatforms()\r\n    {\r\n      return _context.Platforms.ToList();\r\n    }\r\n\r\n    public Platform GetPlatformById(int id)\r\n    {\r\n      var platform = _context.Platforms.FirstOrDefault(p =\u003e p.Id == id);\r\n      if (platform == null)\r\n      {\r\n        return new Platform { };\r\n      }\r\n      else\r\n      {\r\n        return platform;\r\n      }\r\n    }\r\n\r\n    public bool SaveChanges()\r\n    {\r\n      return (_context.SaveChanges() \u003e= 0);\r\n    }\r\n  }\r\n}\r\n```\r\n\r\ninn order to be able to inject this into our constructors, we need to register this with our Program.cs file. This is an important step in the process:\r\n\r\nso, in Program.cs, add this little snippet of code:\r\n\r\n```js\r\nbuilder.Services.AddScoped\u003cIPlatformRepo, PlatformRepo\u003e();\r\n```\r\n\r\nnow, just to keep things tidy, we are going to make sure that our project builds:\r\n\r\n```js\r\ndotnet build\r\n```\r\n\r\nnow, you may see a warning here, but we'll take care of that later on:\r\n\r\n![alt build-error](images/016-build-error.png)\r\n\r\nbefore we commit this, we need to add some stuff to our gitignore, because right now there appears to be a lot of files to commit. first let's check to see where they are coming from:\r\n\r\nadd this to the .gitignore file\r\n\r\n```js\r\nbin\r\nobj\r\n```\r\n\r\nok, now we can commit this branch before we move on\r\n\r\n## branch 7\r\n\r\nnow we are going to seed out in-memory database so create a file in the Data folder called PrepDb.cs\r\n\r\nlet's just stub out the start of this file so we can add it to our Program.cs file:\r\n\r\n```js\r\nnamespace PlatformService.Data\r\n{\r\n  public static class PrepDb\r\n  {\r\n    public static void PrepPopulation(IApplicationBuilder app, bool isProd)\r\n    {\r\n\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nthen in our Program.cs file, let's add this snippet just before the app.Run() command:\r\n\r\n```js\r\nPrepDb.PrepPopulation(app, app.Environment.IsProduction());\r\n```\r\n\r\nAt first, our file looks like this:\r\n\r\n![alt prep-db](images/017-prep-db.png)\r\n\r\nso, lets get rid of that warning. go into the PlatformService.csproj file and commend out this line\r\n\r\n![alt comment](images/018-comment.png)\r\n\r\nnow you wll see that this error will go away\r\n\r\nnew this file should look like this:\r\n\r\n```js\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Data\r\n{\r\n  public static class PrepDb\r\n  {\r\n    public static void PrepPopulation(IApplicationBuilder app, bool isProd)\r\n    {\r\n      using (var serviceScope = app.ApplicationServices.CreateScope())\r\n      {\r\n        SeedData(serviceScope.ServiceProvider.GetService\u003cAppDbContext\u003e(), isProd);\r\n      }\r\n    }\r\n\r\n    private static void SeedData(AppDbContext context, bool isProd)\r\n    {\r\n      if (!context.Platforms.Any())\r\n      {\r\n        Console.WriteLine(\"--\u003e Seeding Data...\");\r\n        context.Platforms.AddRange(\r\n          new Platform() { Name = \"Dot Net\", Publisher = \"Microsoft\", Cost = \"Free\" },\r\n          new Platform() { Name = \"SQL Server Express\", Publisher = \"Microsoft\", Cost = \"Free\" },\r\n          new Platform() { Name = \"Kubernetes\", Publisher = \"Cloud Native Computing Foundation\", Cost = \"Free\" }\r\n        );\r\n\r\n        context.SaveChanges();\r\n      }\r\n      else\r\n      {\r\n        Console.WriteLine(\"--\u003e we already have data\");\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow just for safety, lets run a build\r\n\r\n```js\r\ndotnet build\r\n```\r\n\r\neverything should be good. oh wait, i noticed we got a lot of nullable warnings so lets go back to our Platform.cs class in the models folder and remove the ? character\r\n\r\n![alt build](images/019-build.png)\r\n\r\nnow let's run this command\r\n\r\n```js\r\ndotnet build\r\n```\r\n\r\nand we should see this:\r\n\r\n![alt seeding](images/020-seeding-data.png)\r\n\r\nwe want to make sure that we are seeing the Seeding Data in our console.\r\n\r\n## branch 8\r\n\r\nnow we are going to create some DTOs {Data Transformation Object}\r\n\r\nso, lets create another folder in the root of our project called Dtos and create a file inside of that called PlatformReadDto.cs\r\n\r\n```js\r\nnamespace PlatformService.Dtos\r\n{\r\n  public class PlatformReadDto\r\n  {\r\n    public int Id { get; set; }\r\n\r\n    public string Name { get; set; }\r\n\r\n    public string Publisher { get; set; }\r\n\r\n    public string Cost { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow let's create another Dto called PlatformCreateDto.cs\r\n\r\n```js\r\nusing System.ComponentModel.DataAnnotations;\r\n\r\nnamespace PlatformService.Dtos\r\n{\r\n  public class PlatformCreateDto\r\n  {\r\n    [Required]\r\n    public string Name { get; set; }\r\n    [Required]\r\n    public string Publisher { get; set; }\r\n    [Required]\r\n    public string Cost { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nso now we have our Dtos, but we need a way to map these to our model.\r\nlet's commit what we have and in the next branch, we will create our mappers.\r\n\r\n## branch 9\r\n\r\nfirstly, we need to register AutoMapper so in the Progam.cs file, we need to add this snippet:\r\n\r\n```js\r\nbuilder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());\r\n```\r\n\r\nin the root of our project, we are going to create a new folder called Profiles and in there we are going to create a new file called PlatformProfiles.cs\r\n\r\n```js\r\nusing AutoMapper;\r\nusing PlatformService.Dtos;\r\nusing PlatformService.Models;\r\n\r\nnamespace PlatformService.Profiles\r\n{\r\n  public class PlatformProfile : Profile\r\n  {\r\n    public PlatformProfile()\r\n    {\r\n      // source -\u003e target\r\n      CreateMap\u003cPlatform, PlatformReadDto\u003e();\r\n      CreateMap\u003cPlatformCreateDto, Platform\u003e();\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow let's make sure we don't have any errors, so we'll do a run\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\n## branch 10\r\n\r\nnow we are going to create our controller for this app, so let's create a file called PlatformsController.cs in the Controllers folder.\r\n\r\n```js\r\nusing AutoMapper;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing PlatformService.Data;\r\nusing PlatformService.Dtos;\r\n\r\nnamespace PlatformService.Controllers\r\n{\r\n  [Route(\"api/Platforms\")]\r\n  [ApiController]\r\n  public class PlatformsController : ControllerBase\r\n  {\r\n    private readonly IMapper _mapper;\r\n    private readonly IPlatformRepo _repo;\r\n\r\n    public PlatformsController(IPlatformRepo repo, IMapper mapper)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n    }\r\n\r\n    public ActionResult\u003cIEnumerable\u003cPlatformReadDto\u003e\u003e GetPlatforms()\r\n    {\r\n      Console.WriteLine(\"--\u003e Getting Platforms\");\r\n\r\n      var platformItem = _repo.GetAllPlatforms();\r\n\r\n      return Ok(_mapper.Map\u003cIEnumerable\u003cPlatformReadDto\u003e\u003e(platformItem));\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow let's test everythig out up to this point, so we'll run ths command\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\nnow we can actually test our work finally. We are going to use insomnia to test our api. here is the link to the [app](https://insomnia.rest/) or you can just type insomnia app into your brower and find the download\r\n\r\nonce that is loaded, we are going to go to the dashboard and create a new project:\r\n\r\n![alt create](images/012-create.png)\r\n\r\n![alt new](images/021-new.png)\r\n\r\n![alt kubernetes](images/022-kubernetes.png)\r\n\r\nnow we have a clean slate to work with for this project\r\n\r\nlet create a new folder for this project:\r\n\r\n![alt new-folder](images/023-new-folder.png)\r\n\r\nand we are going to call this new folder PlatformService\r\n\r\nnow we are going to create a new request to test out our service:\r\n\r\n![alt new-request](images/024-new-request.png)\r\n\r\nnow we need to figure out where our request needs to come from:\r\n\r\n![alt localhost](images/025-localhost.png)\r\n\r\nso, let's just fix this up by changing our ports, so open up Properties/luanchSettings.json and change the port to look like this:\r\n\r\n```js\r\n\"applicationUrl\": \"https://localhost:5001;http://localhost:5000\",\r\n```\r\n\r\nnow let's re-run the application\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\nand we should see the ports change\r\n\r\n![alt new-ports](images/026-new-ports.png)\r\n\r\nnow we are going to rename that request to 'Get all Platforms' and we are going to make it look like this:\r\n\r\n![alt platforms](images/027-platforms.png)\r\n\r\nwe have our first successfull endpoint. let's move on shall we.\r\n\r\nnow let's add an endpoint for getting a platform by it's id\r\n\r\n```js\r\n    [HttpGet(\"{id}\",Name = \"GetPlatformById\")]\r\n    public ActionResult\u003cPlatformReadDto\u003e GetPlatformById(int id)\r\n    {\r\n      var platformItem = _repo.GetPlatformById(id);\r\n\r\n      if (platformItem != null)\r\n      {\r\n        return Ok(_mapper.Map\u003cPlatformReadDto\u003e(platformItem));\r\n      }\r\n      else\r\n      {\r\n        return NotFound();\r\n      }\r\n    }\r\n```\r\n\r\nlet's spin it up and give that a try\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\nnow in insomnia, let's test our request like this:\r\n\r\n![alt get-platform-by-id](images/028-get-platform-by-id.png)\r\n\r\neverything is working well, so we need one more endpoint, then on to docker and then on to kubernetes. so, let's add that final endpoint to create a new platform\r\n\r\n```js\r\n    [HttpPost]\r\n    public ActionResult\u003cPlatformReadDto\u003e CreatePlatform(PlatformCreateDto platformCreateDto)\r\n    {\r\n      var platformModel = _mapper.Map\u003cPlatform\u003e(platformCreateDto);\r\n      _repo.CreatePlatform(platformModel);\r\n      _repo.SaveChanges();\r\n\r\n      var platformReadDto = _mapper.Map\u003cPlatformReadDto\u003e(platformModel);\r\n\r\n      return CreatedAtRoute(nameof(GetPlatformById), new { Id = platformReadDto.Id }, platformReadDto);\r\n    }\r\n```\r\n\r\nnow let's test it out\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\nand in insomnia, let's create a test like this:\r\none note, for this request, because it's going to be a post, we need to tell insomnia that we have a json body\r\n\r\n![alt json-body](images/029-json-body.png)\r\n\r\n![alt post](images/030-post.png)\r\n\r\nwe can also look at the headers to see the location parameter\r\n\r\n![alt location](images/032-headers.png)\r\n\r\nnow if we run our Get all Platforms again, we should see our new platform\r\n\r\n![alt get-all](images/031-get-all.png)\r\n\r\nbefore we wrap up this branch, let's take a look at debugging our app, as that is very important when things don't go as planned. To do this, let's look at the debug section of vscode.\r\n\r\n![alt debug-1](images/033-debug-1.png)\r\n\r\nhit the play button and run that endpoint in insomnia, and you should see the code break:\r\n\r\n![alt debug-2](images/034-debug-2.png)\r\n\r\nwe can also see that our app is running on two different ports:\r\n\r\n![alt ports](images/035-ports.png)\r\n\r\nlet's take a look at our swagger documentation\r\n\r\n![alt swagger](images/036-swagger.png)\r\n\r\n## branch 11\r\n\r\nmake sure you have docker desktop running firstly:\r\n\r\n![alt docker-desktop](images/037-docker-desktop.png)\r\n\r\nnow make sure to install the plugin into vscode\r\n\r\n![alt plugin](images/038-plugin.png)\r\n\r\nin the root of our project create a file called Dockerfile\r\n\r\nhere is how i am finding the image:\r\n\r\n![alt find](images/039-find.png)\r\n\r\n![alt docker-hub](images/040-docker-hub.png)\r\n\r\n![alt tags](images/041-tags.png)\r\n\r\n```js\r\nFROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env\r\n\r\nWORKDIR /app\r\n\r\nCOPY *.csproj ./\r\n\r\nRUN dotnet restore\r\n\r\nCOPY . ./\r\n\r\nRUN dotnet publish -c Release -o out\r\n\r\nFROM mcr.microsoft.com/dotnet/aspnet:6.0\r\n\r\nWORKDIR /app\r\n\r\nCOPY --from=build-env /app/out .\r\n\r\nENTRYPOINT [\"dotnet\", \"PlatformService.dll\"]\r\n```\r\n\r\nmake sure the filename matches with whats in the bin directory\r\n\r\n![alt dll](images/042-dll.png)\r\n\r\nnow let's check our version of docker\r\n\r\n![alt docker-version](images/043-docker-version.png)\r\n\r\nlet's now open up the Docker Desktop app and check to make sure that we have kubernetes enabled:\r\n\r\n![alt enable-kubernetes](images/044-enable-kubernetes.png)\r\n\r\n![alt enabled](images/045-running.png)\r\n\r\nnow let's build our first docker file\r\n\r\n```js\r\ndocker build -t c5m7b4/platformservice .\r\n```\r\n\r\nbe sure to use your docker hub username instead of mine and don't forget the period at the end, because that is the directory that it need to look to to find the Dockerfile. now your bash is going to go crazy, so no worries there and after it finishes doing all its work, you should be able to see your new image:\r\n\r\n![alt image](images/046-image.png)\r\n\r\nand you should also be able to see it in the Docker Desktop app:\r\n\r\n![app image](images/047-docker-image.png)\r\n\r\nlet's spin up our image and give it a test run\r\n\r\n```js\r\ndocker run -p 8080:80 -d  c5m7b4/platformservice\r\n```\r\n\r\n![alt first-run](images/048-first-run.png)\r\n\r\nfirstly, you should get a hash back letting us know our image is running, and you should also be able to see that the container is running in the Docker plugin in vscode. there are a few more things that we can do also\r\n\r\n```js\r\ndocker ps\r\n```\r\n\r\nthis will show us all running containers\r\n\r\n![alt running-containers](images/049-running-containers.png)\r\n\r\nif you want to see all containers that you might have that are not running, you can try this command\r\n\r\n```js\r\ndocker ps -a\r\n```\r\n\r\nif you want to see all images that you've created\r\n\r\n```js\r\ndocker images\r\n```\r\n\r\nyou can also stop the container by using it's id\r\n\r\n```js\r\ndocker stop \r\n```\r\n\r\nsometimes it takes a little time to stop the container\r\n\r\none thing to note is that if we run the container again using the same command as before:\r\n\r\n```js\r\ndocker run -p 8080:80 -d  c5m7b4/platformservice\r\n```\r\n\r\n![alt two-containers](images/050-two-containers.png)\r\n\r\nnotice that now, we have two of these containers.\r\n\r\nso let's run docker ps again and get the container id so we can stop it\r\n\r\n![alt second-container](images/051-second-container.png)\r\n\r\n```js\r\ndocker stop 2224fc5941c3\r\n```\r\n\r\nso, to start a stopped container, use the id that was created for your\r\n\r\n```js\r\ndocker start 2224fc5941c3\r\n```\r\n\r\nyou can also use the plugin\r\n\r\n![alt remove](images/052-remove.png)\r\n\r\nnow we are going to push our image up to docker hub. I'm not sure, but I think you have to do a docker login first, and then after that it should remember your credentials:\r\n\r\n```js\r\ndocker push c5m7b4/platformservice\r\n```\r\n\r\nthis will take a few minutes, but after it's finished, we can log into dockerhub and see our new image which we will need for kubernetes\r\n\r\n![alt docker-hub](images/053-docker-hub.png)\r\n\r\nnext up, we'll test out our container\r\n\r\n## branch 12\r\n\r\nlet's find out what containers that we have that we can start up first\r\n\r\n```js\r\ndocker ps -a\r\n```\r\n\r\n![alt available-containers](images/054-available-containers.png)\r\n\r\nnow let's start our container up so we can test it\r\n\r\n```js\r\ndocker start 6dcbea6544d9\r\n```\r\n\r\nyou will see the container running in the Docker Desktop\r\n\r\n![alt running-container](images/055-running-container.png)\r\n\r\nlets now create a new folder in insomnia\r\n\r\n![alt new-folder](images/056-new-insomnia-folder.png)\r\n\r\nim going to call it Docker env, then create another folder inside of that for our PlatformService. Inside of that, create a new request called Get all Platforms\r\n\r\n![alt get-all-platforms](images/057-get-all-platforms.png)\r\n\r\nmake sure you use port 8080 as that is what we specified when we spun up our container.\r\n\r\nthat should be good enough for now. YOu can create and test out the other two endpoints, but the point of all of this is to get to kubernetes. this was just a means to an end. so lets stop here and finally get on to kubernetes\r\n\r\n## branch 13\r\n\r\nkubernetes is a container orchestrator. it handles automatically restarting container even if they stop. it's often referred as k82 because of the number of letters\r\n\r\nthere are two main types of users\r\n\r\n- developers\r\n- administrators\r\n\r\nwe are to have basicaly containers and under that we will have pods\r\n\r\nhere we are going to look at the kubernetes powerpoint\r\n\r\n## branch 14\r\n\r\nlet's make sure our folder structure looks something like this. You probably won't have images or powerpoints, but you should at least have the PlatformService folder\r\n\r\n![alt structure](images/059-structure.png)\r\n\r\nwe are going to create a new folder called K8S. this folder is just going to hold our kubernetes deploy files, so let's open that up in vscode\r\n\r\nwe are going to do the first part of the powerpoint presention, so create a file called platforms-depl.yaml\r\n\r\nit also might help with this to install this plugin into vscode\r\n\r\n![alt yaml-plugin](images/060-yaml-plugin.png)\r\n\r\n```js\r\napiVersion: apps/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: platforms-depl\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: platformservice\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: platformservice\r\n    spec:\r\n      containers:\r\n        - name: platformservice\r\n          image: c5m7b4/platformservice:latest\r\n```\r\n\r\nthis will basically deploy a container into a pod. spaced here are critical so we might run into some problems here, but we'll keep our fingers crossed as we move forward and test things out.\r\n\r\nnow we are going to try to run our deployment file\r\n\r\nfirst, let's make sure that kubernetes is ready so run this command\r\n\r\n```js\r\nkubectl version --short\r\n```\r\n\r\nand you should see something like this:\r\n\r\n![alt kubernetes-version](images/061-kube-version.png)\r\n\r\nkubectl will be the command that we will use for everything kubernetes related as we will see in the near future.\r\n\r\nto deploy our container, we are going to run this command:\r\n\r\n```js\r\nkubectl apply -f platforms-depl.yaml\r\n```\r\n\r\nhopefully you will see this:\r\n\r\n![alt first-kubernetes-deployment](images/062-first-kubernetes-deployment.png)\r\n\r\nnow let's check to see if this really worked or not\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/063-deployments.png)\r\n\r\nat this point, depending on your computers specs, you may see that the ready column might have 0/1, so it might take a bit of time to spin all this up.\r\n\r\nlet's take a look at our pods\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt pods](images/064-pods.png)\r\n\r\nalso at this time, you might need to run this a few times, while waiting for all this to complete\r\n\r\nif you take a look at our docker plugin, you will see that we are up and running:\r\n\r\n![alt docker-plugin](images/065-docker-plugin.png)\r\n\r\nif we now go to our docker desktop, it should look like this:\r\n\r\n![alt docker-desktop](images/066-docker-desktop.png)\r\n\r\nyou can also click on the platformservice and see what the logs look like:\r\n\r\n![alt logs](images/067-logs.png)\r\n\r\nnotice our seeding data console log that we provided\r\n\r\ncongrats, you just deployed your first kubernetes project\r\n\r\n## branch 15\r\n\r\nyou may notice some weirdness when you commit your changes and then checkout the master branch, but it will sort itself out.\r\n\r\nif it makes any difference, we can destroy and redeploy this like so:\r\n\r\n```js\r\nkubectl delete deployment platforms-depl\r\n```\r\n\r\n![alt destroy](images/068-destoy.png)\r\n\r\nand now docker desktop is empty\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt no-deployments](images/069-no-deployments.png)\r\n\r\nlets now fire things back up\r\n\r\n```js\r\nkubectl apply -f platforms-depl.yaml\r\n```\r\n\r\nnow things should look good in the vscode plugin and in Docker Desktop\r\n\r\nnow we are going to create a node port so we can access this container from our local computer\r\n\r\nlet's create a file in our K8S project called platforms-np-srv.yaml\r\nthe np is for node port\r\n\r\nand it should look like this:\r\n\r\n```js\r\napiVersion: v1\r\nkind: Service\r\nmetadata: \r\n  name: platformnpservice-srv\r\nspec:\r\n  type: NodePort\r\n  selector:\r\n    app: platformservice\r\n  ports:\r\n    - name: platformservice\r\n      protocol: TCP\r\n      port: 8070\r\n      targetPort: 80\r\n```\r\n\r\ni am going to experiment here a little bit and deviate from the tutorial, and I am going to try to use port 8070, because I normally have IIS running on my computer and it takes port 80, which was specified in the tutorial, but I want to test this out on port 8070. We'll see how that goes for me 🙈\r\nI'm pretty sure the port 80 if the port of the service and the port 8070 is the port for my computer, but I guess we'll find out when we test it out. easy fix, if that's not the case though.\r\n\r\n```js\r\nkubectl apply -f platforms-np-srv.yaml\r\n```\r\n\r\nlets make sure it is working\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt services](images/070-services.png)\r\n\r\nlet's get brave and test everything out now. so go back to insomnia, and we are going to create a new folder for our K8S and inside of that, create a new folder called PlatformService. then we are going to create a new test called Get all Platforms\r\n\r\n!!!!!!!!!!!!!!!!!!!!!\r\ndisclaimer, I made a mistake. I though that the port 8070 was the one that i need to use but after some testing, i realized that this is the internal port, so we are going to delete this deployment, fix our mistake and then make it right.\r\n\r\nso in our platforms-np-srv.yaml file, make these changes\r\n\r\n```js\r\napiVersion: v1\r\nkind: Service\r\nmetadata: \r\n  name: platformnpservice-srv\r\nspec:\r\n  type: NodePort\r\n  selector:\r\n    app: platformservice\r\n  ports:\r\n    - name: platformservice\r\n      protocol: TCP\r\n      port: 80\r\n      targetPort: 80\r\n```\r\n\r\nthen let's remove our deployment\r\n\r\n```js\r\nkubectl delete service platformnpservice-srv\r\n```\r\n\r\nnow our service should be gone, so let's recreate it the correct way\r\n\r\n```js\r\nkubectl apply -f platforms-np-srv.yaml\r\n```\r\n\r\nnow let see what our services look like\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt re-deploy](images/071-re-deploy.png)\r\n\r\nso now the ip that we need to test with is going to be the 31637 port, so let's setup insomnia like this:\r\n\r\n![alt get-all-platforms](images/072-get-all-platforms.png)\r\n\r\nall right!!!! this all looks really good. congrats if you made it this far. the next steps is to create our command service and get these boys talking to each other synchronously and asynchronously\r\n\r\n## branch 16\r\n\r\nlet go to a command line at the root of our project and run this command\r\n\r\n```js\r\ndotnet new webapi -n CommandsService\r\n```\r\n\r\n![alt new-project](images/073-new-project.png)\r\n\r\nnow our folder stucture should look like so:\r\n\r\n![alt new-folder-structure](images/074-new-folder-structure.png)\r\n\r\nyou will probably see this box pop up, so hit yes, so we can properyly debug this application\r\n\r\n![alt suggestion](images/075-suggestion.png)\r\n\r\nnow let's open that in vscode and get started. open the CommandsService.csproj file so we can make sure that our dependencies that we are about to install do in fact show up.\r\n\r\n```js\r\ndotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection\r\ndotnet add package Microsoft.EntityFrameworkCore\r\ndotnet add package Microsoft.EntityFrameworkCore.Design\r\n dotnet add package Microsoft.EntityFrameworkCore.InMemory\r\n```\r\n\r\nso now our CommandsService.csproj file should look like this:\r\n\r\n```js\r\n\u003cProject Sdk=\"Microsoft.NET.Sdk.Web\"\u003e\r\n\r\n  \u003cPropertyGroup\u003e\r\n    \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\r\n    \u003cNullable\u003eenable\u003c/Nullable\u003e\r\n    \u003cImplicitUsings\u003eenable\u003c/ImplicitUsings\u003e\r\n  \u003c/PropertyGroup\u003e\r\n\r\n  \u003cItemGroup\u003e\r\n    \u003cPackageReference Include=\"AutoMapper.Extensions.Microsoft.DependencyInjection\" Version=\"12.0.0\" /\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"6.0.10\" /\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"6.0.10\"\u003e\r\n      \u003cIncludeAssets\u003eruntime; build; native; contentfiles; analyzers; buildtransitive\u003c/IncludeAssets\u003e\r\n      \u003cPrivateAssets\u003eall\u003c/PrivateAssets\u003e\r\n    \u003c/PackageReference\u003e\r\n    \u003cPackageReference Include=\"Microsoft.EntityFrameworkCore.InMemory\" Version=\"6.0.10\" /\u003e\r\n    \u003cPackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.2.3\" /\u003e\r\n  \u003c/ItemGroup\u003e\r\n\r\n\u003c/Project\u003e\r\n\r\n```\r\n\r\nnow, let's cleanup our project by removing the references to the weatherforcast\r\n\r\nnow in the properties folder under launchSetting.json, let's change our ports so when we fire up both services, the ports dont conflict with each other:\r\n\r\n```js\r\n{\r\n  \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\r\n  \"iisSettings\": {\r\n    \"windowsAuthentication\": false,\r\n    \"anonymousAuthentication\": true,\r\n    \"iisExpress\": {\r\n      \"applicationUrl\": \"http://localhost:34219\",\r\n      \"sslPort\": 44322\r\n    }\r\n  },\r\n  \"profiles\": {\r\n    \"CommandsService\": {\r\n      \"commandName\": \"Project\",\r\n      \"dotnetRunMessages\": true,\r\n      \"launchBrowser\": true,\r\n      \"launchUrl\": \"swagger\",\r\n      \"applicationUrl\": \"https://localhost:6001;http://localhost:6000\",\r\n      \"environmentVariables\": {\r\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\r\n      }\r\n    },\r\n    \"IIS Express\": {\r\n      \"commandName\": \"IISExpress\",\r\n      \"launchBrowser\": true,\r\n      \"launchUrl\": \"swagger\",\r\n      \"environmentVariables\": {\r\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n```\r\n\r\nnow let's just make sure this will run \r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\njust make sure that everything is working ok.\r\n\r\nnow let's create our first controller, so in the controllers folder create a file called PlatformsController.cs\r\n\r\n```js\r\nusing Microsoft.AspNetCore.Mvc;\r\n\r\nnamespace CommandsService.Controllers\r\n{\r\n  [Route(\"api/c/platforms\")]\r\n  [ApiController]\r\n  public class PlatformsController : ControllerBase\r\n  {\r\n    public PlatformsController()\r\n    {\r\n\r\n    }\r\n\r\n    [HttpPost]\r\n    public ActionResult TestInboundConnection()\r\n    {\r\n      Console.WriteLine(\"--\u003e Inbound Post # command service\");\r\n      return Ok(\"Inbound test ok from platforms controller\");\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow we are going to test this with insomnia:\r\n\r\nlet's do a dotnet run command\r\n\r\n```js\r\ndotnet run\r\n```\r\n\r\nit should be running on port 6000\r\n\r\n![alt port-6000](images/076-port-6000.png)\r\n\r\nlet'g go to insomnia and create folder for testing this out by creating a folder for the Command Service. Let's create a new request called 'Test inbound connection'\r\n\r\n![alt inbound-connection](images/078-inbound-connection.png)\r\n\r\nif we look at our console in vscode, we should see that we got that\r\n\r\n![alt inbound-received](images/079-inbound-received.png)\r\n\r\n## branch 17\r\n\r\nlet's go back to the PlatformService application in vscode and we'll make an inefficient way of comunicating between services.\r\n\r\nso, to test this out, we are going to create a new folder called SyncDataServices\r\n\r\ninside of that folder, we are going to create another folder called Http\r\n\r\ninside of here we are going to create an interface, so create a file called ICommandDataClient.cs\r\n\r\n```js\r\nusing PlatformService.Dtos;\r\n\r\nnamespace PlatformService.SyncDataServices.Http\r\n{\r\n  public interface ICommandDataClient\r\n  {\r\n    Task SendPlatformToCommand(PlatformReadDto plat);\r\n  }\r\n}\r\n```\r\n\r\nnow we will create the concrete class to go with our interface so create a filed called CommandDataClient.cs in that same Http folder.\r\n\r\n```js\r\nusing System.Text;\r\nusing System.Text.Json;\r\nusing PlatformService.Dtos;\r\n\r\nnamespace PlatformService.SyncDataServices.Http\r\n{\r\n  public class CommandDataClient : ICommandDataClient\r\n  {\r\n    private readonly HttpClient _httpClient;\r\n    private readonly IConfiguration _config;\r\n\r\n    public CommandDataClient(HttpClient httpClient, IConfiguration config)\r\n    {\r\n      _httpClient = httpClient;\r\n      _config = config;\r\n    }\r\n\r\n    public async Task SendPlatformToCommand(PlatformReadDto plat)\r\n    {\r\n      var httpContent = new StringContent(\r\n        JsonSerializer.Serialize(plat),\r\n        Encoding.UTF8,\r\n        \"application/json\");\r\n\r\n      var response = await _httpClient.PostAsync(\"http://localhost:6000/api/c/platforms\", httpContent);\r\n\r\n      if (response.IsSuccessStatusCode)\r\n      {\r\n        Console.WriteLine(\"--\u003e Sync POST to CommandSerice was OK!\");\r\n      }\r\n      else\r\n      {\r\n        Console.WriteLine(\"--\u003e Sync POST to CommandService was NOT OK!\");\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow we really dont like having that url hard-coded, so let's store that url in our config file. so go to the appsettings.Development.json file and add this into it:\r\n\r\n```js\r\n{\r\n  \"Logging\": {\r\n    \"LogLevel\": {\r\n      \"Default\": \"Information\",\r\n      \"Microsoft.AspNetCore\": \"Warning\"\r\n    }\r\n  },\r\n  \"CommandService\": \"http://localhost:6000/api/c/platforms\"\r\n}\r\n\r\n```\r\n\r\nthen let's replace the url call with our config variable\r\n\r\n```js\r\nvar response = await _httpClient.PostAsync(_config[\"CommandService\"], httpContent);\r\n```\r\n\r\nnow to use this, we need to register this in our Program.cs file like so, and we can put this just below the repo stuff.\r\n\r\n```js\r\nbuilder.Services.AddHttpClient\u003cICommandDataClient, CommandDataClient\u003e();\r\n```\r\n\r\nlet's commit this, and in the next section, we will actually test all this out.\r\n\r\n## branch 18\r\n\r\nfirst let's inject our new service into the controller\r\n\r\n```js\r\n    public PlatformsController(IPlatformRepo repo, IMapper mapper, ICommandDataClient commandDataClient)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n      _commandDataClient = commandDataClient;\r\n    }\r\n```\r\n\r\ndon't forget to add the create readonly field as well.\r\n\r\nthen come down to the post and make it look like this\r\n\r\n```js\r\n    [HttpPost]\r\n    public async Task\u003cActionResult\u003cPlatformReadDto\u003e\u003e CreatePlatform(PlatformCreateDto platformCreateDto)\r\n    {\r\n      var platformModel = _mapper.Map\u003cPlatform\u003e(platformCreateDto);\r\n      _repo.CreatePlatform(platformModel);\r\n      _repo.SaveChanges();\r\n\r\n      var platformReadDto = _mapper.Map\u003cPlatformReadDto\u003e(platformModel);\r\n\r\n      try\r\n      {\r\n        await _commandDataClient.SendPlatformToCommand(platformReadDto);\r\n      }\r\n      catch (System.Exception ex)\r\n      {\r\n        Console.WriteLine($\"--\u003e Could not send synchronously: {ex.Message}\");\r\n      }\r\n\r\n      return CreatedAtRoute(nameof(GetPlatformById), new { Id = platformReadDto.Id }, platformReadDto);\r\n    }\r\n```\r\n\r\nnow let's check things out, so we do a dotnet build and then a dotnet run\r\n\r\nnow let's open our CommandService application in another instance of vscode and do a dotnet run on it so they are both running. Now if we create a plaform in our PlatformService, it should alert the CommandService of the new platform.\r\n\r\nnow that we have both of those up and running, let's go back to insomnia and create a platform and see what's happening here.\r\n\r\n![alt create-platform](images/080-create-platform.png)\r\n\r\nso, if we look at the console for our platform service, we should see this:\r\n\r\n![alt ok](images/081-ok.png)\r\n\r\nand if we look at the console of our CommandService, we should see this:\r\n\r\n![alt ok](images/082-ok.png)\r\n\r\none thing to note here that i did notice, is that if you are having problems with the two talking, especially using https, this command might be helpful to run on both projects\r\n\r\n```js\r\ndotnet dev-certs https --trust\r\n```\r\n\r\nnow if we kill the comand service and try to use the same endpoint, you will see that it's taking time.\r\n\r\n![alt waiting](images/083-waiting.png)\r\n\r\nit stil works, but here you can see that even though we specified asyn await, we still had to wait, and in our platformservice, we got this message:\r\n\r\n![alt failure](images/084-failure.png)\r\n\r\n## branch 19\r\n\r\nlet's get our command service running in kubernetes and setup our clusterip's for both:\r\n\r\nbefore we can get our command service running in kubernetes, we need to dockerize it and push the image up to docker hub.\r\n\r\nlets make sure that we are in our CommandService project and create a file in the root called Dockerfile:\r\n\r\n```js\r\nFROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env\r\n\r\nWORKDIR /app\r\n\r\nCOPY *.csproj ./\r\n\r\nRUN dotnet restore\r\n\r\nCOPY . ./\r\n\r\nRUN dotnet publish -c Release -o out\r\n\r\nFROM mcr.microsoft.com/dotnet/aspnet:6.0\r\n\r\nWORKDIR /app\r\n\r\nCOPY --from=build-env /app/out .\r\n\r\nENTRYPOINT [\"dotnet\", \"CommandsService.dll\"]\r\n```\r\n\r\nthen let's open a terminal and type this command:\r\n\r\n```js\r\ndocker build -t c5m7b4/commandservice .\r\n```\r\n\r\nthen we'll push it up to docker hub\r\n\r\n```js\r\ndocker push c5m7b4/commandservice\r\n```\r\n\r\n![alt docker-hub](images/085-docker-hub.png)\r\n\r\nwe probably should have tested this before we pushed it, but we'll just do that now\r\n\r\n```js\r\ndocker run -p 8080:80 c5m7b4/commandservice\r\n```\r\n\r\nwe should see this:\r\n\r\n![alt command-service-running](images/086-command-service-running.png)\r\n\r\nlet's go ahead and stop that service\r\n\r\n## branch 20\r\n\r\nnow it's time to go back to our K8s project\r\n\r\nlet's add this to the end of our platforms-depl.yaml file\r\n\r\n```js\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: platforms-clusterip-srv\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: platformservice\r\n  ports:\r\n  - name: platformservice\r\n    protocol: TCP\r\n    port: 80\r\n    targetPort: 80\r\n```\r\n\r\nwe'll leave that be for the moment and we will create a new deployment for our commandsService, so create a file called commands-depl.yaml\r\n\r\n```js\r\napiVersion: apps/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: commands-depl\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: commandservice\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: commandservice\r\n    spec:\r\n      containers:\r\n        - name: commandservice\r\n          image: c5m7b4/commandservice:latest\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: commands-clusterip-srv\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: commandservice\r\n  ports:\r\n  - name: commandservice\r\n    protocol: TCP\r\n    port: 80\r\n    targetPort: 80\r\n```\r\n\r\nit's basically just copying the platforms-depl.yaml file and change the names over. pretty basic setup.\r\n\r\n## branch 21\r\n\r\nwe need to update our platformservice so open that project up\r\n\r\nwe need to let our production build know how to talk to the CommandService\r\n\r\nso in appsettings.json, add this entry:\r\n\r\n```js\r\n\"CommandService\": \"http://commands-clusterip-srv:80/api/c/platforms\"\r\n```\r\n\r\nnow, since we have changes our image we need to rebuild and publish it again\r\n\r\n```js\r\ndocker build -t c5m7b4/platformservice .\r\n```\r\n\r\n```js\r\ndocker push c5m7b4/platformservice\r\n```\r\n\r\nnow we should be good to go\r\n\r\n## branch 22\r\n\r\nlet check to see where we are at, so open up the K8s project\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\nwe only have one deployment so far\r\n\r\n![alt deployments](images/087-deployments.png)\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt pods](images/088-pods.png)\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt services](images/089-services.png)\r\n\r\n```js\r\nkubectl apply -f platforms-depl.yaml\r\n```\r\n\r\n![alt deploy-platforms](images/090-deploy-platforms.png)\r\n\r\nnow lets check our services\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\neverything should match here\r\n\r\nwe still need to force kubernetes to pull down the latest image, because although we created the service, it did not detect a change in our actual application\r\n\r\n```js\r\nkubectl rollout restart deployment platforms-depl\r\n```\r\n\r\n![alt restart](images/091-restart.png)\r\n\r\nnow we should be set with that, so let's deploy our command service\r\n\r\n```js\r\nkubectl apply -f commands-depl.yaml\r\n```\r\n\r\n![alt commands-service](images/092-commands-service.png)\r\n\r\nnow if we check our services\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt services](images/093-services.png)\r\n\r\n\r\nnow let check out deployments\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/094-deployments.png)\r\n\r\nand now let's check our pods\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt pods](images/095-pods.png)\r\n\r\nall is looking pretty good so far.\r\n\r\nnow if we go and look at our docker desktop\r\n\r\n![alt docker-desktop](images/096-docker-desktop.png)\r\n\r\n\r\nwe can probably kill the two dead ones while we are at it\r\n\r\nbut not it's time to actually test these puppies out.\r\n\r\n## branch 23\r\n\r\nlet's test all this out with insomnia\r\n\r\nall this is going to happen in our K8s folder that we created in insomnia, so let's just make sure that the Get all Platforms is still working\r\n\r\n![alt get-all-platforms](images/097-get-all-platforms.png)\r\n\r\nthat stil looks good\r\n\r\n![alt create-platform](images/098-create-platform.png)\r\n\r\nlooks good from the outside, but let's check the logs in docker desktop\r\n\r\n![alt command-service](images/099-command-service.png)\r\n\r\nnotice that last line --\u003e Ibound Post # command service\r\n\r\nthat's what we want to see. now in our platform service:\r\n\r\n![alt platform-service](images/100-platform-service.png)\r\n\r\nonce again, notice the last line. That is what we want to see. If for some reason, we are getting some crazy error about certificates, we can use this line on both projects:\r\n\r\n```js\r\ndotnet dev-certs https --trust\r\n```\r\n\r\nnow, just to double check, run the Get all Platforms again and we should see our new platform:\r\n\r\n![alt get-all-platforms](images/101-get-all-platforms.png)\r\n\r\n!!!!!!!!!!!!!!!!! this is definately a start\r\n\r\nas a side note, you may notice the redirection errors. that's becuase we are not using https. this error is coming from this line of code in both our platform and commands services:\r\n\r\nif you look in the Program.cs file, you will find this line\r\n\r\n```js\r\napp.UseHttpsRedirection();\r\n```\r\n\r\nwe could comment this out, but then we would have to rebuild and re-push to docker hub, so we'll leave in the warnings for now.\r\n\r\nif you've made it this far, congrats, but there is a ton of more cool shit that we need to do\r\n\r\n## branch 24\r\n\r\nthis is where we have come so far\r\n\r\n![alt progress](images/102-progress.png)\r\n\r\nand this is the next step:\r\n\r\n![alt next-step](images/103-next-step.png)\r\n\r\nwe are going to setup the ingress nginx container as our gateway. the node port is good for testing, but not good for production.\r\n\r\nlet's do a google search for ingress nginx\r\n\r\nand we want to find the one from kubernetes\r\n\r\n![alt ingress-nginx](images/104-ingress-nginx.png)\r\n\r\nhere is the [link](https://github.com/kubernetes/ingress-nginx)\r\n\r\nthen lets checkout the getting started section, and then the one about using docker desktop. we will probably have to explore a way for aws as well.\r\n\r\n```js\r\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/aws/deploy.yaml\r\n```\r\n\r\njust for fun, type the url of this puppy into chrome and take a look at their yaml file. it's quite impressive.\r\n\r\nbut i digress...\r\n\r\nlet's but that whole thing in our clipboard, open up the K8S app because that is where we have been working with kubernetes. you don't actually have to do that, but I am trying to stay consistent\r\n\r\nim going to paste that into my terminal and let it do its thing. Its actually pretty fast. now if we look at our docker plugin:\r\n\r\n![alt docker-plugin](images/105-docker-plugin.png)\r\n\r\nand if we look at docker desktop, we are going to see a ton of new stuff\r\n\r\n![alt docker-desktop](images/106-docker-desktop.png)\r\n\r\nnow if we run\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/107-deployments.png)\r\n\r\nnotice that we dont see nginx.same for pods. nginx is running in its own namespace, so let's take a look at what we have there\r\n\r\n```js\r\nkubectl get namespace\r\n```\r\n\r\n![alt namespaces](images/108-namespaces.png)\r\n\r\nso, what we can do it this:\r\n\r\n```js\r\nkubectl get pods --namespace=ingress-nginx\r\n```\r\n\r\n![alt nginx](images/109-nginx.png)\r\n\r\nnotice how 2 of them completed. nginx goes through an initialize phase where it will create pods to create other pods so now if we look at docker desktop again\r\n\r\n![alt docker-desktop](images/110-docker-desktop.png)\r\n\r\nso, we can probably just get rid of the ones that have exited\r\n\r\nnow if we look at the services:\r\n\r\n```js\r\nkubectl get services --namespace=ingress-nginx\r\n```\r\n\r\n![alt services](images/111-serices.png)\r\n\r\nnotice we have a load balancer by default.\r\n\r\n## branch 25\r\n\r\nmake sure that you are in the K8S project and create a new file called ingress-srv.\r\n\r\nthis is going to be our routing file fron nginx to our services\r\n\r\n```js\r\napiVersion: networking.k8s.io/v1\r\nkind: Ingress\r\nmetadata:\r\n  name: ingress-srv\r\n  annotations:\r\n    kubernetes.io/ingress.class: nginx\r\n    nginx.ingress.kubernetes.io/user-regex: 'true'\r\nspec:\r\n  rules:\r\n    - host: acme.com\r\n      http:\r\n        paths:\r\n          - path: /api/platforms\r\n            pathType: Prefix\r\n            backend:\r\n              service:\r\n                name: platforms-clusterip-srv\r\n                port:\r\n                  number: 80\r\n          - path: /api/c/platforms\r\n            pathType: Prefix\r\n            backend: \r\n              service:\r\n                name: commands-clusterip-srv\r\n                port:\r\n                  number: 80\r\n\r\n```\r\n\r\nspacing is very critical here!!!!!\r\n\r\nsince we used acme.com, we need to change our host file to that acme.com is associated with something\r\n\r\nmy location is \r\n\r\n```js\r\nC:\\Windows\\System32\\drivers\\etc\r\n```\r\n\r\nim going to add this line\r\n\r\n```js\r\n127.0.0.1 acme.com\r\n```\r\n\r\nalso, if you are running IIS, then make sure to stop if for this\r\n\r\n\r\nnow back in our K8S project, run this command\r\n\r\n```js\r\nkubectl apply -f ingress-srv.yaml\r\n```\r\n\r\nand we should see this:\r\n\r\n![alt created](images/112-created.png)\r\n\r\nnow it's actually time to test the beast\r\n\r\nback to insomnia\r\n\r\nIm going to rename our PlatformService under the K8s to PlatformServer (Node Port)\r\n\r\nthen create another folder called PlatformService (Nginx)\r\n\r\nlet now create a new test:\r\n\r\nthis time we are going to use acme.com\r\n\r\n![alt acme](images/113-acme-1.png)\r\n\r\nsweet, things are starting to come together. in the next section, we'll setup our sql server and then start to move on to rabbitmq for our message bus\r\n\r\n## branch 26\r\n\r\nnow we are going to setup our first sql server, and this is going to need some storage, so let's look to see what storeageclasses we already have\r\n\r\n```js\r\nkubectl get storageclass\r\n```\r\n\r\n![alt storeageclass](images/114-storeageclass.png)\r\n\r\nthere are three types of classes\r\n\r\n- persistent volume claim\r\n- persistent volume\r\n- storeage class\r\n\r\nback in our K8S project, let's create a new file called local-pvc.yaml for local persistent volume\r\n\r\n```js\r\napiVersion: v1\r\nkind: PersistentVolumeClaim\r\nmetadata:\r\n  name: mssql-claim\r\nspec:\r\n  accessModes:\r\n    - ReadWriteMany\r\n  resources:\r\n    requests:\r\n      storage: 200Mi\r\n\r\n```\r\n\r\nthis is our first basic setup and it will allow for persistent storage requesting 200 MB of storage. \r\n\r\nnow we type this command:\r\n\r\n```js\r\nkubectl apply -f local-pvc.yaml\r\n```\r\n\r\nas a note, if you have already done this, you can remove it and start from scratch by running this command:\r\n\r\n```js\r\nkubectl delete pvc mssql-claim\r\n```\r\n\r\nnow we can see what we have by running this command\r\n\r\n```js\r\nkubeclt get pvc\r\n```\r\n\r\n![alt persistent-storage](images/115-persistent-storage.png)\r\n\r\nnow if we run\r\n\r\n```js\r\nkubectl get pvc\r\n```\r\n\r\nwe shoudl see this:\r\n\r\n![alt pvc](images/116-pvc.png)\r\n\r\nok, for the next part, we are going to need to supply sql with an administrator password, so let's do some footwork first. let's check that we have not already stored a secret\r\n\r\n```js\r\nkubeclt get secrtes\r\n```\r\n\r\nhopefully you are seeing this\r\n\r\n![alt secrets](images/117-secrets.png)\r\n\r\nif for some reason, you are doing this series again for practice, you might see this:\r\n\r\n![alt existing-secrets](images/118-existing-secrets.png)\r\n\r\nyou can remove this by using this command:\r\n\r\n```js\r\nkubectl delete secrets mssql\r\n```\r\n\r\njust trying to cover all the bases here. so now, we should be ready to get started. sorry for the long winded explanation.\r\n\r\nnow let's store our sa password into a secret. Now, obviously, this is a terrible thing altogether, but we'll probably come back aroung to this:\r\n\r\n```js\r\nkubectl create secret generic mssql --from-literal=MSSQSL_SA_PASSWORD=\"pa55w0rd!\" \r\n```\r\n\r\n![alt create-secret](images/119-create-secret.png)\r\n\r\nnow, i think we are ready to create our sql server so let's stop here for now.\r\n\r\n## branch 27\r\n\r\nnow, we are back in our K8S project, we are going to create a new file called mssql-plat-depl.yaml\r\n\r\n```js\r\napiVersion: apps/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: mssql-depl\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: mssql\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mssql\r\n    spec:\r\n      containers:\r\n        - name: mssql\r\n          image: mcr.microsoft.com/mssql/server:2017-latest\r\n          ports:\r\n            - containerPort: 1433\r\n          env:\r\n          - name: MSSQL_PID\r\n            value: \"Express\"\r\n          - name: ACCEPT_EULA\r\n            value: \"Y\"\r\n          - name: MSSQL_SA_PASSWORD\r\n            valueFrom:\r\n              secretKeyRef:\r\n                name: mssql\r\n                key: MSSQL_SA_PASSWORD\r\n          volumeMounts:\r\n          - mountPath: /var/opt/mssql/data\r\n            name: mssqldb\r\n      volumes:\r\n      - name: mssqldb\r\n        persistentVolumeClaim:\r\n          claimName: mssql-claim\r\n\r\n```\r\n\r\nthis is our basic setup, but we also have to add the networking, so we can copy the settings from our commands-depl.yaml file. we will copy the cluster section and make some neccessary changes:\r\n\r\n```js\r\n---          \r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: mssql-clusterip-srv\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: mssql\r\n  ports:\r\n  - name: mssql\r\n    protocol: TCP\r\n    port: 1433\r\n    targetPort: 1433\r\n```\r\n\r\ni really want to play with these ports because I have sql server running on my laptop, and i would like to find a way to have these not interfere with each other, so we may need to play with this a little bit, but let's just get all this up and running and then we can look into making this our bitch.\r\n\r\nnow we want to be able to connect to this from our local laptop, so we'll add a load balancer\r\n\r\n```js\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: mssql-loadbalancer\r\nspec:\r\n  type: LoadBalancer\r\n  selector:\r\n    app: mssql\r\n  ports:\r\n    - protocol: TCP\r\n      port: 1433\r\n      targetPort: 1433   \r\n```\r\n\r\nso our whole file should look like this:\r\n\r\n```js\r\napiVersion: apps/v1\r\ntype: Deployment\r\nmetadata:\r\n  name: mssql-depl\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: mssql\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: mssql\r\n    spec:\r\n      containers:\r\n        - name: mssql\r\n          image: mcr.microsoft.com/mssql/server:2017-latest\r\n          ports:\r\n            - containerPort: 1433\r\n          env:\r\n          - name: MSSQL_PID\r\n            value: \"Express\"\r\n          - name: ACCEPT_EULA\r\n            value: \"Y\"\r\n          - name: MSSQL_SA_PASSWORD\r\n            valueFrom:\r\n              secretKeyRef:\r\n                name: mssql\r\n                key: MSSQL_SA_PASSWORD\r\n          volumeMounts:\r\n          - mountPath: /var/opt/mssql/data\r\n            name: mssqldb\r\n      volumes:\r\n      - name: mssqldb\r\n        persistentVolumeClaim:\r\n          claimName: mssql-claim\r\n---          \r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: mssql-clusterip-srv\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: mssql\r\n  ports:\r\n  - name: mssql\r\n    protocol: TCP\r\n    port: 1433\r\n    targetPort: 1433\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: mssql-loadbalancer\r\nspec:\r\n  type: LoadBalancer\r\n  selector:\r\n    app: mssql\r\n  ports:\r\n  - protocol: TCP\r\n    port: 1433\r\n    targetPort: 1433    \r\n```\r\n\r\nalright, lot's to process here. Let's stop here and when we come back, we'll spint this baby up.\r\n\r\n## branch 28\r\n\r\nnow let's deploy this thing:\r\n\r\n```js\r\nkubectl apply -f mssql-plat-depl.yaml\r\n```\r\n\r\ncross your fingers\r\n\r\n![alt sql-deploy](images/120-sql-deploy.png)\r\n\r\nnow lets run this command\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt services](images/121-services.png)\r\n\r\nand if we do a \r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt pods](images/122-pods.png)\r\n\r\nhere we have an error, so we are going to try to figure out why that is. this is not a bad thing, these yaml files are a bitch.\r\n\r\ni verified the yaml file is good, so pretty sure that this is a secrets problem. let's tear down the deployment with \r\n\r\n```js\r\nkubectl delete deployment mssql-depl\r\n```\r\n\r\nnow let's clear out our secret\r\n\r\n```js\r\nkubectl delete secret mssql\r\n```\r\n\r\nand make sure they are cleared\r\n\r\n```js\r\nkubectl get secrets\r\n```\r\n\r\nredo our secret\r\n\r\n```js\r\nkubectl create secret generic mssql --from-literal=MSSQL_SA_PASSWORD=\"pa55w0rd!\"\r\n```\r\n\r\nredploy our yaml file\r\n\r\n```js\r\nkubectl apply -f mssql-plat-depl.yaml\r\n```\r\n\r\nnow let's check everything out\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/123-deployments.png)\r\n\r\nlooks good, now let's check our pods\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt pods](images/124-pods.png)\r\n\r\nsweet jesus!!!!!\r\n\r\nOK, let's try to login to our sql server. You will need to bring up SQL Server Managment Studio. If you do not have it, you can get it [here](https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16)\r\n\r\ntry to connect up using this:\r\n\r\n![alt sql-login](images/125-sql-login.png)\r\n\r\nthe login seems weird, it actually localhost,1433. I think we need to try and play with using different external ports, so we can actually run multiples of these, but for not, this should be find. also, if you are running sql on your local machine, shut it down because they will conflict because of the port. work in progress I guess, but still learning, so this will have to do for now.\r\n\r\nwe were able to login, but there are no databases yet:\r\n\r\n![alt server](images/126-server.png)\r\n\r\nbut we can test the persistent storage by creating a database just as a test\r\n\r\n![alt test-db](images/127-test-db.png)\r\n\r\nnow, we can close out of SSMS, and go to Docker Desktop and find our mssql instance and kill it:\r\n\r\n![alt mssql](images/128-mssql.png)\r\n\r\nshortly after we kill it, it will respawn, and after it comes back, we will log in again and make sure out test database is still there.\r\n\r\n![alt test-db](images/129-test-db.png)\r\n\r\nyep, still there. let's delete it because we don't need it. in the next branch, we'll update the platform service to actually use this sql server.\r\n\r\n## branch 29\r\n\r\nlet's open back up our PlatformService app and get it ready to connect to our sql server when in production mode. in dev mode, we'll still use the inMemory database though.\r\n\r\nopen up the appsettings.json file and add this line:\r\n\r\n```js\r\n  \"ConnectionStrings\": {\r\n    \"PlatformsConn\": \"Server=mssql-clusterip-srv,1433;Initial Catalog=platformsdb;User Id=sa;Password=pa55w0rd!\"\r\n  }\r\n```\r\n\r\nnow we need a conditional statement in our Program.cs to decide which database to use when in development vs production. If you are watching the youtube video, it's using .net5 and we are using .net6 which is a little different, so i had to figure a different way to do this, so, in our Program.cs file, we'll add this code:\r\n\r\n```js\r\nif (builder.Environment.IsDevelopment())\r\n{\r\n  Console.WriteLine(\"--\u003e running in developement mode\");\r\n  builder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\r\n      opt.UseInMemoryDatabase(\"InMem\"));\r\n}\r\nelse\r\n{\r\n  Console.WriteLine(\"--\u003e running in production mode\");\r\n  builder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\r\n    opt.UseSqlServer(builder.Configuration.GetConnectionString(\"PlatformsConn\")));\r\n}\r\n```\r\n\r\nwe are going to put that before this line:\r\n\r\n```js\r\nbuilder.Services.AddScoped\u003cIPlatformRepo, PlatformRepo\u003e();\r\n```\r\n\r\nlet's test everything out and make sure everybody is happy, so do a dotnet run command and just make sure that you are not getting any errors.\r\nafter this, we are ready to start setting up some migrations\r\n\r\n## branch 30\r\n\r\nbefore we start with migrations, we need to make a small change to our propdb.cs file, so in the DataFolder, open up PropDb.cs, and make this small change:\r\n\r\n```js\r\n      if (isProd)\r\n      {\r\n        Console.WriteLine(\"--\u003e Attempting to apply migrations\");\r\n        try\r\n        {\r\n          context.Database.Migrate();\r\n        }\r\n        catch (Exception ex)\r\n        {\r\n          Console.WriteLine($\"--\u003e could not run migrations: {ex.Message}\");\r\n        }\r\n      }\r\n```\r\n\r\nwe are going to have to comment out the line for migration because we are not totally there yet\r\n\r\nnow, it's time to setup our migrations: open up a command prompt and type\r\n\r\n```js\r\ndotnet ef migrations add initialmigration\r\n```\r\n\r\nand we get this lovely message:\r\n\r\n![alt failed-migrations](images/130-failed-migrations.png)\r\n\r\nthere are a couple of work-arounds for this. Basically, this is just telling us that it has no idea what ef it, and this is something that Microsoft changed in .net 6, so let's run these commands:\r\n\r\n```js\r\ndotnet new tool-manifest\r\ndotnet tool install --local dotnet-ef --version 6.0.10\r\n```\r\n\r\n![alt add-ef](images/131-add-ef.png)\r\n\r\n![alt add tool](images/132-add-tool.png)\r\n\r\nlet's try the migrations one more time, but this time the command will change a little bit\r\n\r\n```js\r\ndotnet dotnet-ef migrations add initialmigration\r\n```\r\n\r\nnow you are going to get a bunch of nasty error, so there is still a little work that needs to be done. the problem here is the the inMemory database does not support migrations, so we need to fake things out in order to get this up and running\r\n\r\n```js\r\n// if (builder.Environment.IsDevelopment())\r\n// {\r\n//   Console.WriteLine(\"--\u003e running in developement mode\");\r\n//   builder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\r\n//       opt.UseInMemoryDatabase(\"InMem\"));\r\n// }\r\n// else\r\n// {\r\n  Console.WriteLine(\"--\u003e running in production mode\");\r\n  builder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e\r\n    opt.UseSqlServer(builder.Configuration.GetConnectionString(\"PlatformsConn\")));\r\n// }\r\n```\r\n\r\nbasically, we are just telling our app that we are only using a real sql database. and this is just to get our migrations started.\r\n\r\nand comment out this line as well\r\n\r\n```js\r\n// PrepDb.PrepPopulation(app, app.Environment.IsProduction());\r\n```\r\n\r\nwe are also going to need to copy our connection string from the appsettings.json and past it in our appsettings.Development.json, and make a small change\r\n\r\n```js\r\n  \"ConnectionStrings\": {\r\n    \"PlatformsConn\": \"Server=localhost,1433;Initial Catalog=platformsdb;User Id=sa;Password=pa55w0rd!\"\r\n  }\r\n```\r\n\r\nthat should be enough to get our migrations working\r\n\r\n```js\r\ndotnet dotnet-ef migrations add initialmigration\r\n```\r\n\r\n![alt migrations](images/133-migrations.png)\r\n\r\nnow there should be a new folder called migrations with 3 files in it:\r\n\r\n![alt migrations-folder](images/134-migrations-folder.png)\r\n\r\nnow let's roll back the things that we commented out to get the migrations to work. also dont forget to go back to PrepDb in our Data folder and remove the comment on this line:\r\n\r\n```js\r\ncontext.Database.Migrate();\r\n```\r\n\r\nyou may also have to import \r\n\r\n```js\r\nusing Microsoft.EntityFrameworkCore;\r\n```\r\n\r\nthat's quite a chunk, so in the next branch, we'll rebuild our image, and push it back up to docker hub and check to see if our migrations are working or not.\r\n\r\n## branch 31\r\n\r\nback in our PlatformService, let's do another build\r\n\r\n```js\r\ndocker build -t c5m7b4/platformservice .\r\n```\r\n\r\ndont forget the period at the end. and then push it up to docker hub\r\n\r\n```js\r\ndocker push c5m7b4/platformservice\r\n```\r\n\r\nnow just double check docker hub and make sure everything is cool.\r\n\r\nnow we need to update our kubernetes instance so it pulls down our latest version\r\n\r\nit doesnt matter what command prompt you do this from, so you don't have to go back to the K8s project to do this.\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/135-deployments.png )\r\n\r\nwe want to restart the platforms-depl\r\n\r\n```js\r\nkubectl rollout restart deployment platforms-depl\r\n```\r\n\r\nand now if you do\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\nyou should see everything running. if for some reason, things are out of whack, like maybe you mispelled the password in the config, you can kill the deployment like this\r\n\r\n```js\r\nkubectl delete deployment platforms-depl\r\n```\r\n\r\nthen fix your errors and redeploy\r\n\r\nnow, if you look at the logs for the platformservice in docke desktop, you should be able to see the migrations in action:\r\n\r\n![alt migrations](images/136-migrations.png)\r\n\r\nnow just to really check, open up ssms and take a look at our database\r\n\r\n![alt db](images/137-db.png)\r\n\r\n![alt seeded-data](images/138-seeded-data.png)\r\n\r\nnow back to insomnia using the K8s version we can go a get all platforms\r\n\r\n![alt get-all-platforms](images/139-get-all-platforms.png)\r\n\r\nnow let's create a platform\r\n\r\n![alt create-platform](images/140-create-platform.png)\r\n\r\nand now recheck our platforms again\r\n\r\n![alt get-all-platforms](images/141-get-all-platforms.png)\r\n\r\nnow we'll check sql\r\n\r\n![alt data](images/142-data.png)\r\n\r\nthere you go. we have come a long way so far, but much more to come\r\n\r\n## branch 32\r\n\r\nnow we are going to fledge out our commandsservice to make it more real\r\n\r\nso, let's open up the commandsService project and create a new folder called Models\r\n\r\nwe will create our first model inside that folder called Platform.cs\r\n\r\n```js\r\nnamespace CommandsService.Models\r\n{\r\n  public class Platforms\r\n  {\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n    public int ExternalId { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nthe next model we will create is our Command.cs file\r\n\r\n```js\r\nusing System.ComponentModel.DataAnnotations;\r\n\r\nnamespace CommandsService.Models\r\n{\r\n  public class Command\r\n  {\r\n    [Key]\r\n    [Required]\r\n    public int Id { get; set; }\r\n    [Required]\r\n    public string HowTo { get; set; }\r\n    [Required]\r\n    public string CommandLine { get; set; }\r\n    [Required]\r\n    public int PlatformId { get; set; }\r\n    public Platform Platform { get; set; }\r\n  }\r\n}\r\n```\r\n\r\none thing I'm going to change about this project is in the CommandsService.csproj file\r\n\r\n```js\r\n\u003c!-- \u003cNullable\u003eenable\u003c/Nullable\u003e --\u003e\r\n```\r\n\r\nnow back over to our Platform class, we will add this:\r\n\r\n```js\r\nusing System.ComponentModel.DataAnnotations;\r\n\r\nnamespace CommandsService.Models\r\n{\r\n  public class Platform\r\n  {\r\n    [Key]\r\n    [Required]\r\n    public int Id { get; set; }\r\n    [Required]\r\n    public string Name { get; set; }\r\n    [Required]\r\n    public int ExternalId { get; set; }\r\n\r\n    public ICollection\u003cCommand\u003e Commands { get; set; } = new List\u003cCommand\u003e();\r\n  }\r\n```\r\n\r\nnow let's just do a dotnet build to make sure everything is kosher\r\n\r\n## branch 33\r\n\r\nnow we are going to create an in memory database for this for now, so create a new folder called Data and create a new file inside of that called AppDbContext.cs\r\n\r\n```js\r\nusing CommandsService.Models;\r\nusing Microsoft.EntityFrameworkCore;\r\n\r\nnamespace CommandsService.Data\r\n{\r\n  public class AppDbContext : DbContext\r\n  {\r\n    public AppDbContext(DbContextOptions\u003cAppDbContext\u003e opt) : base(opt)\r\n    {\r\n\r\n    }\r\n\r\n    public DbSet\u003cPlatform\u003e Platforms { get; set; }\r\n    public DbSet\u003cCommand\u003e Commands { get; set; }\r\n\r\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\r\n    {\r\n      modelBuilder\r\n        .Entity\u003cPlatform\u003e()\r\n        .HasMany(p =\u003e p.Commands)\r\n        .WithOne(p =\u003e p.Platform!)\r\n        .HasForeignKey(p =\u003e p.PlatformId);\r\n\r\n      modelBuilder\r\n        .Entity\u003cCommand\u003e()\r\n        .HasOne(p =\u003e p.Platform)\r\n        .WithMany(p =\u003e p.Commands)\r\n        .HasForeignKey(p =\u003e p.PlatformId);\r\n    }\r\n\r\n  }\r\n}\r\n```\r\n\r\nnow let's just run a dotnet build just to check\r\n\r\nnow let's create a file in the Data folder called ICommandRepo.cs\r\n\r\n```js\r\nusing CommandsService.Models;\r\n\r\nnamespace CommandsService.Data\r\n{\r\n  public interface ICommandRepo\r\n  {\r\n    bool SaveChanges();\r\n\r\n    IEnumerable\u003cPlatform\u003e GetAllPlatforms();\r\n    void CreatePlatform(Platform plat);\r\n    bool PlatformExists(int platformId);\r\n\r\n    IEnumerable\u003cCommand\u003e GetCommandsForPlatform(int platformId);\r\n    Command GetCommand(int platformId, int commandId);\r\n    void CreateCommand(int platformId, Command command);\r\n  }\r\n}\r\n```\r\n\r\nand now create the concrete class to go with the interface, so create a file called CommandRepo.cs in the Data folder:\r\n\r\n```js\r\nusing CommandsService.Models;\r\n\r\nnamespace CommandsService.Data\r\n{\r\n  public class CommandRepo : ICommandRepo\r\n  {\r\n    private readonly AppDbContext _context;\r\n\r\n    public CommandRepo(AppDbContext context)\r\n    {\r\n      _context = context;\r\n    }\r\n    public void CreateCommand(int platformId, Command command)\r\n    {\r\n      if (command == null)\r\n      {\r\n        throw new ArgumentNullException(nameof(command));\r\n      }\r\n\r\n      command.PlatformId = platformId;\r\n      _context.Commands.Add(command);\r\n    }\r\n\r\n    public void CreatePlatform(Platform plat)\r\n    {\r\n      if (plat == null)\r\n      {\r\n        throw new ArgumentNullException(nameof(plat));\r\n      }\r\n\r\n      _context.Platforms.Add(plat);\r\n\r\n    }\r\n\r\n    public IEnumerable\u003cPlatform\u003e GetAllPlatforms()\r\n    {\r\n      return _context.Platforms.ToList();\r\n    }\r\n\r\n    public Command GetCommand(int platformId, int commandId)\r\n    {\r\n      return _context.Commands\r\n        .Where(c =\u003e c.PlatformId == platformId \u0026\u0026 c.Id == commandId).FirstOrDefault();\r\n    }\r\n\r\n    public IEnumerable\u003cCommand\u003e GetCommandsForPlatform(int platformId)\r\n    {\r\n      return _context.Commands\r\n        .Where(c =\u003e c.PlatformId == platformId)\r\n        .OrderBy(c =\u003e c.Platform.Name);\r\n    }\r\n\r\n    public bool PlatformExists(int platformId)\r\n    {\r\n      return _context.Platforms.Any(p =\u003e p.Id == platformId);\r\n    }\r\n\r\n    public bool SaveChanges()\r\n    {\r\n      return (_context.SaveChanges() \u003e= 0);\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow we are just going to run a dotnet build just to check\r\n\r\n## branch 34\r\n\r\nnow we are going to create some Dtos, so create a folder  in the root of the project called Dtos. let's create our first file, PlatformReadDto.cs\r\n\r\n```js\r\nnamespace CommandsService.Dtos\r\n{\r\n  public class PlatformReadDto\r\n  {\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow lets create the CommandReadDto.cs\r\n\r\n```js\r\nnamespace CommandsService.Dtos\r\n{\r\n  public class CommandReadDto\r\n  {\r\n    public int Id { get; set; }\r\n    public string HowTo { get; set; }\r\n    public string CommandLine { get; set; }\r\n    public int PlatformId { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow we are going to create one called CommandCreateDto.cs\r\n\r\n```js\r\nusing System.ComponentModel.DataAnnotations;\r\n\r\nnamespace CommandsService.Dtos\r\n{\r\n  public class CommandCreateDto\r\n  {\r\n    [Required]\r\n    public string HowTo { get; set; }\r\n    [Required]\r\n    public string CommandLine { get; set; }\r\n  }\r\n}\r\n```\r\n\r\n## branch 35\r\n\r\nnow it's time for automapper\r\n\r\nlet's open up the Program.cs file and add this under AddControllers\r\n\r\n```js\r\nbuilder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());\r\n```\r\n\r\nnow we create the folder called Profiles and create a file in there called CommandsProfile.cs\r\n\r\n```js\r\nusing AutoMapper;\r\nusing CommandsService.Dtos;\r\nusing CommandsService.Models;\r\n\r\nnamespace CommandsService.Profiles\r\n{\r\n  public class CommandsProfile : Profile\r\n  {\r\n    public CommandsProfile()\r\n    {\r\n      // source =\u003e target\r\n      CreateMap\u003cPlatform, PlatformReadDto\u003e();\r\n      CreateMap\u003cCommandCreateDto, Command\u003e();\r\n      CreateMap\u003cCommand, CommandReadDto\u003e();\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nthat's it for our automapper\r\n\r\n## branch 36\r\n\r\nstill inside of the CommandsService project, let's open up the PlatformsController.cs. let's make these changes to it\r\n\r\n```js\r\n    private readonly ICommandRepo _repo;\r\n    private readonly IMapper _mapper;\r\n\r\n    public PlatformsController(ICommandRepo repo, IMapper mapper)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n    }\r\n```\r\n\r\nwe are missing a major piece though. we need to setup our dependency injection for our repo. so back in program.cs, we need to add this:\r\n\r\n```js\r\nbuilder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e opt.UseInMemoryDatabase(\"InMem\"));\r\nbuilder.Services.AddScoped\u003cICommandRepo, CommandRepo\u003e();\r\n```\r\n\r\nlet make sure that it builds by running dotnet build\r\n\r\nnow let's go back to the PlatformsController.cs and add another endpoint\r\n\r\n```js\r\n    [HttpGet]\r\n    public ActionResult\u003cIEnumerable\u003cPlatformReadDto\u003e\u003e GetPlatforms()\r\n    {\r\n      Console.WriteLine(\"--\u003e Getting Platforms from CommandsService\");\r\n\r\n      var platformItems = _repo.GetAllPlatforms();\r\n\r\n      return Ok(_mapper.Map\u003cIEnumerable\u003cPlatformReadDto\u003e\u003e(platformItems));\r\n    }\r\n```\r\n\r\nlet's give this a go, so we'll spin it up by running dotnet run\r\n\r\nlet's go over to insomnia and create a test for that endpoint\r\n\r\n![alt get-all-platforms](images/143-get-all-platforms.png)\r\n\r\nlooks good. we wouldn't expect to have any data in the inmemory database that we just spun up.\r\n\r\nlet's create our second controller called CommandsController.cs\r\n\r\n```js\r\nusing AutoMapper;\r\nusing CommandsService.Data;\r\nusing CommandsService.Dtos;\r\nusing Microsoft.AspNetCore.Mvc;\r\n\r\nnamespace CommandsService.Controllers\r\n{\r\n  [Route(\"api/c/platforms/{platformId}/[controller]\")]\r\n  [ApiController]\r\n  public class CommandsController : ControllerBase\r\n  {\r\n    private readonly ICommandRepo _repo;\r\n    private readonly IMapper _mapper;\r\n\r\n    public CommandsController(ICommandRepo repo, IMapper mapper)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n    }\r\n\r\n    [HttpGet]\r\n    public ActionResult\u003cIEnumerable\u003cCommandReadDto\u003e\u003e GetCommandsForPlatform(int platformId)\r\n    {\r\n      Console.WriteLine($\"--\u003e Hit GetCommandsForPlatform: {platformId}\");\r\n\r\n      if (!_repo.PlatformExists(platformId))\r\n      {\r\n        return NotFound();\r\n      }\r\n\r\n      var commands = _repo.GetCommandsForPlatform(platformId);\r\n\r\n      return Ok(_mapper.Map\u003cIEnumerable\u003cCommandReadDto\u003e\u003e(commands));\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nwe can start with this, but if we try to test it, we aren't going to get anything back, but that's ok for now.\r\n\r\nlets do a dotnet run and head back to insomnia\r\n![alt get-commands-for-platform](images/144-get-commands-for-platform.png)\r\n\r\nthis looks good for now, we are not expecting anything back from this just yet.\r\n\r\nlet's add another endpoint\r\n\r\n```js\r\n\r\n    [HttpGet(\"{commandId}\", Name = \"GetCommandForPlatform\")]\r\n    public ActionResult\u003cCommandReadDto\u003e GetCommandForPlatform(int platformId, int commandId)\r\n    {\r\n      Console.WriteLine($\"--\u003e Hit GetCommandForPlatform: {platformId} / {commandId}\");\r\n\r\n      if (!_repo.PlatformExists(platformId))\r\n      {\r\n        return NotFound();\r\n      }\r\n\r\n      var command = _repo.GetCommand(platformId, commandId);\r\n\r\n      if (command == null)\r\n      {\r\n        return NotFound();\r\n      }\r\n\r\n      return Ok(_mapper.Map\u003cCommandReadDto\u003e(command));\r\n    }\r\n```\r\n\r\nwe can spin it up and make sure that the endpoint is working\r\nso, do a dotnet run\r\n\r\nwe still get a not found\r\n\r\n![alt not-found](images/145-not-found.png)\r\n\r\nbut if we check out log, we can see the results there\r\n\r\n![alt arguments](images/146-arguments.png)\r\n\r\nand now for our final route\r\n\r\n```js\r\n    [HttpPost]\r\n    public ActionResult\u003cCommandReadDto\u003e CreateCommandForPlatform(int platformId, CommandCreateDto commandDto)\r\n    {\r\n      Console.WriteLine($\"--\u003e Hit CreateCommandForPlatform: {platformId}\");\r\n\r\n      if (!_repo.PlatformExists(platformId))\r\n      {\r\n        return NotFound();\r\n      }\r\n\r\n      var command = _mapper.Map\u003cCommand\u003e(commandDto);\r\n\r\n      _repo.CreateCommand(platformId, command);\r\n      _repo.SaveChanges();\r\n\r\n      var commandReadDto = _mapper.Map\u003cCommandReadDto\u003e(command);\r\n\r\n      return CreatedAtRoute(nameof(GetCommandForPlatform), new { platformId = platformId, commandId = commandReadDto.Id }, commandReadDto);\r\n    }\r\n```\r\n\r\nspin up a dotnet run and create this in insomnia\r\n\r\n![alt post](images/147-post.png)\r\n\r\nand also make sure that we can see our log because we are just going to get a 404 not found\r\n\r\n![alt hit-create-command](images/148-hit-create-command.png)\r\n\r\n## branch 37\r\n\r\nnow we are going to look into setting up rabbitmq as our messaging but. I need to do more research on this because there are features that I would like to learn. one thing to lookup also is amqp (advanced-messaging-queuing-protocal)\r\n\r\nthere are 4 types of exchange\r\n\r\n- Direct\r\n- Fanout\r\n- Topic\r\n- Header\r\n\r\nso, let's go to our K8S project and create a new file called rabbitmq-depl.yaml\r\n\r\n```js\r\napiVersion: apps/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: rabbitmq-depl\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: rabbitmq\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: rabbitmq\r\n    spec:\r\n      containers:\r\n        - name: rabbitmq\r\n          image: rabbitmq:3-management\r\n          ports:\r\n            - containerPort: 15672\r\n              name: rbmq-mgmt-port\r\n            - containerPort: 5672\r\n              name: rbmq-msg-port\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: rabbitmq-clusterip-srv\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: rabbitmq\r\n  ports:\r\n  - name: rbmq-mgmt-port\r\n    protocol: TCP\r\n    port: 15672\r\n    targetPort: 15672\r\n  - name: rbmq-msg-port\r\n    protocol: TCP\r\n    port: 5672\r\n    targetPort: 5672\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: rabbitmq-loadbalancer\r\nspec:\r\n  type: LoadBalancer\r\n  selector:\r\n    app: rabbitmq\r\n  ports:\r\n  - name: rbmq-mgmt-port\r\n    protocol: TCP\r\n    port: 15672\r\n    targetPort: 15672\r\n  - name: rbmq-msg-port\r\n    protocol: TCP\r\n    port: 5672\r\n    targetPort: 5672\r\n```\r\n\r\nnow lets run the deployment\r\n\r\n```js\r\nkubectl apply -f rabbitmq-depl.yaml\r\n```\r\n\r\n![alt rabbit](images/149-rabbit-mq.png)\r\n\r\nnow let's get our deployments\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/150-deployments.png)\r\n\r\nit might take some time to start. notice in my screenshot, it is not started yet, so let's check out pods\r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\n![alt deployments](images/151-deployments.png)\r\n\r\nlooking good now.\r\n\r\n![alt services](images/152-services.png)\r\n\r\nnow let's open up a browser and go go localhost:15672\r\n\r\n![alt rabbit](images/153-rabbit.png)\r\n\r\nyou can login with guest/guest\r\n\r\n![alt dashboard](images/154-dashboard.png)\r\n\r\n## branch 38\r\n\r\nnow let's go into our platform service\r\n\r\nwe need to add a dependency for RabbitMQ\r\n\r\n```js\r\ndotnet add package RabbitMQ.Client\r\n```\r\n\r\nnow in our appsettings.Development.json we need to add our config\r\n\r\n```js\r\n  \"RabbitMQHost\": \"localhost\",\r\n  \"RabbitMQPort\": \"5672\"\r\n```\r\n\r\nand in our appsettings.json, we need to add that config\r\n\r\n```js\r\n  \"RabbitMQHost\": \"rabbitmq-clusterip-srv\",\r\n  \"RabbitMQPort\": \"5672\"\r\n```\r\n\r\nnow let's create a dto, so in the Dtos folder create a file named PlatformPublishedDto.cs\r\n\r\n```js\r\nnamespace PlatformService.Dtos\r\n{\r\n  public class PlatformPublishedDto\r\n  {\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n    public string Event { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow we need to create another mapping, so let's go into the Profiles folder and update that file:\r\n\r\n```js\r\nCreateMap\u003cPlatformReadDto, PlatformPublishedDto\u003e();\r\n```\r\n\r\nnow let's create a folder in the root of our project and name it AsyncDataServices and create a file in there called IMessageBusClient\r\n\r\n```js\r\nusing PlatformService.Dtos;\r\n\r\nnamespace PlatformService.AsyncDataService\r\n{\r\n  public interface IMessageBusClient\r\n  {\r\n    void PublishNewPlatform(PlatformPublishedDto platformPublishedDto);\r\n  }\r\n}\r\n```\r\n\r\nnow we are going to implement this interface so create a file calledMessageBusClient.cs. this is going to be kind of a lengthy file\r\n\r\n```js\r\nusing System.Text;\r\nusing System.Text.Json;\r\nusing PlatformService.Dtos;\r\nusing RabbitMQ.Client;\r\n\r\nnamespace PlatformService.AsyncDataService\r\n{\r\n  public class MessageBusClient : IMessageBusClient\r\n  {\r\n    private readonly IConfiguration _config;\r\n    private readonly IConnection _connection;\r\n    private readonly IModel _channel;\r\n\r\n    public MessageBusClient(IConfiguration config)\r\n    {\r\n      _config = config;\r\n      var factory = new ConnectionFactory() { HostName = _config[\"RabbitMQHost\"], Port = int.Parse(_config[\"RabbitMQPort\"]) };\r\n      try\r\n      {\r\n        _connection = factory.CreateConnection();\r\n        _channel = _connection.CreateModel();\r\n\r\n        _channel.ExchangeDeclare(exchange: \"trigger\", type: ExchangeType.Fanout);\r\n\r\n        _connection.ConnectionShutdown += RabbitMQ_ConnectionShutdown;\r\n\r\n        Console.WriteLine(\"--\u003e Connected to Message Bus\");\r\n      }\r\n      catch (System.Exception ex)\r\n      {\r\n        Console.WriteLine($\"--\u003e Could not connect to the Message Bus: {ex.Message}\");\r\n      }\r\n    }\r\n\r\n    private void RabbitMQ_ConnectionShutdown(object sender, ShutdownEventArgs e)\r\n    {\r\n      Console.WriteLine(\"--\u003e Message Bus has disconnected\");\r\n    }\r\n\r\n    private void SendMessage(string message)\r\n    {\r\n      var body = Encoding.UTF8.GetBytes(message);\r\n\r\n      _channel.BasicPublish(exchange: \"trigger\", routingKey: \"\", basicProperties: null, body: body);\r\n\r\n      Console.WriteLine($\"--\u003e We have sent {message}\");\r\n    }\r\n\r\n\r\n    public void PublishNewPlatform(PlatformPublishedDto platformPublishedDto)\r\n    {\r\n      var message = JsonSerializer.Serialize(platformPublishedDto);\r\n\r\n      if (_connection.IsOpen)\r\n      {\r\n        Console.WriteLine(\"--\u003e Rabbit MQ Connection open, sending message...\");\r\n        SendMessage(message);\r\n      }\r\n      else\r\n      {\r\n        Console.WriteLine(\"--. Rabbit MQ connection is closed, not sendind\");\r\n      }\r\n    }\r\n\r\n    public void Dispose()\r\n    {\r\n      Console.WriteLine(\"Message Bus Disposed\");\r\n      if (_channel.IsOpen)\r\n      {\r\n        _channel.Close();\r\n        _connection.Close();\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n```\r\n\r\nlets do a dotnet build just to make sure we haven't broken anything\r\n\r\nnow we just need to register our dependency injection\r\n\r\n```js\r\nbuilder.Services.AddSingleton\u003cIMessageBusClient, MessageBusClient\u003e();\r\n```\r\n\r\nafter you commit, you may have some nasty errors, so use ctrl-shift-p and type reload to fix things up.\r\n\r\nnow let's go into the PlatformsController and setup our Dependency Injection\r\n\r\n```js\r\n    private readonly IMapper _mapper;\r\n    private readonly ICommandDataClient _commandDataClient;\r\n    private readonly IMessageBusClient _messageBusClient;\r\n    private readonly IPlatformRepo _repo;\r\n\r\n    public PlatformsController(IPlatformRepo repo, IMapper mapper, ICommandDataClient commandDataClient, IMessageBusClient messageBusClient)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n      _commandDataClient = commandDataClient;\r\n      _messageBusClient = messageBusClient;\r\n    }\r\n```\r\n\r\nand then in our post, we'll add this code\r\n\r\n```js\r\n      try\r\n      {\r\n        var platforPublishedDto = _mapper.Map\u003cPlatformPublishedDto\u003e(platformReadDto);\r\n        platforPublishedDto.Event = \"Platform_Published\";\r\n        _messageBusClient.PublishNewPlatform(platforPublishedDto);\r\n      }\r\n      catch (System.Exception ex)\r\n      {\r\n        Console.WriteLine($\"--\u003e Could not send asynchronously: {ex.Message}\");\r\n      }\r\n```\r\n\r\nnow let's fire up our PlatformService with a dotnet run\r\n\r\nnow let's open up the CommandService and do a dotnet run on it\r\n\r\nthen we'll go to  insomnia and on our local platform service, make sure we can still get all platforms and then let's create a platform\r\n\r\nthen in our command service, we should still see this\r\n\r\n![alt command-service](images/155-command-service.png)\r\n\r\nand i our PlatformService we should see our new logs\r\n\r\n![alt platform-service](images/156-platform-service.png)\r\n\r\nnow if we blast the Create command, we can see in rabbitmq, our activity\r\n\r\n![alt rabbit](images/157-rabbit.png)\r\n\r\n## branch 40\r\n\r\nnow let's open up teh ComandsService and work on that for a little while.\r\n\r\nfirst we need to add the RabbitMQ.Client dependency\r\n\r\n```js\r\ndotnet add package RabbitMQ.Client\r\n```\r\n\r\nmake sure the check the CommandsService.csproj to make sure it got loaded.\r\n\r\nnow in our appsettings.Development.json, let's add our RabbitMQ config\r\n\r\n```js\r\n  \"RabbitMQHost\": \"localhost\",\r\n  \"RabbitMQPort\": \"5672\"\r\n```\r\n\r\nthen i nour appsettings.json, we need to add the config there as well\r\n\r\n```js\r\n  \"RabbitMQHost\": \"rabbitmq-clusterip-srv\",\r\n  \"RabbitMQPort\": \"5672\"\r\n```\r\n\r\nnow we are going to create some Dtos, so create a file in the Dto folder called PlatformPublishedDto.cs\r\n\r\n```js\r\nnamespace CommandsService.Dtos\r\n{\r\n  public class PlatformPublishedDto\r\n  {\r\n    public int Id { get; set; }\r\n    public string Name { get; set; }\r\n    public string Event { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow create another dto called GenericEventDto.cs\r\n\r\n```js\r\nnamespace CommandsService.Dtos\r\n{\r\n  public class GenericEventDto\r\n  {\r\n    public string Event { get; set; }\r\n  }\r\n}\r\n```\r\n\r\nnow we need to change our profile code to AutoMapper\r\n\r\n```js\r\n      CreateMap\u003cPlatformPublishedDto, Platform\u003e()\r\n        .ForMember(dest =\u003e dest.ExternalId, opt =\u003e opt.MapFrom(src =\u003e src.Id));\r\n```\r\n\r\nnow i our ICommandRepo.cs file, add this little snippet\r\n\r\n```js\r\nbool ExternalPlatformExists(int externalPlatformId);\r\n```\r\n\r\nand then we need to implement this in the CommandRepo.cs file\r\n\r\n```js\r\n    public bool ExternalPlatformExists(int externalPlatformId)\r\n    {\r\n      return _context.Platforms.Any(p =\u003e p.ExternalId == externalPlatformId);\r\n    } \r\n```\r\n\r\n## branch 41\r\n\r\nlet's create a root folder in our CommandsService project called EventProcessing.\r\n\r\ninside of there, create a file called IEventProcessor.cs\r\n\r\n```js\r\nnamespace CommandsService.EventProcessing\r\n{\r\n  public interface IEventProcessor\r\n  {\r\n    void ProcessEvent(string message);\r\n  }\r\n}\r\n```\r\n\r\nthen create another file called EventProcessor.cs\r\n\r\n```js\r\nusing System.Text.Json;\r\nusing AutoMapper;\r\nusing CommandsService.Data;\r\nusing CommandsService.Dtos;\r\nusing CommandsService.Models;\r\n\r\nnamespace CommandsService.EventProcessing\r\n{\r\n  public class EventProcessor : IEventProcessor\r\n  {\r\n    private readonly IServiceScopeFactory _scopeFactory;\r\n    private readonly IMapper _mapper;\r\n\r\n    public EventProcessor(IServiceScopeFactory scopeFactory, IMapper mapper)\r\n    {\r\n      _scopeFactory = scopeFactory;\r\n      _mapper = mapper;\r\n    }\r\n    public void ProcessEvent(string message)\r\n    {\r\n      var eventType = DetermineEvent(message);\r\n\r\n\r\n      switch (eventType)\r\n      {\r\n        case EventType.PlatformPublished:\r\n          // To Do\r\n          break;\r\n        default:\r\n          break;\r\n      }\r\n    }\r\n\r\n    private EventType DetermineEvent(string notificationMessage)\r\n    {\r\n      Console.WriteLine(\"--\u003e Determining Event Type\");\r\n\r\n      var eventType = JsonSerializer.Deserialize\u003cGenericEventDto\u003e(notificationMessage);\r\n\r\n      switch (eventType.Event)\r\n      {\r\n        case \"Platform_Published\":\r\n          Console.WriteLine(\"--\u003e Platform Published Event detected\");\r\n          return EventType.PlatformPublished;\r\n        default:\r\n          Console.WriteLine(\"--\u003e Could not determine event type\");\r\n          return EventType.Undetermined;\r\n      }\r\n    }\r\n\r\n    private void AddPlatform(string platformPublishedMessage)\r\n    {\r\n      using (var scope = _scopeFactory.CreateScope())\r\n      {\r\n        var repo = scope.ServiceProvider.GetRequiredService\u003cICommandRepo\u003e();\r\n\r\n        var platformPublishedDto = JsonSerializer.Deserialize\u003cPlatformPublishedDto\u003e(platformPublishedMessage);\r\n\r\n        try\r\n        {\r\n          var plat = _mapper.Map\u003cPlatform\u003e(platformPublishedDto);\r\n          if (!repo.ExternalPlatformExists(plat.ExternalId))\r\n          {\r\n            repo.CreatePlatform(plat);\r\n            repo.SaveChanges();\r\n          }\r\n          else\r\n          {\r\n            Console.WriteLine(\"--\u003e Platform already exitss\");\r\n          }\r\n\r\n        }\r\n        catch (System.Exception ex)\r\n        {\r\n          Console.WriteLine($\"--\u003e Could not add platform to teh db {ex.Message}\");\r\n        }\r\n\r\n      }\r\n    }\r\n  }\r\n\r\n  enum EventType\r\n  {\r\n    PlatformPublished,\r\n    Undetermined\r\n  }\r\n}\r\n```\r\n\r\ni know, this one is big\r\n\r\nnow in our Program.cs file, we need to register our dependency injection\r\n\r\n```js\r\nbuilder.Services.AddSingleton\u003cIEventProcessor, EventProcessor\u003e();\r\n```\r\n\r\nlet's quickly do a build with dotnet build\r\n\r\nand let's test a dotnet run, just to check\r\n\r\n## branch 42\r\n\r\nnow let's create another folder in the root of the CommandsService project called AsyncDataServices\r\n\r\nnow in that folder, create a file called MessageBusSubscriber.cs\r\n\r\n```js\r\nusing System.Text;\r\nusing CommandsService.EventProcessing;\r\nusing RabbitMQ.Client;\r\nusing RabbitMQ.Client.Events;\r\n\r\nnamespace CommandsService.AsyncDataServices\r\n{\r\n  public class MessageBusSubscriber : BackgroundService\r\n  {\r\n    private readonly IConfiguration _config;\r\n    private readonly IEventProcessor _eventProcessor;\r\n    private IConnection _connection;\r\n    private IModel _channel;\r\n    private string _queueName;\r\n\r\n    public MessageBusSubscriber(IConfiguration config, IEventProcessor eventProcessor)\r\n    {\r\n      _config = config;\r\n      _eventProcessor = eventProcessor;\r\n      InitializeRabbitMQ();\r\n    }\r\n\r\n    private void InitializeRabbitMQ()\r\n    {\r\n      var factory = new ConnectionFactory() { HostName = _config[\"RabbitMQHost\"], Port = int.Parse(_config[\"RabbitMQPort\"]) };\r\n\r\n      _connection = factory.CreateConnection();\r\n      _channel = _connection.CreateModel();\r\n      _channel.ExchangeDeclare(exchange: \"trigger\", type: ExchangeType.Fanout);\r\n      _queueName = _channel.QueueDeclare().QueueName;\r\n      _channel.QueueBind(queue: _queueName, exchange: \"trigger\", routingKey: \"\");\r\n\r\n      Console.WriteLine(\"--\u003e Listening on the Message Bus\");\r\n\r\n      _connection.ConnectionShutdown += RabbitMQ_ConnectionShutdown;\r\n    }\r\n\r\n    protected override Task ExecuteAsync(CancellationToken stoppingToken)\r\n    {\r\n      // do this one last\r\n      stoppingToken.ThrowIfCancellationRequested();\r\n\r\n      var consumer = new EventingBasicConsumer(_channel);\r\n\r\n      consumer.Received += (ModuleHandle, ea) =\u003e\r\n      {\r\n        Console.WriteLine(\"--\u003e Event received\");\r\n\r\n        var body = ea.Body;\r\n        var notificationMessage = Encoding.UTF8.GetString(body.ToArray());\r\n\r\n        _eventProcessor.ProcessEvent(notificationMessage);\r\n      };\r\n\r\n      _channel.BasicConsume(queue: _queueName, autoAck: true, consumer: consumer);\r\n\r\n      return Task.CompletedTask;\r\n    }\r\n\r\n    private void RabbitMQ_ConnectionShutdown(object sender, ShutdownEventArgs e)\r\n    {\r\n      Console.WriteLine(\"--\u003e Connection shutdown\");\r\n    }\r\n\r\n    public override void Dispose()\r\n    {\r\n      if (_channel.IsOpen)\r\n      {\r\n        _channel.Close();\r\n        _connection.Close();\r\n      }\r\n\r\n\r\n      base.Dispose();\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nnow we just need to register this, so open up the Program.cs file and add this after the controllers\r\n\r\n```js\r\nbuilder.Services.AddHostedService\u003cMessageBusSubscriber\u003e();\r\n```\r\n\r\nnow, we are ready to test\r\n\r\n## branch 43\r\n\r\nlet's open up the platform service and do a dotnet build and dotnet run\r\n\r\nthen go back to the command service and do a dotnet build and a dotnet run\r\n\r\nthis is the important part\r\n\r\n![alt listening](images/158-listening.png)\r\n\r\nnow over to insomnia and we are using the local versions for testing. make sure first that the Get all Platforms is still working, and then we are going to Create a platform and see what happens.\r\n\r\nin our command service, we should see this:\r\n\r\n![alt command-received](images/159-event-received.png)\r\n\r\nand in our platform service, we should see this\r\n\r\n![alt sent](images/160-sent.png)\r\n\r\nwe are missing something though, in the command service, open uup the EventProcessor class and let's first add a console message on lin 66 after we save the \r\n\r\nthen in our ToDo section that we left around line 25,\r\nwe need to add this:\r\n\r\n```js\r\n      switch (eventType)\r\n      {\r\n        case EventType.PlatformPublished:\r\n          AddPlatform(message);\r\n          break;\r\n        default:\r\n          break;\r\n      }\r\n```\r\n\r\nnow we can restart the command service and test Creating a platform again with insomnia\r\n\r\nnow in our command service, we'll get some better logging:\r\n\r\n![alt platform-added](images/161-platform-added.png)\r\n\r\nnow if we go to the CommandService in insomnia, we should be able to run the Get all platforms there and we should see the platform we added\r\n\r\n![alt new-platform](images/162-new-platform.png)\r\n\r\nnow let's try the Create Command for Platform. note the id that was returned\r\n\r\n![alt new-command](images/163-new-command.png)\r\n\r\nactually, i messed that up. I need to the use id that that is in the previous screenshot\r\n\r\n![alt new-command](images/164-new-command.png)\r\n\r\nand now we should be able to run the Get all Commands for Platform\r\n\r\n![alt all-commands](images/165-all-commands.png)\r\n\r\ncongrats, this was all a big step. next up, let's rebuild everthing and re-push our images to docker hub and refresh kubernetes and do some more testing\r\n\r\n## branch 44\r\n\r\nlet's go back over to our platform service, shut everthing down and do a fresh docker build\r\n\r\n```js\r\ndocker build -t c5m7b4/platformservice .\r\n```\r\n\r\nand now we will push it back up to docker hub\r\n\r\n```js\r\ndocker push c5m7b4/platformservice\r\n```\r\n\r\nnow we need to go over to our CommandService and do a build there as well\r\n\r\n```js\r\ndocker build -t c5m7b4/commandservice .\r\n```\r\n\r\nand then push that up to docker hub\r\n\r\n```js\r\ndocker push c5m7b4/commandservice\r\n```\r\n\r\ncheck our work on docker hub of course\r\n\r\nnext up, let's double check our deployments\r\n\r\n```js\r\nkubectl get deployments\r\n```\r\n\r\n![alt deployments](images/166-deployments.png)\r\n\r\nnow lets restart the platform-depl\r\n\r\n```js\r\nkubectl rollout restart deployment platforms-depl\r\n```\r\n\r\nmake sure the pods are running \r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\nnow we'll go over to insomnia and using our K8s Platform service let's create a platform and see what we get\r\n\r\n![alt create-platform](images/167-create-platform.png)\r\n\r\nnow if we do a get all platforms\r\n\r\n![alt platforms](images/168-platforms.png)\r\n\r\nall is looking good. let check the logs\r\n\r\n![alt logs](images/169-logs.png)\r\n\r\nnow let's restart the CommandService\r\n\r\n```js\r\nkubectl rollout restart deployment commands-depl\r\n```\r\n\r\nmake sure the pods are running \r\n\r\n```js\r\nkubectl get pods\r\n```\r\n\r\nnow we'll create another platform\r\n\r\n![alt create-platform](images/170-create-platform.png)\r\n\r\nand take a look at the logs\r\n\r\n![alt platform-added](images/171-platform-added.png)\r\n\r\nnow lets create a CommandService folder in our K8s insomnia folder and create the Get all Platforms request\r\n\r\n![alt get-all-platforms](images/172-get-all-platforms.png)\r\n\r\n![alt create-command](images/173-create-command.png)\r\n\r\n![alt get-all-commands](images/174-get-all-commands.png)\r\n\r\nin the next section we will look at grpc and really syncing our commands\r\n\r\n## branch 45\r\n\r\nin order to get grpc working, we are going to have to modify our platforms-depl.yaml file, so let's open up the K8s project and open that platforms-depl.yaml file\r\n\r\nwe just need to add one more port\r\n\r\n```js\r\n  - name: platformgrpc\r\n    protocol: TCP\r\n    port: 666\r\n    targetPort: 666\r\n```\r\n\r\nredeploy our service\r\n\r\n```js\r\nkubectl apply -f platforms-depl.yaml\r\n```\r\n\r\n```js\r\nkubectl get services\r\n```\r\n\r\n![alt services](images/175-services.png)\r\n\r\nnow you will notice the 666 port is present\r\n\r\nnow let's go back to the platform service because it is going to be the grpc server\r\n\r\nnow in our appsettings.json, we need to add this little bit of config\r\n***** on a side note, i'm pretty sure that this has to go into appsetting.Production.json or we will get a clash of port 80 in developement mode.\r\n\r\n```js\r\n  \"Kestrel\": {\r\n    \"Endpoints\": {\r\n      \"Grpc\":{\r\n        \"Protocols\": \"Http2\",\r\n        \"Url\":\"http://platforms-clusterip-srv:666\"\r\n      },\r\n      \"webApi\":{\r\n        \"Protocols\": \"Http1\",\r\n        \"Url\":\"http://platforms-clusterip-srv:80\"\r\n      }\r\n    }\r\n  }\r\n```\r\n\r\nwe do need to add one package to our Platform service\r\n\r\n```js\r\ndotnet add package Grpc.AspNetCore\r\n```\r\n\r\nnow we are going to jump back over to our command service and add the needed packages there\r\n\r\n```js\r\ndotnet add package Grpc.Tools\r\ndotnet add package Grpc.Net.Client\r\ndotnet add package Google.Protobuf\r\n```\r\n\r\nnow let's go back into our PlatformService and create the proto file\r\nlet's create a folder in the root called Protos and we are going to create a file in there called platforms.proto\r\n\r\n```js\r\nsyntax = \"proto3\";\r\n\r\noption csharp_namespace = \"PlatformService\";\r\n\r\nservice GrpcPlatform {\r\n  rpc GetAllPlatforms (GetAllRequests) returns (PlatformResponse);\r\n}\r\n\r\nmessage GetAllRequests {}\r\n\r\nmessage GrpcPlatformModel{\r\n  int32 platformId = 1;\r\n  string name = 2;\r\n  string publisher = 3;\r\n}\r\n\r\nmessage PlatformResponse{\r\n  repeated GrpcPlatformModel platform = 1;\r\n}\r\n```\r\n\r\nthis one is a bit strange\r\n\r\nnow we need to go to the csproj file and add this\r\n\r\n```js\r\n  \u003cItemGroup\u003e\r\n    \u003cProtobuf Include=\"Protos\\platforms.proto\" GrpcServices=\"Server\" /\u003e\r\n  \u003c/ItemGroup\u003e\r\n```\r\n\r\nnow let's do a dotnet build\r\n\r\nnow if we need in obj\\Debug\\Protos we will see the autogenerated code\r\n\r\nnow let's create a folder inside our SyncDataServices folder called Grpc and create a file in there called GrpcPlatformService.cs\r\n\r\n```js\r\nnamespace PlatformService.SyncDataServices.Grpc\r\n{\r\n  public class GrpcPlatformService : GrpcPlatform.GrpcPlatformBase\r\n  {\r\n    \r\n  }\r\n}\r\n```\r\n\r\nbut before we can finish this file, we need to go back into the Profiles folder and add another map\r\n\r\n```js\r\n      CreateMap\u003cPlatform, GrpcPlatformModel\u003e()\r\n        .ForMember(dest =\u003e dest.PlatformId, opt =\u003e opt.MapFrom(src =\u003e src.Id))\r\n        .ForMember(dest =\u003e dest.Name, opt =\u003e opt.MapFrom(src =\u003e src.Name))\r\n        .ForMember(dest =\u003e dest.Publisher, opt =\u003e opt.MapFrom(src =\u003e src.Publi\r\n```\r\n\r\nnow let's go back into the GrpcPlatformService.cs file\r\n\r\n```js\r\nusing AutoMapper;\r\nusing Grpc.Core;\r\nusing PlatformService.Data;\r\n\r\nnamespace PlatformService.SyncDataServices.Grpc\r\n{\r\n  public class GrpcPlatformService : GrpcPlatform.GrpcPlatformBase\r\n  {\r\n    private readonly IPlatformRepo _repo;\r\n    private readonly IMapper _mapper;\r\n\r\n    public GrpcPlatformService(IPlatformRepo repo, IMapper mapper)\r\n    {\r\n      _repo = repo;\r\n      _mapper = mapper;\r\n    }\r\n\r\n    public override Task\u003cPlatformResponse\u003e GetAllPlatforms(GetAllRequests request, ServerCallContext ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc5m7b4%2Fkubernetes-net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc5m7b4%2Fkubernetes-net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc5m7b4%2Fkubernetes-net/lists"}