{"id":17037986,"url":"https://github.com/kzu/dotnet-echo","last_synced_at":"2025-04-12T13:52:01.712Z","repository":{"id":36986224,"uuid":"368695574","full_name":"kzu/dotnet-echo","owner":"kzu","description":"A .NET cross-platform micro-service that just echoes whatever you send it","archived":false,"fork":false,"pushed_at":"2025-02-09T18:45:28.000Z","size":1007,"stargazers_count":5,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T13:49:20.149Z","etag":null,"topics":["cli","csharp","dotnet","dotnet-tool","dotnet-tools"],"latest_commit_sha":null,"homepage":"https://www.cazzulino.com/dotnet-echo","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kzu.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":"devlooped"}},"created_at":"2021-05-18T23:56:27.000Z","updated_at":"2025-02-09T18:45:32.000Z","dependencies_parsed_at":"2023-02-13T05:25:13.885Z","dependency_job_id":null,"html_url":"https://github.com/kzu/dotnet-echo","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2Fdotnet-echo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2Fdotnet-echo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2Fdotnet-echo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2Fdotnet-echo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kzu","download_url":"https://codeload.github.com/kzu/dotnet-echo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248575955,"owners_count":21127301,"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":["cli","csharp","dotnet","dotnet-tool","dotnet-tools"],"created_at":"2024-10-14T08:55:38.925Z","updated_at":"2025-04-12T13:52:01.690Z","avatar_url":"https://github.com/kzu.png","language":"C#","funding_links":["https://github.com/sponsors/devlooped"],"categories":[],"sub_categories":[],"readme":"![Icon](https://raw.githubusercontent.com/kzu/dotnet-echo/main/assets/img/icon-32.png) dotnet-echo\n============\n\n[![Version](https://img.shields.io/nuget/v/dotnet-echo.svg?color=royalblue)](https://www.nuget.org/packages/dotnet-echo) [![Downloads](https://img.shields.io/nuget/dt/dotnet-echo.svg?color=darkmagenta)](https://www.nuget.org/packages/dotnet-echo) [![License](https://img.shields.io/github/license/kzu/dotnet-echo.svg?color=blue)](https://github.com/kzu/dotnet-echo/blob/main/LICENSE) [![CI Status](https://github.com/kzu/dotnet-file/workflows/build/badge.svg?branch=main)](https://github.com/kzu/dotnet-file/actions?query=branch%3Amain+workflow%3Abuild+) [![CI Version](https://img.shields.io/endpoint?url=https://shields.kzu.io/vpre/dotnet-echo/main\u0026label=nuget.ci\u0026color=brightgreen)](https://pkg.kzu.io/index.json)\n\nInstalling or updating (same command can be used for both):\n\n```\ndotnet tool update -g dotnet-echo\n```\n\nUsage:\n\n```\n\u003e dotnet echo -?\necho\n  A trivial program that echoes whatever is sent to it via HTTP or gRPC\n\nUsage:\n  echo [options] [\u003cport\u003e...]\n\nArguments:\n  \u003cport\u003e  Port(s) to listen on. [default: 80 or 443 with --ssl] [default: ]\n\nOptions:\n  -ssl            Use HTTPS with self-signed SSL certificate, persisted as dotnet-echo.pfx in the current directory.\n  -http2          Use HTTP/2 only. Prevents additional port for HTTP/2 to support gRPC.\n  --version       Show version information\n  -?, -h, --help  Show help and usage information\n```\n\nThe program will automatically check for updates once a day and recommend updating \nif there is a new version available.\n\nThe service supports gRPC too, with [echo.proto](src/dotnet-echo/echo.proto):\n\n```protobuf\nsyntax = \"proto3\";\n\nservice chamber {\n  rpc echo (message) returns (message);\n}\n\nmessage message {\n  string payload = 1;\n}\n```\n\nSince gRPC [needs to use HTTP/2](https://docs.microsoft.com/en-US/aspnet/core/grpc/troubleshoot?view=aspnetcore-5.0#unable-to-start-aspnet-core-grpc-app-on-macos), \n`dotnet-echo` will use the specified `port`(s) + 1 to listen HTTP/2-only traffic \n(i.e. if you specify `8080`, the gRPC endpoint will be available at `http://localhost:8081`). \nYou can avoid the additional port by forcing HTTP/2-only with the `--http2` option.\n\nExample of a .NET client to run `echo` in the `chamber` service:\n\n```xml\n\u003cProject\u003e\n  ...\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"Google.Protobuf\" Version=\"*\" /\u003e\n    \u003cPackageReference Include=\"Grpc.Net.Client\" Version=\"*\" /\u003e\n    \u003cPackageReference Include=\"Grpc.Tools\" Version=\"*\" /\u003e\n  \u003c/ItemGroup\u003e\n  \u003cItemGroup\u003e\n    \u003cProtobuf Include=\"echo.proto\" GrpcServices=\"Client\" /\u003e\n  \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\n```csharp\nvar channel = GrpcChannel.ForAddress(\"http://localhost:8081\");\nvar service = new chamber.chamberClient(channel);\n\nvar response = await service.echoAsync(new message { Payload = \"Hello World\" }, cancellationToken: cancellation);\n\nConsole.WriteLine(response.Payload);\n```\n\nExample of a .NET client using HTTP/2 only mode for a regular HTTP POST:\n\n```csharp\nvar http = new HttpClient();\n\nvar send = await http.SendAsync(new HttpRequestMessage(\n    HttpMethod.Post,\n    \"http://localhost:8081\")\n    {\n        Content = new StringContent(\"Hello HTTP\"),\n        Version = new Version(2, 0),\n        VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher,\n    });\n```\n\nAlternatively, you can force all HTTP requests to be sent with the \nrequired Version 2.0 property with a simple delegating HTTP handler like :\n\n```csharp\nclass Http2Handler : DelegatingHandler\n{\n    public Http2Handler() : this(new HttpClientHandler()) { }\n    public Http2Handler(HttpMessageHandler inner) : base(inner) { }\n\n    protected override Task\u003cHttpResponseMessage\u003e SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\n    {\n        request.Version = new Version(2, 0);\n        request.VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;\n        return base.SendAsync(request, cancellationToken);\n    }\n}\n```\n\nWhich can be consumed like:\n\n```csharp\nvar http = new HttpClient(new Http2Handler());\n\nvar post = await http.PostAsync(\"http://localhost:8081\", new StringContent(\"Hello HTTP\"));\n```\n\nSince the handler automatically sets the relevant message properties, we can use the simpler \n`Delete/Get/Post/Put` methods instead.\n\n\nAn example of the output during execution:\n\n![](https://raw.githubusercontent.com/kzu/dotnet-echo/main/assets/img/echo.gif)\n\nAnd running on Ubuntu:\n\n![](https://raw.githubusercontent.com/kzu/dotnet-echo/main/assets/img/echo-ubuntu.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkzu%2Fdotnet-echo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkzu%2Fdotnet-echo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkzu%2Fdotnet-echo/lists"}