Can a class library have an App.config file?
Asked Answered
C

7

55

Here is what my solution is looking like at the moment:

enter image description here

In the Tutomentor.Branding project, I'd like to save branding information in the App.config file, like names, colors, etc.

In the Tutomentor.Data project, the App.config was created when I added an entity .edmx model file.

Is this possible? Any recommendations?

When deploying, will the output COMBINE these App.config files into a single one?

Concoct answered 27/1, 2011 at 13:41 Comment(0)
P
58

No, class libraries can hold setting files, but their values will be defined in the application configuration (web.config, app.config...).

That's because of configuration settings overriding feature.

You'll need to declare the assemblies' configuration sections in the app.config or web.config of your application (WPF, SL, ASP.NET...) and define a value for a particular number of settings defined in the proper assembly settings.

EDIT: Add a setting file to your project and add a setting with application scope, and your assembly would have something like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="Assembly1.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <Assembly1.Settings1>
            <setting name="settingA" serializeAs="String">
                <value>a value</value>
            </setting>
        </Assembly1.Settings1>
    </applicationSettings>
</configuration> 

Now you'd need to go to your application, and you need to copy-paste the section group, and section declarations, and the definition of the values for the settings. That's all.

Phylys answered 27/1, 2011 at 13:47 Comment(4)
Can you expand on that? How would I, "declare the assemblies' configuration sections in the app.config or web.config of your application".Concoct
Fist you create the settings file in your non-executable assembly, and then, you re-declare the same section in your executable application or web application, and you define there the value for a set of settings :) The name of the section (the namespace to the settings file - in fact, the class - must match in the assembly and in the executable. The executable doesn't need to define ALL settings from the satellite assembly. You can define 1, 2 or all.Phrenetic
Regarding edit: Copypasting settings that already exist sounds like a bad idea. What other approach do you suggest?Concoct
You didn't tried my solution, which is the official one. It's not copy-pasting, it's that you define a strongly-typed settings in your assembly and Visual Studio generates a sample app.config for you, which is in the other hand a shortcut for copy-pasting this auto-generated code to your final application executable configuration.Phrenetic
C
49

While this is an older thread, It does warrent another look.

It seems you may want to look at the issue in a different way.

Class libraries by nature are supposed to be portable. So, any configuration needed should be passed to the class, instead of residing with the library. Things like connection strings are by nature transitory, so it makes sense to put them in the owning application.

When utilizing the methods contained in the library, you pass any needed information as part of the method's signature, or as a public property in the class. I suggest you create public properties for your configuration items, and pass them when you instantiate the class.

Now you have no issues with an app.config for the DLL, and the DLL is then truly portable.

Central answered 25/9, 2012 at 14:54 Comment(12)
I see your point and I agree. But then why does Visual Studio even allow creation of "Settings.settings" files for DLLs? Is Microsoft just trolling us?Demob
@Demob Much of the information in these answers seems to no longer be strictly accurate, at least as it applies to Visual Studio 2017. I just created a class library with a Settings.settings file for a class library that serves as a plug-in for an application not under my control. Compilation generated a library.dll file and a library.dll.config file. Distributing the two files together, my plug-in was able to access its own settings without having to modify the .config file for the main application in any way.Grammarian
@Grammarian As far as I know, this is not entirely true. VS 2017 (and 2013 too) will create library.dll.config file, but it won't use it. The only configuration file that is used is the exe's. The reason why your settings worked is because your app was using default values that were configured in Settings.Designer.cs. If you try to modify the library's config file locally (outside of VS), the modifications will be ignored.Fernandes
@Fernandes Thank you for the clarification. I ran some tests on my plugin and you are correct.Grammarian
Sorry, original answer is still correct. Copy the settings from the child app.config to the parent web.config. When the parent app runs and calls the class library, and that class library references its own setting, the parent app will apply the settings in the web.config.Ripe
Thanks for this answer. Very simple idea which also makes total sense.Dimaggio
The reason VS generates library.dll.config is for COM applications. Imagine you have an Excel COM Add-in and want to allow administrators the ability to configure what web service URL and port the Add-in talks to. It is not intended for class libraries that are consumed by other EXE's. It's not whether it is a DLL that matters. What matters is whether it's got an "ENTRY POINT". For Excel COM Add-ins like RTD Servers, the server is the "ENTRY POINT".Chancellor
This will get you a library.dll.config's AppSettings: ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettingsChancellor
I don't agree with this - making something "portable" doesn't mean it should ONLY be configurable in code (which is the cut and thrust of this answer). In fact many 3rd party libraries that need configuring require settings to be "copied" to the application app/web.config - e.g. Loggers/ORMsDecorticate
Class libraries by nature are supposed to be portable. So, any configuration needed should be passed to the class, instead of residing with the library. Does this mean the library shouldn't be making calls to ConfigurationManager.AppSettings.Get("SomeSetting") and instead take the value of SomeSetting that the application code passes to it (the library API)?Colocynth
If a library depends on some app settings, how do communicate to the library user that they must define certain key/value pairs for the library to work properly? Documentation?Colocynth
I like this idea; By any chance would you have a GIST about passing the config to the class methods using DI?Listing
B
9

Just create your own XML file, name it appConfig.xml or something similar, have your class library read the file using System.Xml instead of System.Configuration, and package the file along with your dll.

Beaujolais answered 31/7, 2016 at 19:29 Comment(0)
M
4

Any specific configuration from library app.config, you have to put in your exe configuration file manually.

Multiplechoice answered 27/1, 2011 at 13:50 Comment(0)
M
3

You can add Settings File which will automatically generate app.config file. Visual C# Items

And can Add the key value pairs in tabular form with the datatype specified. Then Access the values by calling Settings.Default.[KEY]

can reffer: https://www.technical-recipes.com/2018/creating-a-user-settings-class-library-for-your-c-project/

Maxima answered 23/8, 2019 at 9:59 Comment(0)
M
-1

Well the class library can't have its own app.config, but if you define your settings the from the class library in the app.config for the exe file the class library should be able to find those to..

im a bit unsure but i don't think it will combine them automatically i guess you have to do i manually!

Marchpast answered 27/1, 2011 at 13:58 Comment(0)
P
-2

just use this common config to handle d.injection of services in class lib;

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDBContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                    assembly => assembly.MigrationsAssembly(typeof(AppDBContext).Assembly.FullName));
            });

            services.AddScoped<IUsersRepository, UsersRepository>();

            services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
            {
                builder.AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader();
            }));

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseCors("MyPolicy");
            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseMvc();

        }

