I'm looking for advice on how best to bind a couple of connection
strings which recur throughout my dependencies.
Currently I have (using ninject):
Bind<IFoo>().To<SqlFoo>()
.WithConstructorArgument("db1ConnStr", db1ConnectionString)
.WithConstructorArgument("db2ConnStr", db2ConnectionString);
Bind<IBar>().To<SqlBar>()
.WithConstructorArgument("db1ConnStr", db1ConnectionString)
.WithConstructorArgument("db2ConnStr", db2ConnectionString);
etc.
which obviously is not the most elegant code.
Is there a way to bind the value of db1ConnectionString to every string constructor parameter named "db1ConnStr"?
I would create a class which holds the connection strings:
public class ConnectionStringProvider
{
public string Db1ConnectionString { get; set; }
public string Db2ConnectionString { get; set; }
}
Note: You can also create an interface IConnectionStringProvider for it if you want.
Then the classes SqlFoo and SqlBar can use it as a dependency
public class SqlFoo
{
public SqlFoo(ConnectionStringProvider connectionStringProvider)
{
//do something with connectionStringProvider.Db1ConnectionString
}
}
And the registration would look like this:
Bind<ConnectionStringProvider>().ToConstant(
new ConnectionStringProvider
{
Db1ConnectionString = db1ConnectionString,
Db2ConnectionString = db2ConnectionString,
});
Bind<IFoo>().To<SqlFoo>();
Bind<IBar>().To<SqlBar>();
Related
I'm just getting my head round setting up my own services to inject from Startup.cs in an ASP.NET Core 3.1+ project.
So far I created an interface and a class:
public interface IMyClass
{
public string SomeString { get; set; }
}
public class MyClass : IMyClass
{
public string SomeString { get; set; }
}
I added the service in startup using:
services.AddScoped<Services.IMyClass, Services.MyClass>();
Which works fine, except I want this class to have various strings it can return based on the current configuration and I have no idea how to pass those variables from appsettings.json to populate SomeString so I can then get it from in a controller.
I was trying this:
services.AddScoped<Services.IMyClass, Services.MyClass>(
Configuration.GetValue<string>("SomeAppSettingKey");
To pull a string from appsettings, but don't know how to populate a constructor in the class with the string. Do I need to add some sort of options class as a property in MyClass ?
There's lots of hints on how I can be adding some of these config settings but I'm just missing some info e.g.
services.AddTransient<IMyClass, MyClass>();
services.Configure<MyClass>(Configuration);
Makes syntactical sense to me but I'm still not sure how to populate the string in MyClass by passing the Configuration here.
Create a model to store the setting extracted from configuration
public class MyClassOptions {
public string SomeAppSettingKey { get; set; }
}
(Note the matching names)
Configure it at Startup
services.Configure<MyClassOptions>(Configuration);
(This assumes the key is in the root of the settings file)
Update the target class to inject the options configured
public class MyClass : IMyClass {
public MyClass (IOptions<MyClassOptions> options) {
SomeString = options.Value.SomeAppSettingKey;
}
public string SomeString { get; set; }
}
Reference Options pattern in ASP.NET Core
I currently have a Json config file that looks something like this :
{
"MySettings" " {
"SomeSetting" : "SomeValue"
}
}
In the perfect world, I would have a class that matches that same structure. But, I need to map it to a class that would look something like this :
public class MySettingsUpdated
{
public string MyRenamedSetting {get;set;}
}
I am already using a custom ConfigurationProvider to get data from a configuration file (for various reasons), and I -could- create the data in the expected path in there, but it would make my life much easier if I could decorate the new class with some type of attribute in order to specify where the data needs to come from.
Any way to do this?
static string data = #"
{
""class"": {
""property"" : ""some string!""
}
}";
class DTO
{
[JsonProperty("class")]
public Data Property { get; set; }
}
class Data
{
[JsonProperty("property")]
public string Value { get; set; }
}
static void Main(string[] args)
{
var result = JsonConvert.DeserializeObject<DTO>(data);
}
You can use the .Bind() method exposed on the IConfigurationSection interface.
In a class it could look like
public class SomeClassDoingWork
{
private MyConfigClass MyConf = new MyConfigClass();
public SomeClassDoingWork(IConfiguration config)
{
config.GetSection("MySettings").Bind(MyConf);
}
}
Brief: I'm creating an MVC application in which I need to display a variety of types documents, some containing more author information than others.
What I wanna do: My approach is to have a generic "view document" view, which dynamically displays the document in a format dictated by the shape/type of the object passed to it.
Example: A simple document would be loaded into a SimpleDocumentViewModel, and display as such. However I'd like to load a larger type of document into an ExtendedDocumentViewModel, bringing with it additional information about both the document and the author. The view(s) would then display the appropriate data based on the object it receives.
Where I'm at now: In this vein I've created the following interfaces and classes, but I'm stuck as to how to return/identify the more specific return types in their derived classes.
abstract class BaseDocumentViewModel : DocumentViewModel, IDocumentViewModel
{
public int DocumentId { get; set; }
public string Body { get; set; }
public IAuthorViewModel Author { get; set; }
}
class SimpleDocumentViewModel : BaseDocumentViewModel
{
}
class ExtendedDocumentViewModel : BaseDocumentViewModel
{
public new IAuthorExtendedViewModel Author { get; set; }
}
interface IAuthorViewModel
{
int PersonId { get; set; }
string Name { get; set; }
}
interface IAuthorExtendedViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
}
Question: So my question is; how best can I get the specific types from the fully implemented classes, or do I need to return the base types and query it all in the view? Or am I off my head and need to go back to the drawing board?
Edits:
I know that c# doesn't support return type covarience, but hoped that there may be another way of returning/identifying the derived types so that I don't have to query them all in the view.
My current solution would be to always return the base types, and have a separate view for each concrete type that simply casts each object to the correct type, only querying those that could differ. Perhaps this is the best solution end of, but it feels very inelegant.
Usually you can do a simple "is" check. So you can have conditional rendering in your views, for example:
#if(Model is ExtendedDocumentViewModel)
{
// render ExtendedDocumentViewModel html here
}
Type checking is usually considered an anti pattern, however I am not sure if there is a much better approach to this problem. If you are using .NET Core you can also check the subclass tag here http://examples.aspnetcore.mvc-controls.com/InputExamples/SubClass .
Possible cleaner option is to just have a signature in the interface called GetView that each document has to implement. This way each document type has their own way of implementing the function and the calling function knows that each document has a function GetView. This method will work well if every document has a unique way of viewing the document. However if some documents share the same way of getting views, then may I suggest creating each View type into their own class and you can assign the views types to each document. I suggest looking into the strategy pattern.
First suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
view GetView()
{
... do document specific stuff
... return view
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
view GetView()
{
... do document specific stuff
... return view
}
}
interface IAuthorViewModel
{
view GetView();
}
Second suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
public viewType1 view {get;set;}
public SimpleDocumentViewModel(viewType1 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView();
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
public viewType2 view {get;set;}
public ExtendedDocumentViewModel(viewType2 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView(ExtraData,MoreExtraData);
}
}
interface IAuthorViewModel
{
view GetView();
}
I may be way off base here, but as I understand your question... why not just throw the return types in an object and pass that to your view?
You could look at the desired method and use reflection to pull out whatever info you want. Modify this and the object class hold whatever you want it to.
public class DiscoverInternalClass
{
public List<InternalClassObject> FindClassMethods(Type type)
{
List<InternalClassObject> MethodList = new List<InternalClassObject>();
MethodInfo[] methodInfo = type.GetMethods();
foreach (MethodInfo m in methodInfo)
{
List<string> propTypeList = new List<string>();
List<string> propNameList = new List<string>();
string returntype = m.ReturnType.ToString();
foreach (var x in m.GetParameters())
{
propTypeList.Add(x.ParameterType.Name);
propNameList.Add(x.Name);
}
InternalClassObject ICO = new InternalClassObject(c.Name, propNameList, propTypeList);
MethodList.Add(ICO);
}
return MethodList;
}
}
he object class could be something like this or modify it however you want:
public class InternalClassObject
{
public string Name { get; set; }
public List<string> ParameterNameList { get; set; }
public List<string> ParameterList { get; set; }
public InternalClassObject(string iName,List<string> iParameterNameList, List<string> iParameterList)
{
Name = iName;
ParameterNameList = iParameterNameList;
ParameterList = iParameterList;
}
}
You could call the method like this with the desired class.
public static List<InternalClassObject> MethodList = new List<InternalClassObject>();
DiscoverInternalClass newDiscover= new DiscoverInternalClass();
MethodList = newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
Now you can have your GetView build based on what is in MethodList
Hope this helps!
I have a class that needs to get some data to perform analysis. Let's say the interface for getting the data is as follows:
public interface IDataFetcher
{
List<someobject> GetData();
}
In a very simple case my class will use this interface as follows in one of its methods:
void PerformAnalysis(List<IDataFetcher> fetchers)
{
...
foreach(IDataFetcher fetcher in fetchers)
{
List<someobject> myList = fetcher.GetData();
//We will try fetching one by one using different fetchers until we get the data
if(myList.Count > 0)
break;
}
...
}
Now, different fetching implementations such as fetching from file, fetching from machine or fetching from dB take different input for their data sources e.g. File Fetcher would need the file path, machine fetcher would need machine name and dB fetcher would need database string.
In my case this source information can only be known at runtime (from user input or some other source) later in PerformAnalysis Method above. So, now I cannot pass IDataFetchers since source is not known.
The way I modified this was to not perform the instantiation from outside but to defer it by creating an Abstract factory as follows:
public interface IDataFetcherAbstractFactory
{
IDataFetcher CreateFetcher(string source);
}
public interface FileDataFetcherFactory : IDataFetcherAbstractFactory
{
IDataFetcher CreateFetcher(string source)
{
return new FileDataFetcher(source);
}
}
Similary, different fetchers would do the same like MachineDataFetcherFactory etc.
One implementation of a FileDataFetcher could be swapped with another by updating few tags in Unity Container XML configuration without modifying source code at all. So, this is good.
Now, I updated my method as follows:
void PerformAnalysis (List<IDataFetcherAbstractFactory> fetcherFactories)
{
...
string source = GetSource(); //source known dynamically
foreach(IDataFetcherAbstractFactory factory in fetcherFactories)
{
IDataFetcher fetcher = factory.Create(source);
List<someobject> myList = fetcher.GetData();
//We will try fetching one by one using different fetchers until we get the data
if(myList.Count > 0)
break;
}
...
}
a) Is this approach of using Factory correct or is there a better way to do this ?
b) The second issue I observed is for each factory product the source string could be different. i.e. for database factory source string is connection string, for machine its machine name etc. This means my class must be aware of what factory it is dealing with. Is it okay to make it aware ?
c) Without updating the source can a new factory be somehow passed/injected into the fectcherFactories list using unity ?
Example, someone implemented a new WebServiceFetcher : IDataFetcher and a corresponding factory for it. Now, to make my framework utilize it, I will have to modify source code to add it to the list of fetcherFactories. This does not sound scalable.
Thanks
Maybe I am missunderstanding something in your question but I will try to offer an answer:
Declare runtime data for user input values:
public interface IRuntimeData
{
string filePath { get; set; }
string connectionString { get; set; }
string machineName { get; set; }
}
class RuntimeData : IRuntimeData
{
public string filePath { get; set; }
public string connectionString { get; set; }
public string machineName { get; set; }
}
Declare interface for data fetcher and implementations. Theese classes need IRuntimeData to work.
interface IDataFetcher
{
object getData();
}
class FileFetcher : IDataFetcher
{
private string _filePath;
public FileFetcher(IRuntimeData userInputData)
{
_filePath = userInputData.filePath;
}
public object getData()
{
return "Hello from FileFetcher. File path is " + _filePath;
}
}
class DBFetcher : IDataFetcher
{
private string _connStr;
public DBFetcher(IRuntimeData userInputData)
{
_connStr = userInputData.connectionString;
}
public object getData()
{
return "Hello from DBFetcher. Connection string is " + _connStr;
}
}
class MachineFetcher : IDataFetcher
{
private string _machineName;
public MachineFetcher(IRuntimeData userInputData)
{
_machineName = userInputData.machineName;
}
public object getData()
{
return "Hello from MachineFetcher. Machine name is " + _machineName;
}
}
Declare Analyzer class. This class need a list of IDataFetcher.
class Analyzer
{
private List<IDataFetcher> _fetcherList;
public Analyzer(IDataFetcher[] fetcherList)
{
_fetcherList = new List<IDataFetcher>(fetcherList);
}
public void PerformAnalysis()
{
foreach (IDataFetcher dtFetcher in _fetcherList)
{
Console.WriteLine(dtFetcher.getData());
}
}
}
Now, register Datafetchers in the container at app bootstrap.
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataFetcher, FileFetcher>("file");
container.RegisterType<IDataFetcher, DBFetcher>("db");
container.RegisterType<IDataFetcher, MachineFetcher>("machine");
When user insert runtime data, create a instance and register it in the container:
IRuntimeData rtData = new RuntimeData();
rtData.connectionString = "Persist Security Info=False;Integrated Security=true;Initial Catalog=Northwind;server=(local)";
rtData.filePath = #"C:\foo.txt";
rtData.machineName = "jlvaqueroMachine";
container.RegisterInstance<IRuntimeData>(rtData);
The last part is resolve the Analyzer through container:
Analyzer myAnalyzer = container.Resolve<Analyzer>();
myAnalyzer.PerformAnalysis();
Console.Read();
And you can see how all DataFetcher registered in the container are created an injected into Analyzer.
Full example here.
PD: If RegisterInstance of runTimeData looks like service locator anti-pattern to you; it is possible to resolve Analyzer overriding runtimeData pependency:
IRuntimeData rtData = new RuntimeData();
rtData.connectionString = "Persist Security Info=False;Integrated Security=true;Initial Catalog=Northwind;server=(local)";
rtData.filePath = #"C:\foo.txt";
rtData.machineName = "jlvaqueroMachine";
Analyzer myAnalyzer = container.Resolve<Analyzer>(new DependencyOverride<IRuntimeData>(rtData));
Is it possible to add some additional attributes to my components which are then set/hydrated using some custom logic/perhaps from a data store? Similar to adding some custom builder strategy in cab/unity ?
UPDATE
e.g.
assuming a class has these properties
[MyImport] string name1 { get; set }
[MyImport] MyType name2 { get; set }
[MyGuid] Guid { get; set; }
with custom attributes MyImport and MyGuid which are resolved by an "extension" to MEF ( which gets executed after the [imports] are resolved ) and has code along these lines
// property SET
var valu = myDBStore.GetValue( instanceGUID, propertyInfo.Name);
propertyInfo.SetValue( instance, TypeDescripter.GetConverter(valu).ConvertTo(propertyType), null);
// property GET - for example only, used during dehydration outside of MEF !
var valu = propertyInfo.GetValue( instance, null);
myDBStore.SetValue( instanceGUID, propertyInfo.Name, TypeDescripter.GetConverter(valu).ConvertTo(typeof(string));
// the above is pseudo code only, pls no comments on correct args/syntax :)
EDIT
components which are then set/hydrated using some custom logic/perhaps from a data store
One can do this via an "ExportFactory".
// "ExportFactory"
public sealed class DataStoreProvider
{
[Export(typeof(Model))]
public Model Item
{
get
{
return [custom logic];
}
}
}
public class NeedsModel
{
[Import(typeof(Model))]
public Model Item { get; set; }
}
Initial Answer
This is possible through MEF's Lazy<T, TMetadata>.
public interface ISomeMetadata
{
string UsefulInfo { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportBaseAttribute : ExportAttribute, ISomeMetadata
{
public ExportBaseAttribute(string usefulInfo)
:base(typeof(BaseExport))
{
UsefulInfo = usefulInfo;
}
public string UsefulInfo { get; private set; }
}
// BaseExport class is not needed.. just showing advanced attribute usage.
public abstract class BaseExport { }
[ExportBase("Useful Filter Information")]
public class SomeExport : BaseExport
{
}
Then, in your host (composer), you can
[ImportMany(typeof(BaseExport))]
Lazy<BaseExport, ISomeMetadata>[] _baseExports
After you compose, you can run a LINQ filter using .Metadata
var goodExports = from export in _baseExports
where export.Metadata.UsefulInfo ...
select export;