Skip to content

Commit

Permalink
Feature/36 improve response types for grpc support (#37)
Browse files Browse the repository at this point in the history
* Make response types Grpc Compatible.

* Add support for asynchronous paginiation.

* Revert old response types.

* add constructor for generic response base.
  • Loading branch information
Reza-Noei committed Jun 8, 2023
1 parent 02bf90d commit e3235e4
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 126 deletions.
Original file line number Diff line number Diff line change
@@ -1,80 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{746AF465-DE8E-41C9-B558-CFFC6E3638D4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BSN.Commons.Orm.EntityFramework</RootNamespace>
<AssemblyName>BSN.Commons.Orm.EntityFramework</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.Identity.Core.2.2.3\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RepositoryBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BSN.Commons\BSN.Commons.csproj">
<Project>{ffef752b-4e11-44ff-82fa-9aec0b607990}</Project>
<Name>BSN.Commons</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
<Error Condition="!Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
</Target>
<Import Project="..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{746AF465-DE8E-41C9-B558-CFFC6E3638D4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BSN.Commons.Orm.EntityFramework</RootNamespace>
<AssemblyName>BSN.Commons.Orm.EntityFramework</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.Identity.Core.2.2.3\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions\IQueryableExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RepositoryBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BSN.Commons\BSN.Commons.csproj">
<Project>{ffef752b-4e11-44ff-82fa-9aec0b607990}</Project>
<Name>BSN.Commons</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
<Error Condition="!Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
</Target>
<Import Project="..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
</Project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Data.Entity;
using System.Linq;

using System.Threading.Tasks;

namespace BSN.Commons.Extensions
{
public static partial class IQueryableExtensions
Expand All @@ -27,6 +29,31 @@ public static PagedEntityCollection<T> Paginate<T>(this IQueryable<T> query, uin

result.PageCount = (uint)Math.Ceiling((double)result.RecordCount / pageSize);

return result;
}

/// <summary>
/// Paginate IQueryable of <T>
/// with given pageNumber and pageSize
/// </summary>
public static async Task<PagedEntityCollection<T>> PaginateAsync<T>(this IQueryable<T> 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<T>
{
CurrentPage = pageNumber,
PageSize = pageSize,
RecordCount = (uint) await query.CountAsync(),
Results = await query.Skip((int)((pageNumber - 1) * pageSize)).Take((int)pageSize).ToListAsync()
};

result.PageCount = (uint)Math.Ceiling((double)result.RecordCount / pageSize);

return result;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace BSN.Commons.Extensions
{
public static partial class IQueryableExtensions
{
/// <summary>
/// Paginate IQueryable of <T>
/// with given pageNumber and pageSize
/// </summary>
public static PagedEntityCollection<T> Paginate<T>(this IQueryable<T> 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<T>
{
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;
}

/// <summary>
/// Paginate IQueryable of <T>
/// with given pageNumber and pageSize
/// </summary>
public static async Task<PagedEntityCollection<T>> PaginateAsync<T>(this IQueryable<T> 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<T>
{
CurrentPage = pageNumber,
PageSize = pageSize,
RecordCount = (uint) await query.CountAsync(),
Results = await query.Skip((int)((pageNumber - 1) * pageSize)).Take((int)pageSize).ToListAsync()
};

result.PageCount = (uint)Math.Ceiling((double)result.RecordCount / pageSize);

return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
namespace BSN.Commons.Responses
{
/// <summary>
/// Add data as given type to response class.
/// </summary>
/// <typeparam name="T"> The type of object or value handled by the class. </typeparam>
public class GenericResponseBase<T> : Response where T : class
{
public GenericResponseBase() { }

public T Data { get; set; }
}
}
using System;

namespace BSN.Commons.Responses
{
/// <summary>
/// Generic base response.
/// </summary>
/// <typeparam name="T"> The type of object or value handled by the class. </typeparam>
[Obsolete("Due to incompatability with Grpc this response type is only used for backward compatibility.")]
public class GenericResponseBase<T> : Response where T : class
{
public GenericResponseBase() { }

public T Data { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
namespace BSN.Commons.Responses
{
/// <summary>
/// Generic response base for paginated data.
/// </summary>
/// <remarks>
/// Paginated response provides metadata for navigation purpose.
/// </remarks>
/// <typeparam name="T">Data type.</typeparam>
public class GenericResponseBaseWithPagination<T> : GenericResponseBase<T> where T : class
{
/// <summary>
/// Pagination metada used by the client as the parameters for navigation through whole records.
/// </summary>
public PaginationMetadata Meta { get; set; }
}
}
using System;

namespace BSN.Commons.Responses
{
/// <summary>
/// Generic response base for paginated data.
/// </summary>
/// <remarks>
/// Paginated response provides metadata for navigation purpose.
/// </remarks>
/// <typeparam name="T">Data type.</typeparam>
[Obsolete("Due to incompatability with Grpc this response type is only used for backward compatibility.")]
public class GenericResponseBaseWithPagination<T> : GenericResponseBase<T> where T : class
{
public GenericResponseBaseWithPagination() { }

/// <summary>
/// Pagination metada used by the client as the parameters for navigation through whole records.
/// </summary>
public PaginationMetadata Meta { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Runtime.Serialization;

namespace BSN.Commons.Responses
{
/// <summary>
/// Represents a request validation issue for the API consumers.
/// </summary>
[DataContract]
public class InvalidItem
{
/// <summary>
/// Name of the request item.
/// </summary>
[DataMember(Order = 1)]
public string Name { get; set; }

/// <summary>
/// The reason caused the validation issue.
/// </summary>
[DataMember(Order = 2)]
public string Reason { get; set; }
}
}
Loading

0 comments on commit e3235e4

Please sign in to comment.