-
Add packages
dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore --version 2.0.0-preview-009470001-12
dotnet add package Microsoft.FeatureManagement.AspNetCore --version 1.0.0-preview-009000001-1251
-
Add StartUp.cs
public void ConfigureServices(IServiceCollection services)
{
ConfigureTypedClients(services);
services.AddFeatureManagement();
services.AddControllersWithViews();
}
- Add tag helper StarwarsWeb/Views/_ViewImports.cshtml
@addTagHelper *, Microsoft.FeatureManagement.AspNetCore
- Add toggle /StarwarsWeb/Views/Shared/_Layout.cshtml
<feature name="ShowPlanetsOfStarwars">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Starwars" asp-action="Planets">Planets</a>
</li>
</feature>
- Show the that the feature toggle hides the implementation of the menu item
- Build out the example ISwapiClient.cs
[Get("/api/planets")]
Task<StarwarsPlanets> GetPlanets();
- Update StarwarsController.cs
public class StarwarsController : Controller
{
private readonly IFeatureManager featureManager;
public StarwarsController(ISwapiClient proxy, IFeatureManager featureManager)
{
this.proxy = proxy;
this.featureManager = featureManager;
}
//optional if you want to lock on the controller
//[FeatureGate(FeatureToggles.ShowPlanetsOfStarwars)]
public async Task<IActionResult> Planets()
{
return View(await proxy.GetPlanets().ConfigureAwait(true));
}
-
Add other files
- StarwarsWeb/FeatureToggles.cs
- StarwarsWeb/Models/Planet.cs
- StarwarsWeb/Models/StarwarsPlanets.cs
- StarwarsWeb/Views/Starwars/Planets.cshtml
-
Add application configuration
},
"FeatureManagement": {
"ShowPlanetsOfStarwars": false
}
- Refactor HardStarshipProvider ==> IStarshipClient
using Refit;
using System.Threading.Tasks;
namespace StarwarsWeb.HardProviders
{
public interface IStarshipClient
{
Task<Starships> GetStarships();
}
}
- Add dependency to the startup.cs
services.AddTransient<IStarshipClient,HardStarshipProvider>();
- rework StarshipController.cs
private readonly ISwapiClient proxy;
private readonly IStarshipClient starshipProxy;
public StarwarsController(ISwapiClient proxy, IStarshipClient starshipProxy)
{
this.proxy = proxy;
this.starshipProxy = starshipProxy;
}
-
Demo old site works
-
Introduce new toggle
- appsettings.json
"FeatureManagement": {
"UseImprovedStarshipProvider": false
}
- FeatureToggle.cs
public enum FeatureToggles
{
ShowPlanetsOfStarwars,
UseImprovedStarshipProvider
}
- StarwarsController.cs
public StarwarsController(ISwapiClient proxy, Func<bool, IStarshipClient> starshipProxy, IFeatureManager featureManager)
{
this.proxy = proxy;
this.starshipProxy = starshipProxy(featureManager.IsEnabled(nameof(FeatureToggles.UseImprovedStarshipProvider)));
}
- implement new provider
public interface IStarshipClient
{
[Get("/api/starships")]
Task<Starships> GetStarships();
}
services.AddHttpClient("StarshipAPIs", options =>
{
options.BaseAddress = new Uri(Configuration["SwapiApiOptions:BaseUrl"]);
options.Timeout = TimeSpan.FromMilliseconds(15000);
options.DefaultRequestHeaders.Add("ClientFactory", "Check");
})
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromMilliseconds(15000)))
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTypedClient(client => RestService.For<IStarshipClient>(client));
services.AddTransient<HardStarshipProvider>();
services.AddTransient<Func<bool, IStarshipClient>>(serviceProvider => UseImprovedStarshipProvider =>
{
switch (UseImprovedStarshipProvider)
{
case true:
return serviceProvider.GetService<IStarshipClient>();
default:
return serviceProvider.GetService<HardStarshipProvider>();
}
});
-show result
- Change the feature toggle to a percentage toggle appsettings.json
"UseImprovedStarshipProvider": {
"EnabledFor": [
{
"Name": "Microsoft.Percentage",
"Parameters": {
"Value": 50
}
}
]
}
- enable the use of percentage in the setup.cs
public void ConfigureServices(IServiceCollection services)
{
ConfigureTypedClients(services);
services.AddFeatureManagement().AddFeatureFilter<PercentageFilter>();
services.AddControllersWithViews();
}
- Validate the working
- Next add the cloud integration
- Configure connection in appconfig
"ConnectionStrings": {
"AppConfig": ""
},
- configure startup.cs
app.UseRouting();
//Add azure app configuraiton
app.UseAzureAppConfiguration();
app.UseAuthorization();
- Configure the program.cs
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
//[....]
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
{
var aspnetcorEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (string.IsNullOrEmpty(aspnetcorEnvironment) || !aspnetcorEnvironment.Equals("Development", StringComparison.OrdinalIgnoreCase))
{
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
options.Connect(settings["ConnectionStrings:AppConfig"])
.UseFeatureFlags();
});
}
});
webBuilder.UseStartup<Startup>();
});
- push to AzDo -Create pipeline and ADD VARIABLE AzureAppConfigurationUrl + secret read only endpoint