(feature): init
This commit is contained in:
parent
c93020745a
commit
0d170df610
4
.gitignore
vendored
4
.gitignore
vendored
@ -260,7 +260,3 @@ paket-files/
|
|||||||
# Python Tools for Visual Studio (PTVS)
|
# Python Tools for Visual Studio (PTVS)
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
|
|
||||||
**/*docker-compose/LetsEncryptServer/acme
|
|
||||||
**/*docker-compose/LetsEncryptServer/cache
|
|
||||||
215
README.md
Normal file
215
README.md
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
# MaksIT.Results
|
||||||
|
|
||||||
|
`MaksIT.Results` is a powerful library designed to streamline the creation and management of result objects in your ASP.NET Core applications. It provides a standardized way to handle method results and easily convert them to `IActionResult` for HTTP responses, ensuring consistent and clear API responses.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Standardized Result Handling**: Represent operation outcomes (success or failure) with appropriate HTTP status codes.
|
||||||
|
- **Seamless Conversion to `IActionResult`**: Convert result objects to HTTP responses (`IActionResult`) with detailed problem descriptions.
|
||||||
|
- **Flexible Result Types**: Supports both generic (`Result<T>`) and non-generic (`Result`) results for handling various scenarios.
|
||||||
|
- **Predefined Results for All Standard HTTP Status Codes**: Includes predefined static methods to create results for all standard HTTP status codes (e.g., 200 OK, 404 Not Found, 500 Internal Server Error, etc.).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install `MaksIT.Results`, use the NuGet Package Manager:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Install-Package MaksIT.Results
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage example
|
||||||
|
|
||||||
|
Below is an example demonstrating how to use `MaksIT.Results` in a typical ASP.NET Core application where a controller interacts with a service.
|
||||||
|
|
||||||
|
### Step 1: Define and Register the Service
|
||||||
|
|
||||||
|
Define a service that uses `MaksIT.Results` to return operation results, handling different result types with proper casting and conversion.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IVaultPersistanceService
|
||||||
|
{
|
||||||
|
Result<Organization?> ReadOrganization(Guid organizationId);
|
||||||
|
Task<Result> DeleteOrganizationAsync(Guid organizationId);
|
||||||
|
// Additional method definitions...
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VaultPersistanceService : IVaultPersistanceService
|
||||||
|
{
|
||||||
|
// Inject dependencies as needed
|
||||||
|
|
||||||
|
public Result<Organization?> ReadOrganization(Guid organizationId)
|
||||||
|
{
|
||||||
|
var organizationResult = _organizationDataProvider.GetById(organizationId);
|
||||||
|
if (!organizationResult.IsSuccess || organizationResult.Value == null)
|
||||||
|
{
|
||||||
|
// Return a NotFound result when the organization isn't found
|
||||||
|
return Result<Organization?>.NotFound("Organization not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var organization = organizationResult.Value;
|
||||||
|
var applicationDtos = new List<ApplicationDto>();
|
||||||
|
|
||||||
|
foreach (var applicationId in organization.Applications)
|
||||||
|
{
|
||||||
|
var applicationResult = _applicationDataProvider.GetById(applicationId);
|
||||||
|
if (!applicationResult.IsSuccess || applicationResult.Value == null)
|
||||||
|
{
|
||||||
|
// Transform the result from Result<Application?> to Result<Organization?>
|
||||||
|
// Ensuring the return type matches the method signature (Result<Organization?>)
|
||||||
|
return applicationResult.WithNewValue<Organization?>(_ => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var applicationDto = applicationResult.Value;
|
||||||
|
applicationDtos.Add(applicationDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the final result with all applications loaded
|
||||||
|
return Result<Organization>.Ok(organization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result> DeleteOrganizationAsync(Guid organizationId)
|
||||||
|
{
|
||||||
|
var organizationResult = await _organizationDataProvider.GetByIdAsync(organizationId);
|
||||||
|
|
||||||
|
if (!organizationResult.IsSuccess || organizationResult.Value == null)
|
||||||
|
{
|
||||||
|
// Convert Result<Organization?> to a non-generic Result
|
||||||
|
// The cast to (Result) allows for standardized response type
|
||||||
|
return (Result)organizationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed with the deletion if the organization is found
|
||||||
|
var deleteResult = await _organizationDataProvider.DeleteByIdAsync(organizationId);
|
||||||
|
|
||||||
|
// Return the result of the delete operation directly
|
||||||
|
return deleteResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points to Note:**
|
||||||
|
|
||||||
|
1. **Handling Different Result Types:**
|
||||||
|
- The `ReadOrganization` method demonstrates handling a `Result<Organization?>` and transforming other types as needed using `WithNewValue<T>`. This ensures the method always returns the correct type.
|
||||||
|
|
||||||
|
2. **Casting from `Result<T>` to `Result`:**
|
||||||
|
- In `DeleteOrganizationAsync`, we cast `Result<Organization?>` to `Result` using `(Result)organizationResult`. This cast standardizes the result type, making it suitable for scenarios where only success or failure matters.
|
||||||
|
|
||||||
|
Ensure this service is registered in your dependency injection container:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IVaultPersistanceService, VaultPersistanceService>();
|
||||||
|
// Other service registrations...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Use the Service in the Controller
|
||||||
|
|
||||||
|
Inject the service into your controller and utilize `MaksIT.Results` to handle results efficiently:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using MaksIT.Results;
|
||||||
|
|
||||||
|
public class OrganizationController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IVaultPersistanceService _vaultPersistanceService;
|
||||||
|
|
||||||
|
public OrganizationController(IVaultPersistanceService vaultPersistanceService)
|
||||||
|
{
|
||||||
|
_vaultPersistanceService = vaultPersistanceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{organizationId}")]
|
||||||
|
public IActionResult GetOrganization(Guid organizationId)
|
||||||
|
{
|
||||||
|
var result = _vaultPersistanceService.ReadOrganization(organizationId);
|
||||||
|
|
||||||
|
// Convert the Result to IActionResult using ToActionResult()
|
||||||
|
return result.ToActionResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{organizationId}")]
|
||||||
|
public async Task<IActionResult> DeleteOrganization(Guid organizationId)
|
||||||
|
{
|
||||||
|
var result = await _vaultPersistanceService.DeleteOrganizationAsync(organizationId);
|
||||||
|
|
||||||
|
// Convert the Result to IActionResult using ToActionResult()
|
||||||
|
return result.ToActionResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional actions...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transforming Results
|
||||||
|
|
||||||
|
You can also transform the result within the controller or service to adjust the output type as needed:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public IActionResult TransformResultExample()
|
||||||
|
{
|
||||||
|
var result = _vaultPersistanceService.ReadOrganization(Guid.NewGuid());
|
||||||
|
|
||||||
|
// Transform the result to a different type if needed
|
||||||
|
var transformedResult = result.WithNewValue<string>(org => (org?.Name ?? "").ToTitle());
|
||||||
|
|
||||||
|
return transformedResult.ToActionResult();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Predefined Results for All Standard HTTP Status Codes
|
||||||
|
|
||||||
|
`MaksIT.Results` provides methods to easily create results for all standard HTTP status codes, simplifying the handling of responses:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
return Result.Ok<string?>("Success").ToActionResult(); // 200 OK
|
||||||
|
return Result.NotFound<string?>("Resource not found").ToActionResult(); // 404 Not Found
|
||||||
|
return Result.InternalServerError<string?>("An unexpected error occurred").ToActionResult(); // 500 Internal Server Error
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conclusion
|
||||||
|
|
||||||
|
`MaksIT.Results` is a powerful tool for simplifying the handling of operation results in ASP.NET Core applications. It provides a robust framework for standardized result handling, seamless conversion to `IActionResult`, and flexible result types to handle various scenarios. By adopting this library, developers can create more maintainable and readable code, ensuring consistent and clear HTTP responses.
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
Contributions to this project are welcome! Please fork the repository and submit a pull request with your changes. If you encounter any issues or have feature requests, feel free to open an issue on GitHub.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License. See the full license text below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### MIT License
|
||||||
|
|
||||||
|
```
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Maksym Sadovnychyy (MAKS-IT)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
For any questions or inquiries, please reach out via GitHub or [email](mailto:maksym.sadovnychyy@gmail.com).
|
||||||
25
src/MaksIT.Results.sln
Normal file
25
src/MaksIT.Results.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.9.34902.65
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaksIT.Results", "MaksIT.Results\MaksIT.Results.csproj", "{E947F5FC-8FD9-4F1E-AA5F-29FED95B5A2D}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{E947F5FC-8FD9-4F1E-AA5F-29FED95B5A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E947F5FC-8FD9-4F1E-AA5F-29FED95B5A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E947F5FC-8FD9-4F1E-AA5F-29FED95B5A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E947F5FC-8FD9-4F1E-AA5F-29FED95B5A2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {C3627A51-0642-40DB-96BC-07C627FF8ACC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@ -4,10 +4,24 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
<RootNamespace>MaksIT.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
|
|
||||||
|
<!-- NuGet package metadata -->
|
||||||
|
<PackageId>MaksIT.Results</PackageId>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<Authors>Maksym Sadovnychyy</Authors>
|
||||||
|
<Company>MAKS-IT</Company>
|
||||||
|
<Product>MaksIT.Results</Product>
|
||||||
|
<Description>Library for standardized result handling and seamless conversion to IActionResult in ASP.NET Core applications.</Description>
|
||||||
|
<PackageTags>aspnetcore;result;handling;api;dotnet</PackageTags>
|
||||||
|
<RepositoryUrl>https://github.com/MAKS-IT-COM/maksit-results</RepositoryUrl>
|
||||||
|
<License>MIT</License>
|
||||||
|
<RequireLicenseAcceptance>false</RequireLicenseAcceptance>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||||
|
<None Include="../../README.md" Pack="true" PackagePath="" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -14,6 +14,14 @@ namespace MaksIT.Results {
|
|||||||
StatusCode = statusCode;
|
StatusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the current Result{T} to a non-generic Result.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A non-generic Result object.</returns>
|
||||||
|
public Result ToResult() {
|
||||||
|
return new Result(IsSuccess, Messages, StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the current Result to an IActionResult.
|
/// Converts the current Result to an IActionResult.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -52,6 +60,8 @@ namespace MaksIT.Results {
|
|||||||
return new Result<U?>(newValueFunc(Value), IsSuccess, Messages, StatusCode);
|
return new Result<U?>(newValueFunc(Value), IsSuccess, Messages, StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the current Result<T> to an IActionResult.
|
/// Converts the current Result<T> to an IActionResult.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -61,10 +71,10 @@ namespace MaksIT.Results {
|
|||||||
if (Value is not null) {
|
if (Value is not null) {
|
||||||
return new ObjectResult(Value) { StatusCode = (int)StatusCode };
|
return new ObjectResult(Value) { StatusCode = (int)StatusCode };
|
||||||
}
|
}
|
||||||
return ToActionResult();
|
return base.ToActionResult();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return ToActionResult();
|
return base.ToActionResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/Release-NuGetPackage.bat
Normal file
7
src/Release-NuGetPackage.bat
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
REM Change directory to the location of the script
|
||||||
|
cd /d %~dp0
|
||||||
|
|
||||||
|
REM Invoke the PowerShell script (Release-NuGetPackage.ps1) in the same directory
|
||||||
|
powershell -ExecutionPolicy Bypass -File "%~dp0Release-NuGetPackage.ps1"
|
||||||
46
src/Release-NuGetPackage.ps1
Normal file
46
src/Release-NuGetPackage.ps1
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Retrieve the API key from the environment variable
|
||||||
|
$apiKey = $env:NUGET_MAKS_IT
|
||||||
|
if (-not $apiKey) {
|
||||||
|
Write-Host "Error: API key not found in environment variable NUGET_MAKS_IT."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# NuGet source
|
||||||
|
$nugetSource = "https://api.nuget.org/v3/index.json"
|
||||||
|
|
||||||
|
# Define paths
|
||||||
|
$solutionDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$projectDir = "$solutionDir\MaksIT.Results"
|
||||||
|
$outputDir = "$projectDir\bin\Release"
|
||||||
|
|
||||||
|
# Clean previous builds
|
||||||
|
Write-Host "Cleaning previous builds..."
|
||||||
|
dotnet clean $projectDir -c Release
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
Write-Host "Building the project..."
|
||||||
|
dotnet build $projectDir -c Release
|
||||||
|
|
||||||
|
# Pack the NuGet package
|
||||||
|
Write-Host "Packing the project..."
|
||||||
|
dotnet pack $projectDir -c Release --no-build
|
||||||
|
|
||||||
|
# Look for the .nupkg file
|
||||||
|
$packageFile = Get-ChildItem -Path $outputDir -Filter "*.nupkg" -Recurse | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||||
|
|
||||||
|
if ($packageFile) {
|
||||||
|
Write-Host "Package created successfully: $($packageFile.FullName)"
|
||||||
|
|
||||||
|
# Push the package to NuGet
|
||||||
|
Write-Host "Pushing the package to NuGet..."
|
||||||
|
dotnet nuget push $packageFile.FullName -k $apiKey -s $nugetSource --skip-duplicate
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Host "Package pushed successfully."
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to push the package."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "Package creation failed. No .nupkg file found."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
49
src/Release-NuGetPackage.sh
Normal file
49
src/Release-NuGetPackage.sh
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Retrieve the API key from the environment variable
|
||||||
|
apiKey=$NUGET_MAKS_IT
|
||||||
|
if [ -z "$apiKey" ]; then
|
||||||
|
echo "Error: API key not found in environment variable NUGET_MAKS_IT."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NuGet source
|
||||||
|
nugetSource="https://api.nuget.org/v3/index.json"
|
||||||
|
|
||||||
|
# Define paths
|
||||||
|
scriptDir=$(dirname "$0")
|
||||||
|
solutionDir=$(realpath "$scriptDir")
|
||||||
|
projectDir="$solutionDir/MaksIT.Results"
|
||||||
|
outputDir="$projectDir/bin/Release"
|
||||||
|
|
||||||
|
# Clean previous builds
|
||||||
|
echo "Cleaning previous builds..."
|
||||||
|
dotnet clean "$projectDir" -c Release
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
echo "Building the project..."
|
||||||
|
dotnet build "$projectDir" -c Release
|
||||||
|
|
||||||
|
# Pack the NuGet package
|
||||||
|
echo "Packing the project..."
|
||||||
|
dotnet pack "$projectDir" -c Release --no-build
|
||||||
|
|
||||||
|
# Look for the .nupkg file
|
||||||
|
packageFile=$(find "$outputDir" -name "*.nupkg" -print0 | xargs -0 ls -t | head -n 1)
|
||||||
|
|
||||||
|
if [ -n "$packageFile" ]; then
|
||||||
|
echo "Package created successfully: $packageFile"
|
||||||
|
|
||||||
|
# Push the package to NuGet
|
||||||
|
echo "Pushing the package to NuGet..."
|
||||||
|
dotnet nuget push "$packageFile" -k "$apiKey" -s "$nugetSource" --skip-duplicate
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Package pushed successfully."
|
||||||
|
else
|
||||||
|
echo "Failed to push the package."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Package creation failed. No .nupkg file found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue
Block a user