How can we resolve dependency with configuration file settings - c#

I am kind of new to the dependency injection resolver techniques topic. May I know how we can resolve dependency through configuration file section(s)? Below are my classes and interface along with the config file.
I am sure that missing some portion of code/setting. Can you please help me with this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnityConfiguration_Testing
{
public interface IUserAuthentication
{
string Authenticate(string username, string password);
string GetUserRole(string username);
}
}
public class CloudAppAuthetication: IUserAuthentication
{
public string Authenticate(string username, string password)
{
return "This Authenticate method executed from cloud class";//Jwt token based authentication logic should be there
}
public string GetUserRole(string username)
{
return "This GetUserRole method executed from cloud class";//New logic to user management api call
}
}
public class StandaloneAppAuthetication : IUserAuthentication
{
public string Authenticate(string username, string password)
{
return "This Authenticate method executed from standalone class";//current logic should be here
}
public string GetUserRole(string username)
{
return "This GetUserRole method executed from standalone class";//current logic should be here
}
}
Console application calling of interface method:
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnityConfiguration_Testing
{
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.LoadConfiguration("TestContainer");
IUserAuthentication _userAuthentication = null;
string validatedUser = _userAuthentication.Authenticate("testuser#user.com", "testpassword");
string validatedUserRole = _userAuthentication.GetUserRole("testuser#user.com");
}
}
}
My App.config file of console application is:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container name="TestContainer">
<register type="UnityConfiguration_Testing.IUserAuthentication,UnityConfiguration_Testing" mapTo="UnityConfiguration_Testing.StandaloneAppAuthetication,UnityConfiguration_Testing" />
</container>
</unity>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>

Inversion Of Control contener is what you want to have.
There are many. For example Autofac. They have ability to register implementations for interface depending on your configuration in config files or you can configure it at runtime.

If I understood the question correctly, this is roughly what you're looking for.
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
Type t = Type.GetType("Second"); //get class name from config here
MethodInfo method
= t.GetMethod("Hello", BindingFlags.Static | BindingFlags.Public); // get method by name here
Console.WriteLine(method.Invoke(null,null));
}
}
public static class First
{
public static string Hello(){
return "hello";
}
}
public static class Second
{
public static string Hello(){
return "Hello World";
}
}
This will allow you to get a class and method defined by names you can get from the config file.

Related

How to add Global MongoDB connection String to C# Project

I am using my MongoDB database to store some documents for my project. The driver version for MongoDB I am using is 2.12.2.
How I am using my Mongo connection for my Operations is like this,
Web.config
<configuration>
<appSettings>
<add key="MongoDBDatabase" value="TestDB" />
</appSettings>
<connectionStrings>
<add name="MongoConnection" connectionString="myconnnection/db?retryWrites=true"/>
</connectionStrings>
</configuration>
DBConnection.cs
using System.Configuration;
namespace MyProj.DataAccess.Implementations
{
internal class DBConnection
{
public static string MongoDBConnectionString { get { return ConfigurationManager.ConnectionStrings["MongoConnection"].ConnectionString; } }
public static string MongoDBdatabase { get { return ConfigurationManager.AppSettings["MongoDBDatabase"].ToString(); } }
}
}
UserDAL.cs
namespace MyProj.DataAccess.Implementations
{
public class UserDAL: IUserDAL
{
public static string database = DBConnection.MongoDBdatabase;
public List<UserTbl> GetAll()
{
var con = new MongoClient(DBConnection.MongoDBConnectionString);
var db = con.GetDatabase(database);
var collection = db.GetCollection<UserTbl>("UserTbls");
var users=collection.AsQueryable().ToList();
}
}
}
The thing is I need to call the connection globally like from singleton. So that only a single connection is open for multiple requests. How can I do that ?
I prefer to you to config your mongodb client with best practices like this
you can define your mongodb as singlton but be aware you should use async methods , I prefer you to use ConcurrentQueue and its methods

Changing a path for logger using Form application and implementing it to Service with C#

