In The Olden Days
In a web.config file, settings could be placed in an appSettings section like so:
<appSettings>
<add key="mysetting" value="123"/>
</appSettings>
Even though my web.config file was in my web project, any assemblies/libraries used in that project could access the settings using:
ConfigurationManager.AppSettings["mysetting"]
Today (and the problem)
I am starting to use .NET core, and just like before, I have assemblies/libraries that are not web projects in of themselves and need to access various configuration settings.
Microsoft's Configuration documentation (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) along with all of the other examples I can find, have the configuration class being consumed by a controller and don't provide any guidance on how to make it work with a class in another assembly/library that is not a controller.
For ONE example, if I have a custom attribute that I can decorate a class with and that custom attribute is defined in another library (not in a web project) and it needs to access a configuration setting, how do I do that today? I can't pass in anything to a constructor in such an instance either.
I'm going to assume you're talking about a ASPNET Core project as you specifically mention web.config.
Here's what you need to do.
IOptions<FooSettingsClass> is usually configured at application start which means that it's available at runtime with code that looks something like this.
// Adds services required for using options.
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("FooAppSettings"));
The easiest way is to have the framework inject it through the constructor. Typically you'll see it (as you mentioned) being injected in the controller like this:
class FooController : Controller {
public FooController(IOptions<FooSettingsClass> settings) { .
//..
}
}
If you need to access this configuration is say, a service, then you simply have a constructor, in a different assembly, which accepts those options. So:
public class SomeServiceInAnotherAssembly {
public SomeServiceInAnotherAssembly(IOptions<FooSettingsClass> settings) {
//..
}
}
This obviously means that your FooSettingsClass class needs to be outside of your ASPNET Core project (to avoid circular dependencies), but this is one way of propagating your configuration without writing any code, which is what I've seen other developers do. To me, writing code is a hoop jumping solution bound to have bugs.
Don't forget that your class (in this exampe SomeServiceInAnotherAssembly) needs to be registered at startup, i.e. services.AddScoped<SomeServiceInAnotherAssembly>();
The nice thing about this approach is that it makes your classes testable.
In 8-2017 Microsoft came out with System.Configuration.Manager for .NET CORE v4.4. Currently v4.5 and v4.6 preview.
Install this nuget package. Add directive to a code file
using System.Configuration;
Now, you can do your
var val = ConfigurationManager.AppSettings["mysetting"];
There is one trick for web sites though - you no longer use web.config for application settings and configuration sections. You use app.config as well as other types of projects. But if you deploy in ISS, you might need to use both. In web.config you supply strictly ISS-related entries. Your app-specific entries go to app.config
Related
I'm trying to create a Web API project and a client-side web project, where the web project can access the API via ajax. Currently my project looks like this:
I saw this answer on here: Setting app a separate Web API project and ASP.NET app, which explains how the project url can be set to localhost:[port]/api.
But for ASP.NET 5 projects, the properties only have 3 tabs (as opposed to the several found in ASP.NET 4 projects):
What I'm wondering is:
Do I have to set this option somewhere else? (i.e project.json)
How would this work when I publish? Ideally I'd want [websiteURL]/api to serve up my API, whereas that link explicitly put localhost:8080.
Is having these as two projects a good idea? I could easily put API and web in the same project, but I like the separation of client-side and server-side logic.
Any help would be appreciated!
First Point:
Generally speaking in ASP.NET 5, the routing defaults are very good and should work out of the box without much in the way of configuration. You can use configuration and/or attribute based routing in your application (with a detailed overview of both here), although my personal preference is for the attributed approach. Provided you have the following line in your Startup.cs file (which you should have in a new project):
app.UseMvc();
you should be able to route requests to your api controllers in the fashion required (i.e. "/api/...") simply by using [Route] attributes as below (example taken from a standard generated ASP.NET 5 Web API application)
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
The above example will route any GET request made to "/api/values".
While this approach can be used to handle requests made to your api, in order to deliver the files needed for your front end javascript application/single page app, you will need to enable static file serving. If you add the following to the Configure method in your Startup.cs class:
app.UseStaticFiles();
this will allow your application to serve those static files - by default, these are served from the ‘wwwroot’ folder, although this can be changed in the project.json file if required. The files needed for your front end app should then be added to this folder. A tutorial on serving static files can be found here.
Second Point:
In my experience this will not be an issue when you publish your website - provided your server is set up correctly, you will not need to include the port when making a request - navigating to [yourwebsitename]/api/... will suffice.
Third point:
In my opinion this entirely depends on how large the project is likely to grow, although preference and opinion will vary from developer to developer. Generally speaking, if the project will remain small in scope then keeping both in a single project is perfectly ok, as unnecessary complexity is reduced. However it is also very useful as you have pointed out, to maintain a separation of concerns between projects. So aside from the organisational advantage of your approach, the respective dependencies of the two projects are/will be kept separate also.
I'm working with Orchard CMS and it is better CMS for me. I want to understand how it does the logging and whether I can add my own logging or not. I saw that Orchard uses NullLogger class and it does no work. I've opened the App_Data.Logs folder and have seen that there are the log files. But how? I searched in code where is the trick that replaces NullLogger with log4net (I guess this is log4net, because the log format and the formatting for log4net.config are very similar) but I haven't found this.
Can somebody answer me:
How Orchard does the logging?
Whether I can add my own logger and if yes what best practices exist to do this?
Thanks, Andrey.
An Autofac module (Orchard.Logging.LoggerModule to be precise) handles that. Basically - it scans each dependency and fills all properties of type ILogger with a reference to appropriate logger instance. Each dependency gets its own logger with name equal to full type name (including namespace) of a containing class.
The NullLogger is just a placeholder so accessing the property would not throw NullReferenceExceptions before the property is being set by Autofac.
Extending the default logging is a rather complicated task as it would involve doing three things:
create a custom implementation of ILoggerFactory (just like the default Orchard.Logging.CastleLoggerFactory) and
create an Autofac module that registers that implementation in the container (like the mentioned LoggerModule does)
suppress the current default logging module by decorating your new one with [OrchardSuppressDependency("Orchard.Logging.LoggingModule")]
UPDATE
Just realized I haven't addressed the most important part of the question here:)
Yes, Orchard uses log4net so you may alter the default settings via Config/log4net.config file.
There is a great article on how Orchard Logging works. (I am not sure if it is ok to copy and paste the entire article). This is the link: Injection Logger in Orchard
So the trick is this:
Whenever a class requires a Logger instance, all it needs to do is to
declare a ILogger property, that’s it. And later, in your class, you
can use this property to Logging at anytime
And how is this done?
When Orchard web application startup, the OrchardStarter will be used
to do most of the registration work.
In a few words, it looks all the code in all projects, gets all the classes that use an ILogger property, and implements it for you (if not implemented), using Castle's logger factory.
Folks,
This is probably very simple, but I couldn't turn up anything explicitly on point.
I have a web app (ASP.Net 4.0) that references a class library. The class library has various settings. I'd like to use the strongly-typed Properties.Settings capability within the class library. However, since class library config files are ignored under ASP.Net, I'd like the backing store for the settings to be a section of web.config as opposed to a class library-specific app.config.
I figure this is either outrightly forbidden or is as easy as pie to do. Can anyone tell me how to make it work?
Thanks,
Ann L.
I'm not 100% sure what you're asking, but I see two possible questions:
The class library has properties that are controlled (set) by the config file, but class libraries don't consume config files. If that's the case, then all you need to do is move those settings to the calling app's config file - the class library will automatically use the calling app's Web.config (or App.config, as appropriate).
You want to create a custom Configuration Section, which can also be done: How to: Create Custom Configuration Sections Using ConfigurationSection
Unless I've totally misread your question (always a possibility with me :) ), I'd go with #1 as it's easier, unless there's something unique or required in your design to move you to option 2.
In my asp.net project currently i have business logic and and data access code in two sub folders(BLL,DAL) which are itself located web site project's app_code folder. I need to segregate them to two separate projects(one project for business layer and one project for Data access code).
How can I maintain connection strings necessary to Data access project which are currently in web.config file?(i.e if I choose Class library template for creating DAL and BLL projects)
How can I maintain various other web.config key values that are currently used in BLL, DAL code files?
How can I deploy compiled project? (ie Web site project I am currently deploying bin folder to Staging> production but this way where should i put DAL.dll and BLL.dll and relevant config files)
1 and 2) Add a 'using System.Configuration' and just reference them. Since their referenced in the project, asp.net will pick it up.
For example:
using System.Configuration;
namespace DataLayer
{
public class BaseDataAccess
{
public static string ConnectionString_Logging
{
get
{
return ConfigurationManager.ConnectionStrings["ConnectionString_Logging_Legacy"].ToString();
}
}
}
}
3) If properly referenced, upon compile, your BLL and DAL dlls will be in your bin folder of the main/ui project. If using web.config, your good to go.
Fundamentally, you should be wrapping those configuration bits up in objects along the way. But in any case, you can move them to a different class project without worry here -- it will pick up the configuration settings from whatever project it is hosted by, so you don't need to somehow provide the configuration to your library.
Your existing code should work, as the settings are read from the Config file of the running process, in this case your Web.Config, however i suggest you use custom configuration settings, these would be read from your Web.Config file, a typical implementation could look something like :
<YourCompany>
<YourCompany.ProjectName>
<Data ConnectionName="NameOfConnectionToUse" SomethingElse="XZY" />
<Business SomeValue="12345" />
</YourCompany.ProjectName>
</YourCompany>
Without getting into ideal settings/custom config etc, as asked - during runtime, your class libraries will get the configuration from the web.config if referenced as such from within these layers with no change. System.Configuration.AppSettings/ConnectionStrings will still work.
I'm developing a web application (ASP.NET 3.5) that will consume a number of web services. I have created a separate dll-project for each web service: these projects contains the service reference and client code.
However, the calling website MUST have the <system.serviceModel> information (the <bindings> and <client> nodes) in it's web.config, even though this information is also in the dll's app.config file! I have tried copying the serviceclass.dll.config over to the bin directory of the website, but this didn't help.
Is there any way to centralize the configuration of a WCF client?
I've only limited WCF experience, all with BasicHTTP bindings. But I'm allergic to WCF's xml files and have managed to avoid them thus far. I don't recomend this generally but I put the configuration details in my apps existing configuration store and then apply them programatically. E.g. With a Web service proxy I use the constructor for the Client that takes 'bindings'and 'endpoint' and programatically apply the settings to the bindings & endpoint.
A more elegent solution appears to be descibed here: Reading WCF Configuration from a Custom Location, but I haven't tried it yet.
From my experience, library projects never read app.config.
So you can really delete the file because it is not used. The library's host configuration is read instead, so that is the only place the endpoint and binding configuration should be.
It's possible to forgo xml config and build up the Binding and Endpoint classes associated with the service in the constructor or a custom "Service Factory". iDesign has some good information on this:
http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=5&tabid=11
(See In Proc Factory)
In their approach, you set attributes on your services to specify at a high level how they should work (ie [Internet], [Intranet], [BusinessToBusiness]), and the service factory configures the service according to best practices for each scenario. Their book describes building this sort of service:
http://www.amazon.com/Programming-WCF-Services-Juval-Lowy/dp/0596526997
If you just want to share configuration XML config, maybe use the configSource attribute to specify a path for configuration: http://weblogs.asp.net/cibrax/archive/2007/07/24/configsource-attribute-on-system-servicemodel-section.aspx
Remember that a configuration file is is read by an executable that has an entry point. A library dll does not have an entry point so it is not the assembly that will read it. The executing assembly must have a configuration file to read.
If you would like to centralize your web configs then I would suggest you look into nesting them in IIS with virtual directories. This will allow you to use the configuration inheritance to centralize whatever you need.
There are 2 options.
Option 1. Working with channels.
If you are working with channels directly, .NET 4.0 and .NET 4.5 has the ConfigurationChannelFactory. The example on MSDN looks like this:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "Test.config";
Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None);
ConfigurationChannelFactory<ICalculatorChannel> factory1 =
new ConfigurationChannelFactory<ICalculatorChannel>(
"endpoint1",
newConfiguration,
new EndpointAddress("http://localhost:8000/servicemodelsamples/service"));
ICalculatorChannel client1 = factory1.CreateChannel();
As pointed out by Langdon, you can use the endpoint address from the configuration file by simply passing in null, like this:
var factory1 = new ConfigurationChannelFactory<ICalculatorChannel>(
"endpoint1",
newConfiguration,
null);
ICalculatorChannel client1 = factory1.CreateChannel();
This is discussed in the MSDN documentation.
Option 2. Working with proxies.
If you're working with code-generated proxies, you can read the config file and load a ServiceModelSectionGroup. There is a bit more work involved than simply using the ConfigurationChannelFactory but at least you can continue using the generated proxy (that under the hood uses a ChannelFactory and manages the IChannelFactory for you.
Pablo Cibraro shows a nice example of this here: Getting WCF Bindings and Behaviors from any config source
First of all class libraries (DLLs) do not have their own configuration, however they can read the configuration of their host (Web/Executable etc.). That being said, I still maintain an app.config file on the library projects as a template and easy reference.
As far as the service configuration itself is concerned, WCF configuration can make somebody easily pull their hair out. It is an over-engineered over-complicated piece. The goal of your applications should be to depend least on the configuration, while maintaining flexibility of deployment scenarios your product is going to come across.