{"id":18648472,"url":"https://github.com/tfsjohan/github-copilot-demo-dotnet","last_synced_at":"2026-05-02T03:03:17.225Z","repository":{"id":222709979,"uuid":"758079556","full_name":"tfsjohan/github-copilot-demo-dotnet","owner":"tfsjohan","description":"En .net project to demo GitHub Copilot and GitHub Advanced Security.","archived":false,"fork":false,"pushed_at":"2025-01-07T12:59:50.000Z","size":62,"stargazers_count":1,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-07T13:44:07.154Z","etag":null,"topics":["copilot","copilot-chat","dotnet","ghas"],"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/tfsjohan.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-15T15:30:22.000Z","updated_at":"2025-01-07T12:59:54.000Z","dependencies_parsed_at":"2024-04-17T07:27:27.312Z","dependency_job_id":"0af78cfc-98f2-4b18-a424-15759b0cc246","html_url":"https://github.com/tfsjohan/github-copilot-demo-dotnet","commit_stats":null,"previous_names":["tfsjohan/github-copilot-demo-dotnet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfsjohan%2Fgithub-copilot-demo-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfsjohan%2Fgithub-copilot-demo-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfsjohan%2Fgithub-copilot-demo-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfsjohan%2Fgithub-copilot-demo-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tfsjohan","download_url":"https://codeload.github.com/tfsjohan/github-copilot-demo-dotnet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239450611,"owners_count":19640754,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["copilot","copilot-chat","dotnet","ghas"],"created_at":"2024-11-07T06:31:14.673Z","updated_at":"2025-11-05T08:30:22.769Z","avatar_url":"https://github.com/tfsjohan.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":" # GitHub Copilot\n\n## General tips\n\nSometimes Copilot will suggest code that is not the best practice. It's important to always review the code and make sure it's following the best practices. You can often ask Copilot Chat if the code actually is following best practices.\n\nCopilot AutoComplete is great at completing code or having a comment as a prompt, but sometimes it can be a bit too keen on suggesting more comments instead of code.In these cases, it helps to start writing some code to get it started.\n\nIt also helps to already have a `namespace` and some `using` statements.\n\nA top level comment can add useful context for the purpose of the file. Keep it short, specific and to the point.\n\nCopilot does not yet know about the latest C# features, so it might suggest older ways of doing things. For example how to handle nulls and primary constructors.\n\nCopilot might not get it right the first time, so don't forget to iterate on the prompts or code to improve it over time.\n\nAnd don't forget, Copilot is a tool to help you, not replace you.\n\n## The Chuck Norris Joke API\n\nLet's see if we can make a Chuck Norris API with GitHub Copilot. The API is available at `https://api.chucknorris.io/jokes/random`. Your mission, if you choose to accept it, is to create an API that fetches a random joke from the Chuck Norris API using Copilot and making sure that the code follows the best practices.\n\nHere's what we'll try to do:\n\n- Make a `Joke` class\n- Make a `JokeService` that can be used in dependency injection\n- Make a `JokeController` that can serve up some fresh jokes\n- Make some tests\n\n\u003e [!TIP]\n\u003e Copilot can use context from all open files, so try to open files related to what you're working on.\n\n\u003e [!TIP]\n\u003e In VS Code or Visual Studio, you can explicitly tell Copilot to use a specific file or the selection by using the `#` command.\n\n### Make a Joke class\n\nHere's a sample response from the joke api:\n\n```json\n{\n  \"icon_url\": \"https://assets.chucknorris.host/img/avatar/chuck-norris.png\",\n  \"id\": \"Bup36JbASxW5R-HzSI5ygA\",\n  \"url\": \"\",\n  \"value\": \"Chuck Norris once participated in a 100 mt race and obviously came first, light came second.\"\n}\n```\n\n**Create a class called `Joke` that represent the joke response.**\n\n\u003e [!CAUTION] \n\u003e Pay extra attention to the `icon_url` field. Can you make sure that the `icon_url` is mapped to the C# property `IconUrl`? There are several ways to do this, try to find the best one. Is Copilot Chat or Autocomplete better? Does it matter if you have added a `using` statement for `System.Text.Json.Serialization`?\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt (Autocomplete)\u003c/summary\u003e\n\u003cpre\u003e\n/*\nCreate a class Joke class that can be deserialized from the Chuck Norris API. \nMake sure to use the correct property names and types. Serialize/deserialize all properties names to lower snake case.\n\n```json \n{\n   \"icon_url\" : \"https://assets.chucknorris.host/img/avatar/chuck-norris.png\",\n   \"id\" : \"Bup36JbASxW5R-HzSI5ygA\",\n   \"url\" : \"\",\n   \"value\" : \"Chuck Norris once participated in a 100 mt race and obviously came first, light came second.\"\n}\n```\n*/\n\u003c/pre\u003e\n\u003c/details\u003e\n\n### Make a JokeService\n\nLet's create a service called `JokeService` that will be responsible for fetching the joke from the API. The class should fetch a random joke from the API and return it as a `Joke` object. The API endpoint is `https://api.chucknorris.io/jokes/random`.\n\nThis service should be **registered with the Dependency Injection container**. Make sure that it is testable and that the http calls to the api can be mocked. Can Copilot Chat help you with that?\n\nFor that **you will need a IJokeService interface that has a public method called GetRandomJoke that returns a Joke.\nYou will also need a JokeService class that implements the IJokeService interface**.\n\n\u003e The method will make a http call, so is there something you need to be specific about in the interface and implementation to make that work?\n\n\u003e Can you avoid having the base url hardcoded in the JokeService class and instead be defined in `Program.cs`? Is that something Copilot Chat can help with?\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt (Autocomplete) for IJokeService\u003c/summary\u003e\n\u003cpre\u003e\n// Make a public interface called IJokeService that has a public async method called GetRandomJoke.\n// The method returns a Joke object. Joke can be null.\n\u003c/pre\u003e\n\u003c/details\u003e\n\u0026nbsp;\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt (Autocomplete) for JokeService\u003c/summary\u003e\n\u003cpre\u003e\n/*\n * Create a JokeService class that implements IJokeService.\n * The class should take an HttpClient as a constructor argument.\n * The GetRandomJoke method should make a GET request to `https://api.chucknorris.io/jokes/random` and return the result as a Joke object.\n */ \n\u003c/pre\u003e\n\u003c/details\u003e\n\u0026nbsp;\n\n\u003e This is a good example of how the resulting code can be better or worse by just adding a using statement. Try adding a `using System.Net.Http.Json;` and see how the result changes.\n\n\n\u003e [!HINT] \n\u003e If you believe that the code is not using the best way to handle http requests, you can ask Copilot Chat to improve it, or you can write the code yourself. One example here might be how the request is executed and then deserialized, which can be done in single line of code.\n\n#### Register the JokeService with the Dependency Injection container\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt in Program.cs (Autocomplete)\u003c/summary\u003e\n\u003cpre\u003e\n// Add the IJokeService and JokeService to the services collection that uses \"https://api.chucknorris.io/\" as base address.\n\u003c/pre\u003e\n\u003c/details\u003e\n\n### Add documentation to the GetRandomJoke method\n\nUse the `/doc` slash command to add documentation for the GetRandomJoke method.\n\n### Make a JokeController\n\nLet's make the JokeController that will have a single GET endpoint that returns a random joke.\n\nThe controller should get an instance of `IJokeService` injected in the constructor.\n\n**Make a `GET` endpoint for `/` that returns a random joke.**\n\n\u003e How does the result of your prompts differ if you have IJokeService and JokeService open or closed?\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt (Autocomplete)\u003c/summary\u003e\n\u003cpre\u003e\n// Make a JokeController that uses the IJokeService.\n// The controller should have a single Http Get endpoint that returns a random joke.\n\u003c/pre\u003e\n\u003c/details\u003e\n\n### Add Swagger documentation for the JokeController\n\nSee if you can get Copilot to help you add Swagger documentation for the JokeController.\nIt can produce both a 200 Ok response for a Joke and a 500 Internal Server Error response.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt (Chat)\u003c/summary\u003e\n\u003cpre\u003e\nAdd Swagger documentation attributes to the GetJoke action\n\u003c/pre\u003e\n\u003c/details\u003e\n\n## Testing\n\nLet's make some tests for the JokeService and the JokeController.\n\n### Test the JokeController\n\nThe JokeController should be tested to make sure that it returns a random joke. The test should mock the `IJokeService` to control what it will return and to make throw exceptions.\n\nOpen JokeController.cs and see if Copilot Chat can help you write tests. You want to test both a successful response and a failed response. Use the `/tests` slash command to get help with writing the tests.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt with JokeController.cs open (Chat)\u003c/summary\u003e\n\u003cpre\u003e\n/tests Create Xunit tests for the JokeController that tests both a successful response and a failed response.\n\u003c/pre\u003e\n\u003c/details\u003e\n\n### Test the JokeService\n\nThe JokeService is somewhat tricky to test because it makes a http call. We need to make sure that the JokeService can be tested without making a real http call. There are a couple of ways to do this. A common way is to abstract the http call into a separate interface and then mock that interface in the tests.\n\nSee if you can get some help from Copilot Chat to make the JokeService testable.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample prompt with JokeService.cs open (Chat)\u003c/summary\u003e\n\u003cpre\u003e\nExplain how I can improve #editor code for testing.\n\u003c/pre\u003e\n\u003c/details\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftfsjohan%2Fgithub-copilot-demo-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftfsjohan%2Fgithub-copilot-demo-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftfsjohan%2Fgithub-copilot-demo-dotnet/lists"}