I'm working on migrating an existing ASP.NET MVC app to ASP.NET Core. The solution has several class libraries (providing data access, services, etc). Many of those class libraries make use of the static ConfigurationManager.AppSettings["..."] way of getting the config from the web.config file.
With the ASP.NET Core app, though, there is no web.config file and it appears ConfigurationManager can't read appsettings.json.
I really like the new configuration system in ASP.NET Core, and am making use of it within the web app.
But is there a "simple" way to migrate these class libraries without having to rewrite them to use the new configuration system? Any basic replacement for the static ConfigurationManager.AppSettings["..."] calls that'll read appsettings.json? (note: we'll eventually rewrite them, but we'd rather do this one piece at a time)
If you're using .NET Standard 2.0 you can add a reference to the System.Configuration.ConfigurationManager NuGet package to get access to appSettings.
You can add an app.Config file (not web.Config) to your ASP.NET Core project to store the appSettings. This will be copied to the output folder and renamed as AppName.dll.config during the project build.
Disclaimer: I didn't try this with a class library, but this worked in LinqPad:
void Main()
{
var config = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["test"] = "test",
["test2:test"] = "test2"
})
.Build();
foreach (var pair in config.AsEnumerable())
{
// Skips the (test2 = null) pair
if (pair.Value != null)
{
ConfigurationManager.AppSettings.Set(pair.Key, pair.Value);
}
}
ConfigurationManager.AppSettings["test"].Dump();
ConfigurationManager.AppSettings["test2:test"].Dump();
}
You could put something like this in your initialization code.
It sets all of the values available to the System.Configuration app setting collection.
Related
I have a Blazor Server Project based on ASP.NET Core 5. I want to host my own openid-configuration discovery file. Since this file is served while running the OIDC workflow I want to verify what is the correct way to host this file. So far I have tried the following and only option 2 works.
using wwwroot/.well-known
This involves hosting the openid-configuration file statically in the wwwroot folder of my blazor server project.
After this if I run he project and try to access the file using localhost:44382/.well-known/openid-configuration, the file is not served.
Using Controllers
For this I just added a simple controller to my blazor project and specified .well-known/openid-configuration as a route for my anonymous controller HTTPGET action.
public class OidcConfigurationController : Controller
{
[HttpGet(".well-known/openid-configuration")]
public JsonResult OpenIdConfiguration()
{
return Json(new Storage.Storables.Security.OIDC.Configuration());
}
}
Now if I run the project with Option 2 and try to reach the localhost:44382/.well-known/openid-configuration the configuration JSON is served correctly.
Is option 2 the correct way to serve the OpenId-Configuration using ASP.NET Core and Blazor server project ? Will it cause any issues if I publish the server (for e.g. to Azure)
The reason why your first method is not working is that you don't serve a static file in a way the static file extensions assume you do. You missing a file ending, otherwise, the request isn't recognized as a file.
That said, you can write your own middleware. Give the file a proper ending like .json. If the resources /.well-known/openid-configuration/ is requested, you change the requested path to /.well-known/openid-configuration.json and let the static file extension handle the rest.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.Use(async (context, next) =>
{
if (context.Request.Path == "/.well-known/openid-configuration")
{
context.Request.Path = "/.well-known/openid-configuration.json";
}
await next();
});
app.UseStaticFiles();
...
}
For more information about writing a middleware have a look at the documentation https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write
However, you ran into the problem - I guess - because mostly this document is generated on the fly based on the configuration of your open id connect server like IdentityServer. So, maybe there is away around the static file?
I have .net core standard class library which is essentially a DAL with several class methods that return collections and objects from a database. The connection string is in the appsettings.json file of the ASP.net 2 core web app. I also want to access this class library from a console app project where the configuration file with the connection string will be present in that console app project.
This was simple in .net prior to .net core. The DAL class library would just access the web.config from a web project and an app.config from a console application as it the library is referenced in both the web app and console apps. But it doesn't seem like this is at all possible.
I'm looking for the simple solution in .net core to get a connection string from web app or console app as the case may be.
Where you're probably going wrong is that you want to access configuration from your class library, but then you want to leak details specifically about the caller (That it will have a web.config).
But what if you decide in your Web Application you want to use Azure Key Vault or another secrets mechanism? Does your class library need to then change it's entire implementation to use Key Vault? And then does that mean your console application also has no option but to use Key Vault too?
So the solution is to use dependency inversion. Put simply, let's say I have code like the following :
interface IMyRepositoryConfiguration
{
string ConnectionString {get;}
}
class MyRepositoryConfiguration : IMyRepositoryConfiguration
{
public string ConnectionString {get;set;}
}
class MyRepository
{
private readonly IMyRepositoryConfiguration _myRepositoryConfiguration;
public MyRepository(IMyRepositoryConfiguration myRepositoryConfiguration)
{
_myRepositoryConfiguration = myRepositoryConfiguration;
}
}
Now in my startup.cs I can do something like :
services.AddSingleton<IMyRepositoryConfiguration>(new MyRepositoryConfiguration {//Set connection string from app settings etc});
And now my class library doesn't need to know exactly how those configuration strings are stored or how they are fetched. Just that if I request an instance of IMyRepositoryConfiguration, that it will have the value in there.
Alternatively of course, you can use the Options class too, but personally I prefer POCOs. More info here : https://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/
It is very much possible to access "connection strings" or other configuration data easily in .Net core without much additional effort.
Just that the configuration system has evolved (into something much better) & we have to make allowances for this as well (& follow recommended practices).
In your case as you are accessing the connection string value in a standard library (intended to be reused), you should not make assumptions as how the configuration values will be "fed" to your class. What this means is you should not write code to read a connection string directly from a config file - instead rely on the dependency injection mechanism to provide you with the required configuration - regardless of how it has been made available to your app.
One way to do this is to "require" an IConfiguration object to be injected into your class constructor & then use the GetValue method to retrieve the value for the appropriate key, like so:
public class IndexModel : PageModel
{
public IndexModel(IConfiguration config)
{
_config = config;
}
public int NumberConfig { get; private set; }
public void OnGet()
{
NumberConfig = _config.GetValue<int>("NumberKey", 99);
}
}
In .net core, before the app is configured and started, a "host" is configured and launched. The host is responsible for app startup and lifetime management. Both the app and the host are configured using various "configuration providers". Host configuration key-value pairs become part of the app's global configuration.
Configuration sources are read in the order that their configuration providers are specified at startup.
.Net core supports various "providers". Read this article for complete information on this topic.
I see that the preferred way to use settings is to use Options pattern, and inject IOptions<T> object in class where I want to use settings.
Is there any other solution how to make this work in Business/Domain layer where I don't want to reference ASP.NET Core specific DLL like the one with IOptions<T> infrastructure?
You can use IConfiguration too. This technology is evolving fast, and the best practices are constantly changing. Take for example the docs on Configuration for 2.0, 2.1, 2.2 and 3.0
As of today, you could sensibly build ASP.NET Core apps in any of these versions.
Hitting the middle ground, say 2.1, look at the configuration docs and take some time to understand the many different ways of using this.
In 2.1, you can use appSettings.json to control settings for different deployments and different layers.
The default scaffolding adds CreateWebHostBuilder:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
Under the covers this calls calls AddJsonFile twice, once for appsettings.json and again for appsettings.{Environment}.json.
Add an appsettings.Production.json file to you project, and you'll get the benefits.
Then the respective appSettings file will be used based on an ASPNETCORE_ENVIRONMENT value that can be added to project properties (or Azure Web App | Application Settings) as needed. If not supplied it will default to Production
To read Configuration in in .Net Core:
//Sample appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"UserId": "sa",
"UserPassword": "123",
"ServerName": "abc"``
}
Step 2 :
Download NuGet packages
-Microsoft.Extensions.Configuration,Microsoft.Extensions.Configuration.FileExtensions
,Microsoft.Extensions.Configuration.Json
Add Class(name class whatever you want)
static class AppSettings
{
public static IConfiguration Settings { get; }
static AppSettings()
{
Settings = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
}
}
In Business, logic read as:
string strUserID= AppSettings.Settings["DbUserId"].ToString()
#CsharpBeginner, I believe I share your concern.
Our domain/use case layer should not know about the way configuration is injected. Therefore, I believe we should not depend on framework solutions as IOptions.
I guess the only ways to solve this are:
to inject the configuration class itself (T in your case) without using IOptions or
to use some sort of custom IOptions interface together with a custom implementation (outside of domain) which in turn uses Microsoft’s IOptions to pass on the configuration class.
I have 2 projects in my solution. First one is simple mvc project and the other one is web api. There was no pre-written code in web api. I put all logics myself. Now I want to add asp.net identity in the web api project. How can I do that?
Thanks.
In your web api project, you can do this:
1. Create a DbContext class that looks like this:
public class DataContext : IdentityDbContext<IdentityUser>
{
public DataContext() : base("ConnectionStringLocal") { }
}
Add a connection string in your Web.config file
In Package manager console, do Enable-Migrations, Add-Migration IdentityUpdate, Update-Database. This will create a database that has asp.net identity built in.
Please let me know if you have additional questions.
I have a Sharepoint 2010 webpart that calls a WCF service.
I've created a service proxy and manually coded the endpoint, see below.
In a conventional WCF client I'd use the config files for the configuration and use transforms when I was buiding for deployment to different environments.
How would I achieve the same through a Sharepoint webpart? I want to put the configuration somewhere that it can be changed for different build configurations.
ie. For a local deployment during testing, then a test server, production. We're trying to automate this as much as possible.
Thanks,
Tim
UPDATE:
I'm aware that you need to put config data in the web.config file in sharepoint. I'm looking for a way to put these config settings into source control and have them automatically populate / deploy for different builds and environments.
namespace CombinedPortal.WcfClient {
public class FrameworkServiceProxy : IFrameworkService
{
private IFrameworkService _proxy;
public FrameworkServiceProxy()
{
var endpoint = new EndpointAddress("http://server:1234/FrameworkService.svc");
var binding = new WSHttpBinding(SecurityMode.None);
_proxy = new ChannelFactory<IFrameworkService>(binding, endpoint).CreateChannel();
}
public Framework GetCurrentFramework(double uniqueLearnerNumber)
{
var fw = _proxy.GetCurrentFramework(uniqueLearnerNumber);
return fw;
}
} }
Your code is C# code which executes on the server.
When then user presses a button on a web part there is a POST back to the Sharepoint web server, where the C# code executes.
It is therefore the web.config of your SharePoint site which is used.