Skip to content

Commit d535f87

Browse files
committed
Added Web API example
1 parent 72ce306 commit d535f87

11 files changed

+233
-1
lines changed

FeatureManagement.Database.sln

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FeatureManagement.Database.
2727
EndProject
2828
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9C0234A4-16D6-4A68-8F89-9B083FA747C9}"
2929
EndProject
30-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "samples\ConsoleApp\ConsoleApp.csproj", "{AA62B656-2A7B-4133-9280-8DF51CCF4105}"
30+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "samples\ConsoleApp\ConsoleApp.csproj", "{AA62B656-2A7B-4133-9280-8DF51CCF4105}"
31+
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApiApp", "samples\WebApiApp\WebApiApp.csproj", "{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB}"
3133
EndProject
3234
Global
3335
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3436
Debug|Any CPU = Debug|Any CPU
3537
Release|Any CPU = Release|Any CPU
3638
EndGlobalSection
3739
GlobalSection(ProjectConfigurationPlatforms) = postSolution
40+
{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41+
{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
42+
{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
43+
{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB}.Release|Any CPU.Build.0 = Release|Any CPU
3844
{AA62B656-2A7B-4133-9280-8DF51CCF4105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3945
{AA62B656-2A7B-4133-9280-8DF51CCF4105}.Debug|Any CPU.Build.0 = Debug|Any CPU
4046
{AA62B656-2A7B-4133-9280-8DF51CCF4105}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -52,6 +58,7 @@ Global
5258
HideSolutionNode = FALSE
5359
EndGlobalSection
5460
GlobalSection(NestedProjects) = preSolution
61+
{728B43AD-5292-4BD1-B3CD-4C576E0FD0AB} = {9C0234A4-16D6-4A68-8F89-9B083FA747C9}
5562
{AA62B656-2A7B-4133-9280-8DF51CCF4105} = {9C0234A4-16D6-4A68-8F89-9B083FA747C9}
5663
{DB4DF079-5C58-4A45-A078-C26EE566DE55} = {80D694E3-6FD9-4249-A5E9-B6623BD59E28}
5764
{9AE83D01-5878-4213-AE34-8F5377A2DC88} = {43BBEC90-C0D3-4FBD-BD47-ACCDE5FA7EA8}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) Matteo Ciapparelli.
2+
// Licensed under the MIT license.
3+
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.FeatureManagement.Mvc;
6+
7+
namespace WebApiApp.Controllers;
8+
9+
[ApiController]
10+
[Route("[controller]")]
11+
public class WeatherForecastController : ControllerBase
12+
{
13+
private static readonly string[] _summaries =
14+
[
15+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
16+
];
17+
18+
private readonly ILogger<WeatherForecastController> _logger;
19+
20+
public WeatherForecastController(ILogger<WeatherForecastController> logger)
21+
{
22+
_logger = logger;
23+
}
24+
25+
[HttpGet(Name = "GetWeatherForecast")]
26+
[FeatureGate(Features.Weather)]
27+
public IEnumerable<WeatherForecast> Get()
28+
{
29+
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
30+
{
31+
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
32+
TemperatureC = Random.Shared.Next(-20, 55),
33+
Summary = _summaries[Random.Shared.Next(_summaries.Length)]
34+
})
35+
.ToArray();
36+
}
37+
}

samples/WebApiApp/FeatureStore.cs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Matteo Ciapparelli.
2+
// Licensed under the MIT license.
3+
4+
using FeatureManagement.Database;
5+
using System.Diagnostics.CodeAnalysis;
6+
using static WebApiApp.Features;
7+
8+
namespace WebApiApp;
9+
10+
public class FeatureStore : IFeatureStore
11+
{
12+
private readonly IReadOnlyCollection<Feature> _features;
13+
14+
public FeatureStore()
15+
{
16+
_features =
17+
[
18+
new Feature {
19+
Name = Weather,
20+
Settings = [new FeatureSettings { FilterType = FeatureFilterType.Percentage, Parameters = """{ "Value": 50 }""" }]
21+
}
22+
];
23+
}
24+
25+
public Task<Feature?> GetFeatureAsync([NotNull] string featureName)
26+
{
27+
return Task.FromResult(_features.SingleOrDefault(x => x.Name == featureName));
28+
}
29+
30+
public Task<IReadOnlyCollection<Feature>> GetFeaturesAsync()
31+
{
32+
return Task.FromResult(_features);
33+
}
34+
}

samples/WebApiApp/Features.cs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) Matteo Ciapparelli.
2+
// Licensed under the MIT license.
3+
4+
namespace WebApiApp;
5+
6+
internal static class Features
7+
{
8+
public const string Weather = nameof(Weather);
9+
}

samples/WebApiApp/Program.cs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Matteo Ciapparelli.
2+
// Licensed under the MIT license.
3+
4+
using FeatureManagement.Database;
5+
using Microsoft.Extensions.Options;
6+
using WebApiApp;
7+
8+
var builder = WebApplication.CreateBuilder(args);
9+
10+
// Add services to the container.
11+
builder.Services.AddControllers();
12+
builder.Services.AddEndpointsApiExplorer();
13+
builder.Services.AddSwaggerGen();
14+
15+
// Set up feature management
16+
builder.Services.AddDatabaseFeatureManagement<FeatureStore>(useCache: false); //set 'true' to use cache (with default values)
17+
18+
//builder.Services.AddOptions<FeatureCacheOptions>()
19+
// .Bind(builder.Configuration.GetSection($"FeatureManagement:{FeatureCacheOptions.Name}"));
20+
21+
var app = builder.Build();
22+
23+
//var options = app.Services.GetRequiredService<IOptions<FeatureCacheOptions>>().Value;
24+
25+
// Configure the HTTP request pipeline.
26+
if (app.Environment.IsDevelopment())
27+
{
28+
app.UseSwagger();
29+
app.UseSwaggerUI();
30+
}
31+
32+
app.UseHttpsRedirection();
33+
34+
app.UseAuthorization();
35+
36+
app.MapControllers();
37+
38+
app.Run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "http://localhost:4185",
8+
"sslPort": 44339
9+
}
10+
},
11+
"profiles": {
12+
"http": {
13+
"commandName": "Project",
14+
"dotnetRunMessages": true,
15+
"launchBrowser": true,
16+
"launchUrl": "swagger",
17+
"applicationUrl": "http://localhost:5139",
18+
"environmentVariables": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
}
21+
},
22+
"https": {
23+
"commandName": "Project",
24+
"dotnetRunMessages": true,
25+
"launchBrowser": true,
26+
"launchUrl": "swagger",
27+
"applicationUrl": "https://localhost:7147;http://localhost:5139",
28+
"environmentVariables": {
29+
"ASPNETCORE_ENVIRONMENT": "Development"
30+
}
31+
},
32+
"IIS Express": {
33+
"commandName": "IISExpress",
34+
"launchBrowser": true,
35+
"launchUrl": "swagger",
36+
"environmentVariables": {
37+
"ASPNETCORE_ENVIRONMENT": "Development"
38+
}
39+
}
40+
}
41+
}