I am working on a File Watcher service which has a form application in it too (2 different projects in same solution). So I am getting a path for where to save the log with Forms application. Then I put that in my app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="location" value="C:\Users\user\Documents" />
<add key="logLocation" value="C:\Users\user\Documents" /> <!-- this is where it changes save it-->
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
And I have a Variables class where I define my variable.
using System.Configuration;
namespace FileWatchingService
{
public static class Variables
{
public static string FilePath { get; set; } = ConfigurationManager.AppSettings.Get("location");
public static string LogPath { get; set; } = ConfigurationManager.AppSettings.Get("logLocation");
}
}
Then I am trying put my LogPath in here:
using System;
using System.IO;
namespace FileWatchingService
{
public static class Logger
{
public static void Log(string message)
{
try
{
string _message = String.Format("{0} {1}", message, Environment.NewLine);
//File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "logFile.log", _message);
File.AppendAllText(Variables.LogPath + "logFile.log", _message);
}
catch (Exception ex)
{
//Implement logging on next version
}
}
}
}
Problem is that my way does not work. What can I do to change my log files path?
Looking solely at the code, it seems you're missing a \ at the end of the LogPath value.
You could also do File.AppendAllText(Variables.LogPath + "\logFile.log", _message); or just define the LogPath itself, such as:
<appSettings>
<add key="location" value="C:\Users\user\Documents" />
<add key="logLocation" value="C:\Users\user\Documents\log.txt" /> <!-- the file itself -->
</appSettings>
Nevertheless, I would advise to just use a library for logging, instead of developing your own. Go with NLog or Serilog

Reading from app.config yields null results

My issue is as the title reads, when I attempt to get some app settings for a given key, I am always returned with null.
I have 2 projects, 1 .Net Core Class library and 1 .Net Core Test Solution. Both contain an identical app.config.
https://imgur.com/a/oD8FHPW.
Here is the solution explorer so you can see the project set up.
In my tests solution, I am trying to test the validity of my helper using this test method
[TestMethod]
public void TestSaveLocationHelper()
{
ConfigurationResponseMessage connectionString = ConfigurationHelper.GetSaveLocation();
Assert.IsTrue(connectionString.ResponseCode == ResponseCode.SUCCESS);
}
I wrote a helper method that calls the configurationManager.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
namespace Unity.Helpers
{
public static class ConfigurationHelper
{
public static ConfigurationResponseMessage GetSaveLocation()
{
string saveLocation = ConfigurationManager.AppSettings[Constants.SAVE_LOCATION];
if (!string.IsNullOrWhiteSpace(saveLocation))
return new ConfigurationResponseMessage()
{
ConfigString = saveLocation,
ResponseCode = ResponseCode.SUCCESS
};
return new ConfigurationResponseMessage()
{
ConfigString = string.Empty,
ResponseCode = ResponseCode.FAILURE
};
}
}
}
saveLcoation is always null
Constants.SAVE_LOCATION = 'SaveLocation'
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SaveLocation" value="D:/test.json"/>
</appSettings>
</configuration>
Not entirely sure what is wrong. Thanks for any help

Unity The parameter host could not be resolved when attempting to call constructor

When I attempt to instantiate my instance of the base class I get the error:
a ResolutionFailedException with roughly the following error "The parameter host could not be resolved when attempting to call constructor"
I'm currently not using an Interface for the base type and my instance of the class is inheriting the base type class. I'm new to Unity and DI so I'm thinking its something I forgot possibly.
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "Unity.Config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)config.GetSection("unity");
IUnityContainer container = new UnityContainer();
section.Containers.Default.Configure(container);
//Throws exception here on this
BaseCalculatorServer server = container.Resolve<BaseCalculatorServer>();
and the Unity.Config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--Unity Configuration-->
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity>
<containers>
<container>
<types>
<type name ="CalculatorServer" type="Calculator.Logic.BaseCalculatorServer, Calculator.Logic" mapTo="Calculator.Logic.CalculateApi, Calculator.Logic"/>
</types>
</container>
</containers>
</unity>
</configuration>
The Base class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Transactions;
using Microsoft.Practices.Unity;
using Calculator.Logic;
namespace Calculator.Logic
{
public class BaseCalculatorServer : IDisposable
{
public BaseCalculatorServer(){}
public CalculateDelegate Calculate { get; set; }
public CalculationHistoryDelegate CalculationHistory { get; set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose();
}
}
}
The Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Calculator.Logic;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using Microsoft.Practices.Unity;
namespace Calculator.Logic
{
public class CalculateApi:BaseCalculatorServer
{
public CalculateDelegate Calculate { get; set; }
public CalculationHistoryDelegate CalculationHistory { get; set; }
}
}
Yes both base class and implementation are in the same Namespace and thats something design wise that will change once I get this working.
Oh and a more detailed error
Resolution of the dependency failed, type = "Calculator.Logic.BaseCalculatorServer", name = "". Exception message is: The current build operation (build key Build Key[Calculator.Logic.BaseCalculatorServer, null]) failed: The value for the property "Calculate" could not be resolved. (Strategy type BuildPlanStrategy, index 3)
I'm not sure that this would trip Unity up, but what happens if you remove the Calculate and CalculationHistory properties from CalculateApi? These are hiding the members of the base class, which is almost certainly not what you want to be doing.
I always configure in code, rather than XML, so I'm not sure about this, but maybe try removing the name attribute from your mapping, or passing the proper name when you call Resolve -- I'm guessing something like container.Resolve<BaseCalculatorServer>("CalculatorServer"). Unless you are registering multiple implementations, though, I'd remove the name altogether.

