How to use App Configuration for common resources - azure-app-configuration

This SO is close but my question is about how to share configuration in Azure App Configuration across multiple apps. I get how this helps configure the app itself (how it works) but looking for advice on how to share settings across apps. Esp since there is no cross referencing in App Configuration service.
example: I have 3 app services. They all make calls to the same internal REST api in another service.
In the app configuration, I typically have an appSettings.json or App Service Configuration setting like:
"MyRestApi":{
"Url":"https://myRestApi-Dev.com/api",
"api1ControllerName" : "Home",
}
or better still (more obvious to ops than buried appSettings.json):
MyRestApi__Url = "https://myRestApi-Dev.com/api"
MyRestApi__api1ControllerName = "Home"
So each app would have this alongside many other settings. In Devops, I use pipelines library with common and per-environment group variables. I detect the dev/test/prod environment and override the url setting then apply that configuration to each deployed app.
In App Confirguration, I am encouraged to use "App:Setting:Subsetting" so it looks like I would have
in code
....
options
.Connect(settings.GetConnectionString("AppConfig"))
// Load configuration values with no label
.Select(KeyFilter.Any, LabelFilter.Null)
// Override with any configuration values specific to current hosting env
.Select(KeyFilter.Any, hostingContext.HostingEnvironment.EnvironmentName)
services.Configure<MyRestApiSettings>(Configuration.GetSection("App1:myRestApi")); //in app 1
services.Configure<MyRestApiSettings>(Configuration.GetSection("App2:myRestApi")); // in app 2
services.Configure<MyRestApiSettings>(Configuration.GetSection("App3:myRestApi")); // in app 3
in App Configuration
app1:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Dev)
app1:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Test)
app1:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Prod)
app1:MyRestApi:api1ControllerName = "Home" (Label: null)
app2:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Dev)
app2:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Test)
app2:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Prod)
app2:MyRestApi:api1ControllerName = "Home" (Label: null)
app3:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Dev)
app3:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Test)
app3:MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Prod)
app3:MyRestApi:api1ControllerName = "Home" (Label: null)
It seems like there is a lot of scope for typos.
So is it better to have :
MyRestApi:Url = "https://myRestApi-Dev.com/api" (Label: Dev)
MyRestApi:Url = "https://myRestApi-Test.com/api" (Label: Test)
MyRestApi:Url = "https://myRestApi-Prod.com/api" (Label: Prod)
MyRestApi:api1ControllerName = "Home" (Label: null)
and then use IOptions in the app to load "MyRestApi" into a settings object for the rest API?
services.Configure<MyRestApiSettings>(Configuration.GetSection("myRestApi")); // in all apps.
I prefer this but am I aiming for trouble down the line?

#MarkD, your approach will work. I am adding an alternative solution here.
You can put the shared configuration in a separate namespace (prefix), for example,
Key
value
Default:MyRestApi:Url
...
App1:MyRestApi:Url
...
App2:MyRestApi:SomethingElse
...
Then you load everything with prefix Default first and override them with any app-specific settings, for example, here is my code for App1:
configBuilder.AddAzureAppConfiguration(options => {
options.Connect(configuration["connection_string"])
.Select("Default:*")
.Select("App1:*")
.TrimKeyPrefix("Default:")
.TrimKeyPrefix("App1:");
});
Note that I called TrimKeyPrefix to remove those prefixes. With this, the rest of my application doesn't need to worry about the prefix and it has only one value for each configuration setting.

Related

Migration to Minimal API - Test Settings Json not overriding Program

Thanks to this answer: Integration test and hosting ASP.NET Core 6.0 without Startup class
I have been able to perform integration tests with API.
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
});
});
HttpClient? client = app.CreateClient();
This has worked using the appsettings.json from the API project. Am now trying to use integrationtestsettings.json instead using:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(ProjectDirectoryLocator.GetProjectDirectory())
.AddJsonFile("integrationtestsettings.json")
.Build();
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
builder.ConfigureServices(services =>
{
});
});
_httpClient = app.CreateClient();
I have inspected the configuration variable and can see the properties loaded from my integrartiontestsettings.json file. However, the host is still running using the appsettings.json from the server project.
Previously, in .Net5, I was using WebHostBuilder and the settings were overridden by test settings.
WebHostBuilder webHostBuilder = new();
webHostBuilder.UseStartup<Startup>();
webHostBuilder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(_configuration));
But cannot get the test settings to apply using the WebApplicationFactory.
It seems the method has changed.
Changing:
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
To:
builder.UseConfiguraton(configuration);
has done the trick.
builder.ConfigureAppConfiguration, now it's configuring the app (after your WebApplicationBuilder.Build() is called) and your WebApplication is created.
You need to "inject" your configurations before the .Build() is done. This is why you need to call UseConfiguraton instead of ConfigureAppConfiguration.

