diff --git a/src/backend/.config/dotnet-tools.json b/src/backend/.config/dotnet-tools.json
index e7d553a..fb1dd62 100644
--- a/src/backend/.config/dotnet-tools.json
+++ b/src/backend/.config/dotnet-tools.json
@@ -36,6 +36,13 @@
"dotnet-outdated"
],
"rollForward": false
+ },
+ "refitter": {
+ "version": "1.4.0",
+ "commands": [
+ "refitter"
+ ],
+ "rollForward": false
}
}
}
\ No newline at end of file
diff --git a/src/backend/ApiClient/ApiClient.csproj b/src/backend/ApiClient/ApiClient.csproj
new file mode 100644
index 0000000..7be0d5f
--- /dev/null
+++ b/src/backend/ApiClient/ApiClient.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/ApiClient/Program.cs b/src/backend/ApiClient/Program.cs
new file mode 100644
index 0000000..501d770
--- /dev/null
+++ b/src/backend/ApiClient/Program.cs
@@ -0,0 +1,5 @@
+using Refit;
+using WebApi.Client;
+
+var testApiClient = RestService.For("https://localhost:44380");
+await testApiClient.Ping();
\ No newline at end of file
diff --git a/src/backend/ApiClient/WebApiClient.cs b/src/backend/ApiClient/WebApiClient.cs
new file mode 100644
index 0000000..5efb3c5
--- /dev/null
+++ b/src/backend/ApiClient/WebApiClient.cs
@@ -0,0 +1,424 @@
+//
+// This code was generated by Refitter.
+//
+
+
+using Refit;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+
+#nullable enable annotations
+
+namespace WebApi.Client
+{
+ [System.CodeDom.Compiler.GeneratedCode("Refitter", "1.4.0.0")]
+ public partial interface IExampleAPI
+ {
+ /// Gets a list of all blogs.
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Blogging/blog")]
+ Task> GetBlogs();
+
+ /// Creates a new blog or updates an existing one.
+ /// The blog data transfer object
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Post("/Blogging/blog")]
+ Task PostBlog([Body] BlogDto body);
+
+ /// Gets a specific blog by ID.
+ /// The ID of the blog.
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Blogging/blog/{id}")]
+ Task GetBlog(int id);
+
+ /// Gets a list of posts related to a specific blog.
+ /// The ID of the blog
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Blogging/blog/{blogId}/posts")]
+ Task> GetPosts(int blogId);
+
+ /// Gets a specific post by ID.
+ /// The ID of the post
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Blogging/post/{id}")]
+ Task GetPost(int id);
+
+ /// Creates a new post.
+ /// The post data transfer object
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Post("/Blogging/post")]
+ Task PostPost([Body] PostDto body);
+
+ /// Sends a message using the MessageSender service.
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/SendMessage")]
+ Task SendMessage();
+
+ /// Returns ok
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Service/ping")]
+ Task Ping();
+
+ /// Returns version
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/Service/version")]
+ Task Version();
+
+ /// Returns weather forecast
+ /// OK
+ ///
+ /// Thrown when the request returns a non-success status code:
+ ///
+ ///
+ /// Status
+ /// Description
+ ///
+ /// -
+ /// 500
+ /// Internal Server Error
+ ///
+ ///
+ ///
+ [Headers("Accept: application/json")]
+ [Get("/WeatherForecast")]
+ Task> GetWeatherForecast();
+
+
+ }
+
+}
+
+//----------------------
+//
+// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
+//
+//----------------------
+
+#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
+#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
+#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
+#pragma warning disable 612 // Disable "CS0612 '...' is obsolete"
+#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null"
+#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
+#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
+#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
+#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
+#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"
+#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter"
+#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type"
+#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)."
+
+namespace WebApi.Client
+{
+ using System = global::System;
+
+
+
+ ///
+ /// Blog DTO
+ ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ public partial class BlogDto
+ {
+ ///
+ /// Gets or sets the unique identifier for the blog.
+ ///
+
+ [JsonPropertyName("blogId")]
+ public int BlogId { get; set; }
+
+ ///
+ /// Gets or sets the title of the blog.
+ ///
+
+ [JsonPropertyName("title")]
+ public string Title { get; set; }
+
+ ///
+ /// Gets or sets the URL of the blog.
+ ///
+
+ [JsonPropertyName("url")]
+ public string Url { get; set; }
+
+ }
+
+ ///
+ /// Post DTO
+ ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ public partial class PostDto
+ {
+ ///
+ /// Gets or sets the unique identifier for the post.
+ ///
+
+ [JsonPropertyName("postId")]
+ public int PostId { get; set; }
+
+ ///
+ /// Gets or sets the title of the post.
+ ///
+
+ [JsonPropertyName("title")]
+ public string Title { get; set; }
+
+ ///
+ /// Gets or sets the content of the post.
+ ///
+
+ [JsonPropertyName("content")]
+ public string Content { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier of the blog to which the post belongs.
+ ///
+
+ [JsonPropertyName("blogId")]
+ public int BlogId { get; set; }
+
+ }
+
+ ///
+ /// Represents a generic value container for value types.
+ ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ public partial class StringGenericValue
+ {
+ ///
+ /// Gets or sets the value stored in the container.
+ ///
+
+ [JsonPropertyName("value")]
+ public string Value { get; set; }
+
+ }
+
+ ///
+ /// Represents version information for an assembly, including constants, environment name, version, and informational
+ ///
version.
+ ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ public partial class VersionInformation
+ {
+ ///
+ /// Constants defined in the assembly, if any.
+ ///
+
+ [JsonPropertyName("constants")]
+ public ICollection Constants { get; set; }
+
+ ///
+ /// The version of the assembly.
+ ///
+
+ [JsonPropertyName("version")]
+ public string Version { get; set; }
+
+ ///
+ /// The informational version of the assembly, which may include additional details.
+ ///
+
+ [JsonPropertyName("informationalVersion")]
+ public string InformationalVersion { get; set; }
+
+ ///
+ /// The name of the environment where the application is running.
+ ///
+
+ [JsonPropertyName("environmentName")]
+ public string EnvironmentName { get; set; }
+
+ }
+
+ ///
+ /// Weather forecast model
+ ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ public partial class WeatherForecast
+ {
+ ///
+ /// Date of forecast
+ ///
+
+ [JsonPropertyName("date")]
+ [JsonConverter(typeof(DateFormatConverter))]
+ public System.DateTimeOffset Date { get; set; }
+
+ ///
+ /// Temperature in celsius
+ ///
+
+ [JsonPropertyName("temperatureC")]
+ public int TemperatureC { get; set; }
+
+ ///
+ /// Summary text
+ ///
+
+ [JsonPropertyName("summary")]
+ public string Summary { get; set; }
+
+ }
+
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
+ internal class DateFormatConverter : JsonConverter
+ {
+ public override System.DateTimeOffset Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
+ {
+ var dateTime = reader.GetString();
+ if (dateTime == null)
+ {
+ throw new System.Text.Json.JsonException("Unexpected JsonTokenType.Null");
+ }
+
+ return System.DateTimeOffset.Parse(dateTime);
+ }
+
+ public override void Write(System.Text.Json.Utf8JsonWriter writer, System.DateTimeOffset value, System.Text.Json.JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString("yyyy-MM-dd"));
+ }
+ }
+
+
+}
+
+#pragma warning restore 108
+#pragma warning restore 114
+#pragma warning restore 472
+#pragma warning restore 612
+#pragma warning restore 1573
+#pragma warning restore 1591
+#pragma warning restore 8073
+#pragma warning restore 3016
+#pragma warning restore 8603
+#pragma warning restore 8604
+#pragma warning restore 8625
\ No newline at end of file
diff --git a/src/backend/ApiClient/packages.lock.json b/src/backend/ApiClient/packages.lock.json
new file mode 100644
index 0000000..c540b6f
--- /dev/null
+++ b/src/backend/ApiClient/packages.lock.json
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net9.0": {
+ "Refit": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "gXRmIy3Va0mwwr8usnqVRQFoFIJaJGlWTTXBlwxIkHB/xwXnq1Ybs1YNA2BM1O4G46JLLlGjg6YOwrTZusuY3Q=="
+ }
+ },
+ "net9.0/linux-musl-x64": {},
+ "net9.0/win-x64": {}
+ }
+}
\ No newline at end of file
diff --git a/src/backend/Backend.sln b/src/backend/Backend.sln
index cd8ae57..67fc9fa 100644
--- a/src/backend/Backend.sln
+++ b/src/backend/Backend.sln
@@ -36,6 +36,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "log", "log", "{0BD80B55-00B
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NugetDistSample", "..\..\shared\NugetDistSample\NugetDistSample.csproj", "{FC33B9B5-7F55-4C06-A9CE-811FE31DDE2D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiClient", "ApiClient\ApiClient.csproj", "{2EAC07D7-36C3-48E3-9C4D-98CEB9AE8CA4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,6 +60,10 @@ Global
{FC33B9B5-7F55-4C06-A9CE-811FE31DDE2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC33B9B5-7F55-4C06-A9CE-811FE31DDE2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC33B9B5-7F55-4C06-A9CE-811FE31DDE2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2EAC07D7-36C3-48E3-9C4D-98CEB9AE8CA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2EAC07D7-36C3-48E3-9C4D-98CEB9AE8CA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2EAC07D7-36C3-48E3-9C4D-98CEB9AE8CA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2EAC07D7-36C3-48E3-9C4D-98CEB9AE8CA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/backend/Directory.Build.props b/src/backend/Directory.Build.props
index 7d1c2a0..1f3bbb4 100644
--- a/src/backend/Directory.Build.props
+++ b/src/backend/Directory.Build.props
@@ -17,10 +17,6 @@
-
- <_Parameter1>"$(DefineConstants)"
-
-
diff --git a/src/backend/WebApi/WebApi.csproj b/src/backend/WebApi/WebApi.csproj
index 1ffba7f..488cc78 100644
--- a/src/backend/WebApi/WebApi.csproj
+++ b/src/backend/WebApi/WebApi.csproj
@@ -35,6 +35,9 @@
+
+ <_Parameter1>"$(DefineConstants)"
+