C# AppSettings: Is there a easy way to put a collection into <appSetting>

i tried
<appSettings >
<add key="List" value="1"/>
<add key="List" value="2"/>
<add key="List" value="3"/>
</appSettings >
and System.Configuration.ConfigurationManager.AppSettings.GetValues("List");
But i only get the last member .
How could i solve this easily?
I have dealt a similar issue and I did it with this code. Hope this helps in your problem.
In this case List (similar to my URLSection) will have a full configuration Section in web.config which you can get all values from this section then.
<configSections>
<section name="URLSection" type="A.WebConfigSection,A,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
</configSections>
<appSettings></appSettings>
<URLSection>
<urlCollection>
<add url="1" value="a"/>
<add url="2" value="b"/>
</urlCollection>
</URLSection>
I made three classes for this: ConfigElement, ConfigElementCollection, WebConfigSection.
ConfigElement
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace A
{
public class ConfigElement:System.Configuration.ConfigurationElement
{
[ConfigurationProperty("url",IsRequired=true) ]
public string url
{
get
{
return this["url"] as string;
}
}
[ConfigurationProperty("value", IsRequired = true)]
public string value
{
get
{
return this["value"] as string;
}
}
}
}
ConfigElementCollection
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace A
{
public class ConfigElementCollection:ConfigurationElementCollection
{
public ConfigElement this[int index]
{
get
{
return base.BaseGet(index) as ConfigElement;
}
}
protected override ConfigurationElement CreateNewElement()
{
return new ConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((ConfigElement)(element)).url;
}
}
}
WebConfigSection
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace A
{
public class WebConfigSection:ConfigurationSection
{
public WebConfigSection()
{
}
[ConfigurationProperty("urlCollection")]
public ConfigElementCollection allValues
{
get
{
return this["urlCollection"] as ConfigElementCollection;
}
}
public static WebConfigSection GetConfigSection()
{
return ConfigurationSettings.GetConfig("URLSection") as WebConfigSection;
}
}
}
foreach (string str in ConfigurationManager.AppSettings.AllKeys)
{
if (str.ToUpper().IndexOf("SOMESPECIAL") > -1) //the somespecial ones you want to add in
lstList.Add(ConfigurationManager.AppSettings[str]);
}
NinjaSettings does this out of the box.
In the package manager console
Install-Package NinjaSettings
You would declare your list as
<appSettings>
<add key="List" value="50,20,10,100"/>
</appSettings>
then create an Interface with a mapping for list to any ICollection or Array
public interface IAppSettings
{
List<int> List { get; }
}
then access your settings user the NinjaSettings wrapper. Generally you would wire this up using IOC, but the basic usage is
var settings = new NinjaSettings<IAppSettings>().Settings;
int total = 0;
for (var i in settings.List)
{
total+=i;
}
You'd likely be better off putting this information in a separate XML file and having a reference to that file in AppSettings. That would give you a lot more flexibility around how you retrieved the information and consumed it.
The only thing would be that you'd want to create a separate (static?) class for reading the XML in a similar fashion to the System.Configuration.ConfigurationManager.AppSettings class.
If, on the other hand, it HAD to be in your Web.Config file, I would suggest the only way to achieve this simply would be to have a [pipe/comma/semi-colon] delimited array in one "List" setting.
Haacked provides a concise approach to configuration settings. His approach uses one class deriving from ConfigurationSection. So for his blog example your app.config or web.config xml representation will look like this:
<configuration>
<configSections>
<section name="BlogSettings" type="Fully.Qualified.TypeName.BlogSettings,
AssemblyName" />
</configSections>
<BlogSettings frontPagePostCount="10" title="You’ve Been Haacked" />
</configuration>
This is worth a read:
http://haacked.com/archive/2007/03/12/custom-configuration-sections-in-3-easy-steps.aspx

Categories