Why is the Azure App Configuration feature flag not found?

Azure Functions app, runtime v3.
The application has a FunctionsStartup class that first enables Azure App Configuration in its ConfigureAppConfiguration method:
builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
{
options
.Connect(appConfigurationConnectionString)
.UseFeatureFlags();
});
And in its Configure method it enables feature management, and it adds the Azure App Configuration services (so we can refresh settings at runtime):
builder.Services
.AddAzureAppConfiguration()
.AddFeatureManagement()
.AddFeatureFilter<ContextualTargetingFilter>();
On the Azure Portal there is a feature flag, which is enabled, called CardExpirationNotice. The code uses IFeatureManagerSnapshot to check if the feature is enabled:
feature = nameof(Features.CardExpirationNotice);
var isEnabled = await _featureManagerSnapshot.IsEnabledAsync(feature);
isEnabled is false, and this log message is output:
The feature declaration for the feature 'CardExpirationNotice' was not found.
I tried configuring a flag locally in local.settings.json:
"FeatureManagement__CardExpirationNotice": true
Then isEnabled is true, so I can narrow the problem to Azure App Configuration, and exclude the feature management implementation.
As it turns out, when you add a feature flag in Azure App Configuration, you can set a label. But if you do that, then you need to specify that label in your code as well:
builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
{
options
.Connect(appConfigurationConnectionString)
.UseFeatureFlags(options => options.Label = "payments");
});

Azure Virtual Network subnet connection issues

I'm having is that I have one Vnet with 2x /27 subnets that have been delegated to WebApps.
webApp-1 -> subnet1
WebApp-2 -> subnet2.
I've terraformed the Vnet:
resource "azurerm_resource_group" "main-rg"{
name = "main-rg"
location = "westeurope"
}
resource "azurerm_virtual_network" "main-vnet" {
name = "main-vnet"
location = azurerm_resource_group.main-rg.location
resource_group_name = azurerm_resource_group.main-rg.name
address_space = ["172.25.44.0/22"]
subnet {
name = "test"
address_prefix = "172.25.44.64/27"
security_group = ""
}
}
resource "azurerm_subnet" "subnet1" {
name = "subnet1"
resource_group_name = azurerm_resource_group.main-rg.name
virtual_network_name = azurerm_virtual_network.main-vnet.name
address_prefixes = ["172.25.44.0/27"]
delegation {
name = "webapp1delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}
resource "azurerm_subnet" "subnet2" {
name = "subnet2"
resource_group_name = azurerm_resource_group.main-rg.name
virtual_network_name = azurerm_virtual_network.main-vnet.name
address_prefixes = ["172.25.44.32/27"]
delegation {
name = "webapp2delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
}
}
}
The problem I'm having is when I'm trying to connect the WebApps to their respective subnets.
FYI: I'm connecting the WebApps from the Azure Portal (old test resources, don't want to import them as they will be removed soon).
The first on (WebApp1 to Subnet1) works out fine.
When I then try to connect WebApp2 to Subnet2 it fails, but I am able to connect WebApp2 to Subnet1.
I also tried the other way around; I'm able to connect both apps to Subnet2 (but I first have to disconnect both apps from Subnet1).
I'm not seeing any error messages other than a little "Connection failed" popup in the Portal UI.
So I guess my question is: is it not possible to have 2x subnets with WebApp-delegations in one Vnet, or am I missing something?
And again, sorry if this is something blatantly obvious that I've overlooked.
In advance; thanks!
It's not possible to have two web apps in the same app service plan to use differently integrated subnets because all web apps in the same app service plan could share the VNet integration. However, you can use each integrated subnet for each app service plan. You could read the limitations:
The integration subnet can be used by only one App Service plan.
You can have only one regional VNet Integration per App Service plan.
Multiple apps in the same App Service plan can use the same VNet.
To avoid any issues with subnet capacity, a /26 subnet address mask with 64 addresses is the recommended size.

How can you use multiple directories for static files in an aspnet core app?

By default, the wwwroot directory can host static files. However, in some scenarios, it might be ideal to have two directories for static files. (For example, having webpack dump a build into one gitignored directory, and keeping some image files, favicon and such in a not-gitignored directory). Technically, this could be achieved by having two folders within the wwwroot, but it might organizationally preferable to have these folders at the root level. Is there a way to configure an aspnet core app to use two separate directories for static files?
Just register UseStaticFiles twice:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "static"))
});
Now files will be found from wwwroot and static folders.
Registering UseStaticFiles twice won't solve it for MapFallbackToFile
An alternative approach.
// Build the different providers you need
var webRootProvider =
new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider =
new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, #"Other"));
// Create the Composite Provider
var compositeProvider =
new CompositeFileProvider(webRootProvider, newPathProvider);
// Replace the default provider with the new one
app.Environment.WebRootFileProvider = compositeProvider;
https://wildermuth.com/2022/04/25/multiple-directories-for-static-files-in-aspnetcore/

