diff --git a/Source/BSN.Commons.PresentationInfrastructure/BSN.Commons.PresentationInfrastructure.csproj b/Source/BSN.Commons.PresentationInfrastructure/BSN.Commons.PresentationInfrastructure.csproj
index eccb3bc..dda0e7f 100644
--- a/Source/BSN.Commons.PresentationInfrastructure/BSN.Commons.PresentationInfrastructure.csproj
+++ b/Source/BSN.Commons.PresentationInfrastructure/BSN.Commons.PresentationInfrastructure.csproj
@@ -17,6 +17,7 @@
+
diff --git a/Source/BSN.Commons.PresentationInfrastructure/Converters/JsonForceDefaultConverter.cs b/Source/BSN.Commons.PresentationInfrastructure/Converters/JsonForceDefaultConverter.cs
new file mode 100644
index 0000000..a333444
--- /dev/null
+++ b/Source/BSN.Commons.PresentationInfrastructure/Converters/JsonForceDefaultConverter.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace BSN.Commons.Converters
+{
+ ///
+ /// Force to keep numeral object or value, while convert an object or value to or from JSON.
+ /// for example 'StatusCode' in Response that should stay numeral.
+ ///
+ /// The type of object or value handled by the converter.
+ public class JsonForceDefaultConverter : JsonConverter
+ {
+ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return JsonSerializer.Deserialize(ref reader);
+ }
+
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ JsonSerializer.Serialize(writer, value);
+ }
+ }
+}
diff --git a/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBase.cs b/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBase.cs
new file mode 100644
index 0000000..5710686
--- /dev/null
+++ b/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBase.cs
@@ -0,0 +1,13 @@
+namespace BSN.Commons.Responses
+{
+ ///
+ /// Add data as given type to response class.
+ ///
+ /// The type of object or value handled by the class.
+ public class GenericResponseBase : Response where T : class
+ {
+ public GenericResponseBase() { }
+
+ public T Data { get; set; }
+ }
+}
diff --git a/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBaseWithPagination.cs b/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBaseWithPagination.cs
new file mode 100644
index 0000000..80edcb1
--- /dev/null
+++ b/Source/BSN.Commons.PresentationInfrastructure/Responses/GenericResponseBaseWithPagination.cs
@@ -0,0 +1,17 @@
+namespace BSN.Commons.Responses
+{
+ ///
+ /// Generic response base for paginated data.
+ ///
+ ///
+ /// Paginated response provides metadata for navigation purpose.
+ ///
+ /// Data type.
+ public class GenericResponseBaseWithPagination : GenericResponseBase where T : class
+ {
+ ///
+ /// Pagination metada used by the client as the parameters for navigation through whole records.
+ ///
+ public PaginationMetadata Meta { get; set; }
+ }
+}
diff --git a/Source/BSN.Commons.PresentationInfrastructure/Responses/PaginationMetadata.cs b/Source/BSN.Commons.PresentationInfrastructure/Responses/PaginationMetadata.cs
new file mode 100644
index 0000000..f57abdc
--- /dev/null
+++ b/Source/BSN.Commons.PresentationInfrastructure/Responses/PaginationMetadata.cs
@@ -0,0 +1,28 @@
+namespace BSN.Commons.Responses
+{
+ ///
+ /// Stores the paginated meta data.
+ ///
+ public class PaginationMetadata
+ {
+ ///
+ /// Current page number
+ ///
+ public uint Page { get; set; }
+
+ ///
+ /// Total number of pages
+ ///
+ public uint PageCount { get; set; }
+
+ ///
+ /// Number of records per page
+ ///
+ public uint PageSize { get; set; }
+
+ ///
+ /// Total number of records that exist
+ ///
+ public uint RecordCount { get; set; }
+ }
+}
diff --git a/Source/BSN.Commons.PresentationInfrastructure/Responses/Response.cs b/Source/BSN.Commons.PresentationInfrastructure/Responses/Response.cs
new file mode 100644
index 0000000..3524f93
--- /dev/null
+++ b/Source/BSN.Commons.PresentationInfrastructure/Responses/Response.cs
@@ -0,0 +1,19 @@
+using BSN.Commons.Converters;
+using BSN.Commons.PresentationInfrastructure;
+using System.Text.Json.Serialization;
+
+namespace BSN.Commons.Responses
+{
+ ///
+ /// During serialization and deserialization operations, enumeration values are always converted to and from strings.
+ /// This is possible through registering the 'JsonStringEnumConverter' in our DI infrastructure. There is once exception,
+ /// namely the 'StatusCode' property of the 'ResponseBase' class which should keep it's default numeral value when being converted.
+ ///
+ public class Response : ResponseBase
+ {
+ public new bool IsSuccess => (int)StatusCode >= 200 && (int)StatusCode <= 299;
+
+ [JsonConverter(typeof(JsonForceDefaultConverter))]
+ public new ResponseStatusCode StatusCode { get; set; }
+ }
+}
diff --git a/Source/BSN.Commons/Dto/PagedEntityCollection.cs b/Source/BSN.Commons/Dto/PagedEntityCollection.cs
new file mode 100644
index 0000000..5b3c28c
--- /dev/null
+++ b/Source/BSN.Commons/Dto/PagedEntityCollection.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+
+namespace BSN.Commons.Dto
+{
+ ///
+ /// Stores the paginated data for the given entity type.
+ ///
+ /// Type of Entity for which pagination is being implemented.
+ public class PagedEntityCollection
+ {
+ ///
+ /// Current page number
+ ///
+ public uint CurrentPage { get; set; }
+
+ ///
+ /// Total number of pages
+ ///
+ public uint PageCount { get; set; }
+
+ ///
+ /// Number of records per page
+ ///
+ public uint PageSize { get; set; }
+
+ ///
+ /// Total number of records that exist for the query
+ ///
+ public uint RecordCount { get; set; }
+
+ ///
+ /// IEnumerable of the paginated data
+ ///
+ public IEnumerable Results { get; set; }
+ }
+}
diff --git a/Source/BSN.Commons/Extensions/IQueryableExtensions.cs b/Source/BSN.Commons/Extensions/IQueryableExtensions.cs
new file mode 100644
index 0000000..68925fa
--- /dev/null
+++ b/Source/BSN.Commons/Extensions/IQueryableExtensions.cs
@@ -0,0 +1,34 @@
+using BSN.Commons.Dto;
+using System;
+using System.Linq;
+
+namespace BSN.Commons.Extensions
+{
+ public static partial class IQueryableExtensions
+ {
+ ///
+ /// Paginate IQueryable of
+ /// with given pageNumber and pageSize
+ ///
+ public static PagedEntityCollection Paginate(this IQueryable query, uint pageNumber, uint pageSize)
+ {
+ if (pageNumber == 0)
+ throw new ArgumentException("Must be greater than zero.", nameof(pageNumber));
+
+ if (pageSize == 0)
+ throw new ArgumentException("Must be greater than zero.", nameof(pageSize));
+
+ var result = new PagedEntityCollection
+ {
+ CurrentPage = pageNumber,
+ PageSize = pageSize,
+ RecordCount = (uint)query.Count(),
+ Results = query.Skip((int)((pageNumber - 1) * pageSize)).Take((int)pageSize).ToList()
+ };
+
+ result.PageCount = (uint)Math.Ceiling((double)result.RecordCount / pageSize);
+
+ return result;
+ }
+ }
+}