samples/WebApiApp/WeatherForecast.cs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Matteo Ciapparelli.
2+
// Licensed under the MIT license.
3+
4+
namespace WebApiApp;
5+
6+
public class WeatherForecast
7+
{
8+
public DateOnly Date { get; set; }
9+
10+
public int TemperatureC { get; set; }
11+
12+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
13+
14+
public string? Summary { get; set; }
15+
}

samples/WebApiApp/WebApiApp.csproj

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="3.2.0" />
11+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\..\src\FeatureManagement.Database.Abstractions\FeatureManagement.Database.Abstractions.csproj" />
16+
</ItemGroup>
17+
18+
</Project>

samples/WebApiApp/WebApiApp.http

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@WebApiApp_HostAddress = http://localhost:5139
2+
3+
GET {{WebApiApp_HostAddress}}/weatherforecast/
4+
Accept: application/json
5+
6+
###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"FeatureManagement": {
9+
"FeatureCacheOptions": {
10+
"AbsoluteExpiration": null,
11+
"AbsoluteExpirationRelativeToNow": null,
12+
"SlidingExpiration": "00:00:30",
13+
"KeyNames": {
14+
"AllFeatures": "allFeatures"
15+
}
16+
}
17+
}
18+
}

samples/WebApiApp/appsettings.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*"
9+
}

0 commit comments

Comments
 (0)