Use of AuthConfig, BundleConfig, FilterConfig , RouteConfig and WebApiConfig in App_Start() folder in MVC

Can you please explain in detail, the use of App_Start() folder in MVC4?
I see that this folder is actually not available in previous versions of MVC.
There are 5 files in this folder.
AuthConfig
BundleConfig,
FilterConfig,
RouteConfig,
WebApiConfig.
App_Start is just another folder that groups together ASP.NET MVC configuration, which in previous versions of ASP.NET MVC was done in Global.asax.
ASP.NET MVC introduces more and more configuration elements, and this folder is ideal to place this configuration. For example, MVC 5's new auth. configuration, such as for third-party login providers, are also placed within this folder (in Startup.Auth.cs).
App_Start is not a ASP.NET special folder recognized by ASP.NET/IIS. You can rename the folder if you want. The name is just a convention, like App_GlobalResouces etc.
Update:
Below are some information and reference points for each file. The use of these files are pretty straightforward. I have included few online references that might help your to understand more.
AuthConfig — registers external authentication providers.
See ASP.NET MVC external authentication providers for more information.
BundleConfig — registers your CSS and JS so they can be bundled and minified. See also ASP.NET MVC: Guidance: Bundling and Minification.
WebApiConfig — only applicable if you are using Web API. It can be used to configure Web API-specific routes, any Web API settings and Web API services. See also configuring ASP.NET MVC Web API 2
FilterConfig — registered global filters. These filters are applied to all actions and controllers. See also ASP.NET MVC 3: Global action filters
RouteConfig — you already found information.
App_start folder has been introduced in Mvc4. It contains various configurations files like:
BundleConnfig.cs
FilterConfig.cs
RouteConfig.cs
WebApiConfig.cs
AuthConfig.cs
App_start is not a special folder in MVC nor the class files inside this, these are just normal class files with different application
configurations(filtering, bundling, routing etc.) and all these settings gets registered within Application_Start method of Global.asax.cs file.
BundleConfig.cs:
This is used to create and register bundles for CSS and JS files. for
eg. jQuery,jQueryUI,jQuery validation,Modernizr and Site CSS..
Bundling and minification are two techniques to improve request load time by
reducing the number of requests to the server and reducing the size of
requested assets (such as CSS and JavaScript.)
Microsoft provides assembly Microsoft.Web.Optimization for the same
for eg.
Lets create two Bundles. one for style(css) and another for script(javascript)
You can create bundle for css and javascripts respectively by calling
BundleCollection class Add() method within BundleConfig.cs file.
STEP 1:
Creating Style Bundle
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
"~/Content/mystyle.min.css"));
Creating Script Bundle
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery-1.7.1.min.js",
"~/Scripts/jquery.validate.min.js"));
STEP 2:
Above bundles are defined in BundleConfig class as:
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
//Adding StyleBundle to BundleCollection
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
"~/Content/mystyle.min.css"));
//Adding ScriptBundle to BundleCollection
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery-1.7.1.min.js",
"~/Scripts/jquery.validate.min.js"));
}
}
STEP 3:
Registering Bundle
All bundles are registered in the Application_Start event of Global.asax:
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Minification is a technique for removing unnecessary characters (like
white space, newline, tab) and comments from the JavaScript and CSS
files to reduce the size, in turn improve load time of a web page. for
eg. jquery-1.7.1.min.js is the minified js file for jquery-1.7.1,
mostly used for production environment, for non-prod you can better use non-
minified js to have better readability.
for eg.
A Jquery function in uncompressed js may look something like:
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
same above function in compressed or minified js will look like:
!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}
FilterConfig.cs:
This is used to create and register global MVC filter:
for eg.
Authentication filters (Executed First)
Authorization filters
Action filters
Result filters
Exception filters (Executed Last)
Note: As mentioned above Filters are executed in an order.
for eg. Authentication Filters introduced with MVC5:
public interface IAuthenticationFilter
{
void OnAuthentication(AuthenticationContext filterContext);
void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
}
You can create your CustomAuthentication filter attribute by implementing
IAuthenticationFilter as shown below-
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
//logic goes here
}
Runs after the OnAuthentication method
public void OnAuthenticationChallenge(AuthenticationChallengeContext
filterContext)
{
{
//logic goes here
}
}
Configuring Filters
You can configure your own custom filter into your application at
following three levels:
Global level
By registering your filter into Application_Start event of
Global.asax.cs file:
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
Controller level
By putting your filter on the top of the controller name:
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
// Logic goes here
}
Action level
By putting your filter on the top of the action name:
public class UserController : Controller
{
[Authorize(Users="User1,User2")]
public ActionResult LinkLogin(string provider)
{
// Logic goes here
return View();
}
}
RouteConfig.cs:
This is used to register various route patterns for your Asp.Net MVC
application. Routing plays an important role in an ASP.NET MVC Application
execution flow, it maps request URL to a specific controller action using a
Routing Table. We can define Routing Rules for the engine, so that it can map > incoming URLs to appropriate controller. Routing Engine uses routing rules
that are defined in Global.asax file in order to parse the URL and find out
the path of corresponding controller. We can find the following piece of code > in Application_Start() method of Global.asax file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
We can find RouteConfig.cs file under App_Start folder. If we follow
this method in RouteConfig class, we will find one default configured
route as follows. Line 3 to 7 is configuring one default route.
public static void RegisterRoutes(RouteCollection routes)
{
1. routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);
2.
3. routes.MapRoute(
4. name: “Default”,
5. url: “{controller}/{action}/{id}”,
6. defaults: new { controller = “Home”, action = “Index”, id = UrlParameter.Optional }
7. );
}
Line 4 : Name for the route. Line 5 : represent URL : Controller,
action followed by id (if any). Line 6 : default controller will be
Home, default action will be Index and Id is optional.
WebApiConfig.cs:
This is used to register various WEB API routes like as Asp.Net MVC, as well as set any addtional WEB API configurations settings.
AuthConfig.cs:
Used to register external authentication providers
for eg. if you want to enable users to log in with credentials from an external provider, such as Facebook, Twitter, Microsoft, or Google, and then integrate some of the functionality from those providers into your web application.
App_start folder has been introduced in Mvc4. It contains various configurations files like as :
BundleConnfig.cs,
FilterConfig.cs,
RouteConfig.cs,
WebApiConfig.cs
for you application.All those settings are registered within App_Start method of Global.asax.cs file
BundleConfig.cs:
This is used to create and register bundles for CS and JS files.By default various bundles are added in this file including jQuery,jQueryUI,jQuery validation,Modernizer and Site Css..
FilterConfig.cs-
This is used to create and register global MVC filter error filter,action filter etc.By default it contains HandleErrorAttribute filter.
RouteConfig.cs-
This is used to register various route patterns for your Asp.Net MVC application. By default,one route is registered here named as Default Route.
WebApiConfig.cs-
This is used to register various WEB API routes like as Asp.Net MVC,as well as set any additional WEB API configurations settings.
In the previous versions of MVC, we just have RegisterRoutes() method in global.asax file to configure the routing. MVC 4 has built in templates to develop mobile web applications, web apis(restful http services).so to configure the routings for all those template driven development ,we will be using the
AuthConfig.cs(Authorization),BundleConfig.cs(web potimization),,FilterConfig.cs,RouteConfig.cs,WebApiConfig.cs(WEB API) files and they will be mainteained in App_start folder.
Lets have a look at each those config.cs files.
AuthConfig.cs - settings in this file allows you to login to ASP.NET MVC site using third party client credentials like fb account,google account,yahoo account etc..or you can register also.
BundleConfig.cs: settings in this file allows to improve the performance of an applications using bundling...
WebApiConfig: sets the routing settings for WEB API (Note:No action needed in url)
AuthConfi g.cs: Used to confi gure security settings, including sites for OAuth login.
BundleConfi g.cs: Used to register bundles used by the bundling and minifi cation
system. Several bundles are added by default, including jQuery, jQueryUI, jQuery
validation, Modernizr, and default CSS references.
FilterConfi g.cs: Unsurprisingly, this is used to register global MVC fi lters. The only
fi lter registered by default is the HandleErrorAttribute, but this is a great place to put
other fi lter registrations.
RouteConfi g.cs: Holds the granddaddy of the MVC confi g statements, Route confi
guration.
WebApiConfi g.cs: Used to register Web API routes, as well as set any additional Web
API confi guration settings.
All those settings are registered within the App_Start method of Global.asax.cs file
BundleConfig.cs:
This is used to create and register bundles for CS and JS files that we have in the template.
FilterConfig.cs-
This is used to create and register global MVC filter error filter
RouteConfig.cs-
This is used to register various route patterns for your Asp.Net MVC application.
WebApiConfig.cs-
This is used to register various WEB API routes like want login with credentials from an external provider, such as Facebook, Twitter, Microsoft, or Google,