appsettingjson file:

{
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "ConnectionStrings": {
        "DefaultConnection": "server=.;database=TestAPP;User ID=yener1;password=yener1;"
      },
      "AppSettings": {
        "Secret": "REPLACE THIS WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
      },
      "AllowedHosts": "*"

}

//commentout

  public static class Hasher
    {
        public static string ToEncrypt<T>(this T value)
        {
            using (var sha256 = SHA256.Create())
            {
                // Send a sample text to hash.  
                var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(value.ToString()));
                // Get the hashed string.  
                return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
            }
        }
    }
public class AppDBContext : DbContext
{
    public AppDBContext(DbContextOptions options)
        : base(options)
    {
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }

    public DbSet<Users> Users { get; set; }
//BLL
    public class UsersRepository : IUsersRepository
    {
        private readonly AppDBContext _context;
        public UsersRepository(AppDBContext context)
        {
            _context = context;
        }
        public async Task<IEnumerable<Users>> GetUsers()
        {
            return await _context.Users.ToListAsync();
        }


[AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody]UserDto userDto)
        {
            var user = _userService.Authenticate(userDto.Username, userDto.Password);

            if (user == null)
                return BadRequest("Username or password is incorrect");

            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[] 
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);

            // return basic user info (without password) and token to store client side
            return Ok(new {
                Id = user.Id,
                Username = user.Username,
                FirstName = user.FirstName,
                LastName = user.LastName,
                Token = tokenString
            });
        }
Pyrone answered 26/6, 2019 at 9:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.