Skip to content

Commit

Permalink
First commit !
Browse files Browse the repository at this point in the history
  • Loading branch information
aimenux committed Dec 16, 2023
1 parent 4765be8 commit 1b5afc9
Show file tree
Hide file tree
Showing 36 changed files with 1,146 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net

name: .NET

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,4 @@ FodyWeavers.xsd

# JetBrains Rider
*.sln.iml
/.idea/*
56 changes: 56 additions & 0 deletions ModelBindingDemo.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D733C4D0-DA18-41A2-945E-E1907BD0F471}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example01", "src\Example01\Example01.csproj", "{362D3A36-4B85-469E-9964-7C31E9F22757}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3D88ADFF-B52F-4B4D-8FA9-EFEEB9F69BAE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example01.Tests", "test\Example01.Tests\Example01.Tests.csproj", "{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example02", "src\Example02\Example02.csproj", "{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example02.Tests", "test\Example02.Tests\Example02.Tests.csproj", "{97814823-3068-4C3E-8CB2-B0FC34E05FA2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFiles", "SolutionFiles", "{11AA728D-845B-46B3-8F8A-1D12664ED8E3}"
ProjectSection(SolutionItems) = preProject
.github\workflows\ci.yml = .github\workflows\ci.yml
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{362D3A36-4B85-469E-9964-7C31E9F22757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{362D3A36-4B85-469E-9964-7C31E9F22757}.Debug|Any CPU.Build.0 = Debug|Any CPU
{362D3A36-4B85-469E-9964-7C31E9F22757}.Release|Any CPU.ActiveCfg = Release|Any CPU
{362D3A36-4B85-469E-9964-7C31E9F22757}.Release|Any CPU.Build.0 = Release|Any CPU
{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21}.Release|Any CPU.Build.0 = Release|Any CPU
{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB}.Release|Any CPU.Build.0 = Release|Any CPU
{97814823-3068-4C3E-8CB2-B0FC34E05FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97814823-3068-4C3E-8CB2-B0FC34E05FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97814823-3068-4C3E-8CB2-B0FC34E05FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97814823-3068-4C3E-8CB2-B0FC34E05FA2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{362D3A36-4B85-469E-9964-7C31E9F22757} = {D733C4D0-DA18-41A2-945E-E1907BD0F471}
{64A216A5-9BB6-48C5-A2B2-9EF4EFBEDC21} = {3D88ADFF-B52F-4B4D-8FA9-EFEEB9F69BAE}
{E6A941D9-BC3E-454C-B4A5-AB8DEE5F69BB} = {D733C4D0-DA18-41A2-945E-E1907BD0F471}
{97814823-3068-4C3E-8CB2-B0FC34E05FA2} = {3D88ADFF-B52F-4B4D-8FA9-EFEEB9F69BAE}
EndGlobalSection
EndGlobal
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
[![.NET](https://github.com/aimenux/ModelBindingDemo/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/aimenux/ModelBindingDemo/actions/workflows/ci.yml)

# ModelBindingDemo
```
Using various model binding ways
```

In this repo, i m using various model binding ways in web api projects
>
> :one: `Example01` use [model binding with controller api](https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding)
>
> :two: `Example02` use [model binding with minimal api](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/parameter-binding)
>
**`Tools`** : net 7.0, web api, integration-testing, fluent-assertions
7 changes: 7 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "7.0.400",
"allowPrerelease": false,
"rollForward": "latestFeature"
}
}
39 changes: 39 additions & 0 deletions src/Example01/Binders/BooleanModelBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace Example01.Binders;

public class BooleanModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
ArgumentNullException.ThrowIfNull(bindingContext);

var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}

var value = valueProviderResult.FirstValue;
var (isTrue, isFalse) = (IsTrueValue(value), IsFalseValue(value));
if (isTrue || isFalse)
{
bindingContext.Result = ModelBindingResult.Success(isTrue);
}

return Task.CompletedTask;
}

private static bool IsTrueValue(string value) => IgnoreCaseEquals(value, "True")
|| IgnoreCaseEquals(value, "Yes")
|| IgnoreCaseEquals(value, "Oui")
|| IgnoreCaseEquals(value, "1");

private static bool IsFalseValue(string value) => IgnoreCaseEquals(value, "False")
|| IgnoreCaseEquals(value, "No")
|| IgnoreCaseEquals(value, "Non")
|| IgnoreCaseEquals(value, "0");

private static bool IgnoreCaseEquals(string left, string right) => string.Equals(left, right, StringComparison.OrdinalIgnoreCase);
}
100 changes: 100 additions & 0 deletions src/Example01/Controllers/ApiController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Example01.Binders;
using Example01.Payloads;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Internal;

namespace Example01.Controllers;

[ApiController]
[Route("[controller]")]
public class ApiController : ControllerBase
{
[HttpGet("{id:int}")]
public IActionResult Get([FromRoute] int id)
{
var response = new
{
Id = id,
Source = "FromRoute"
};
return Ok(response);
}

[HttpGet("trace")]
public IActionResult Get([FromHeader(Name = "X-Trace-Id")] string traceId)
{
var response = new
{
TraceId = traceId,
Source = "FromHeader"
};
return Ok(response);
}

[HttpGet("search")]
public IActionResult Search([FromQuery] string keyword)
{
var response = new
{
KeyWord = keyword,
Source = "FromQuery"
};
return Ok(response);
}

[HttpGet("list")]
public IActionResult List([FromQuery] ApiQuery query)
{
var response = new
{
ApiQuery = query,
Source = "FromQuery"
};
return Ok(response);
}

[HttpGet("date")]
public IActionResult Date([FromServices] ISystemClock systemClock)
{
var response = new
{
UtcNow = systemClock.UtcNow,
Source = "FromServices"
};
return Ok(response);
}

[HttpGet("custom")]
public IActionResult Custom([FromQuery] [ModelBinder(BinderType = typeof(BooleanModelBinder))] bool answer)
{
var response = new
{
Answer = answer,
Source = "CustomBinding"
};
return Ok(response);
}

[HttpPost]
public IActionResult Post([FromBody] ApiRequest request)
{
var response = new
{
ApiResponse = new ApiResponse($"{request.FirstName} {request.LastName}"),
Source = "FromBody"
};
return Ok(response);
}

[HttpPut("{id:int}")]
public IActionResult Put([FromRoute] int id, [FromBody] ApiRequest request)
{
return request.Id == id ? NoContent() : BadRequest();
}

[HttpDelete("{id:int}")]
public IActionResult Delete(int id)
{
return id > 0 ? NoContent() : BadRequest();
}
}
17 changes: 17 additions & 0 deletions src/Example01/Example01.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Example01.Tests" />
</ItemGroup>

</Project>
3 changes: 3 additions & 0 deletions src/Example01/Payloads/ApiQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Example01.Payloads;

public record ApiQuery(int Take, int Skip);
3 changes: 3 additions & 0 deletions src/Example01/Payloads/ApiRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Example01.Payloads;

public record ApiRequest(int Id, string FirstName, string LastName);
3 changes: 3 additions & 0 deletions src/Example01/Payloads/ApiResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Example01.Payloads;

public record ApiResponse(string FullName);
24 changes: 24 additions & 0 deletions src/Example01/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Microsoft.Extensions.Internal;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<ISystemClock, SystemClock>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
41 changes: 41 additions & 0 deletions src/Example01/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:14242",
"sslPort": 44303
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5010",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:5020;http://localhost:5010",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
8 changes: 8 additions & 0 deletions src/Example01/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions src/Example01/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Loading

0 comments on commit 1b5afc9

Please sign in to comment.