vary a constructor injected string parameter with Unity - c#

My goal is to vary a string parameter:
Container
.RegisterInstance<string>("us", #"\\ad1\accounting$\Xml\qb_us.xml")
.RegisterInstance<string>("intl", #"\\ad1\accounting$\Xml\qb_intl.xml");
driver = Container.Resolve<LoaderDriver>(args[1]); // "us" or "intl"
Which results in:
Resolution of the dependency failed, type = "QuickBooksService.LoaderDriver", name = "intl".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
-----------------------------------------------
At the time of the exception, the container was:
Resolving QuickBooksService.LoaderDriver,intl
Resolving parameter "reader" of constructor QuickBooksService.LoaderDriver(QuickBooksService.LoaderInputReader reader, QuickBooksService.ILoader[] loaders)
Resolving QuickBooksService.LoaderInputReader,(none)
Resolving parameter "inputFile" of constructor QuickBooksService.LoaderInputReader(System.String inputFile, AccountingBackupWeb.Models.AccountingBackup.Company company, Qu
ickBooksService.eTargets targets)
Resolving System.String,(none)
This is obviously wrong but its the only way I could get it to work:
if (args[1] == "us")
Container
.RegisterType<LoaderInputReader>(
new InjectionConstructor(
#"\\ad1\accounting$\Xml\qb_us.xml",
new ResolvedParameter<Company>(),
new ResolvedParameter<eTargets>()
)
)
;
else if (args[1] == "intl")
Container
.RegisterType<LoaderInputReader>(
new InjectionConstructor(
#"\\ad1\accounting$\Xml\qb_intl.xml",
new ResolvedParameter<Company>(),
new ResolvedParameter<eTargets>()
)
)
;
else
throw new Exception("invalid company");
driver = Container.Resolve<LoaderDriver>();

Something like this ought to work:
container
.RegisterType<LoaderInputReader>(
"us",
new InjectionConstructor(
#"\\ad1\accounting$\Xml\qb_us.xml",
new ResolvedParameter<Company>(),
new ResolvedParameter<eTargets>()));
container
.RegisterType<LoaderInputReader>(
"intl",
new InjectionConstructor(
#"\\ad1\accounting$\Xml\qb_intl.xml",
new ResolvedParameter<Company>(),
new ResolvedParameter<eTargets>()));
This names each registration of LoaderInputReader. Now you can resolve like this:
var us = container.Resolve<LoaderInputReader>("us");
var intl = container.Resolve<LoaderInputReader>("intl");

Perhaps you could change
driver = Container.Resolve<LoaderDriver>(args[1]); // "us" or "intl"
with
driver = Container.Resolve<LoaderDriver>(Container.Resolve<string>(args[1]))
This takes advantage of the Resolve overload that takes a name, where in your case the name comes from your argument.

Related

Simple Injector 4.1: Overriding Parameter Injection Behavior

I'm new to using DI in C# and had a look at Windsor, Ninject, Autofac, Unity and Simple Injector. I originally discarded Simple Injector because I needed value-type injection (fx. connection strings) but found a blogpost describing this: https://cuttingedge.it/blogs/steven/pivot/entry.php?id=94. Unfortunately the blogpost is outdated since IDependencyInjectionBehavior.BuildExpression is deprecated in version 4.1 and IDependencyInjectionBehavior.GetInstanceProducer has been introduced instead.
I'm not sure how to do what the blogpost describes with the new InstanceProducer. InstanceProducer has a static method FromExpression but I'm not sure which type etc. should be used.
I currently do Pure DI and have the following settings:
// Settings
var conLocal = ConfigurationManager.ConnectionStrings["APIPortMan"].ConnectionString;
var con = ConfigurationManager.ConnectionStrings["PortMan"].ConnectionString;
var conAzure = ConfigurationManager.ConnectionStrings["Azure"].ConnectionString;
var conSitecore = ConfigurationManager.ConnectionStrings["Sitecore"].ConnectionString;
var azureStorageAccount = ConfigurationManager.AppSettings.Get("StorageConnection");
var reportUploadPath = ConfigurationManager.AppSettings.Get("ReportUploadPath");
var PfsmlPath = ConfigurationManager.AppSettings.Get("PfsmlPath");
var reloadCounter = int.Parse(ConfigurationManager.AppSettings.Get("transactionServiceReloadCounter"));
var systemStartDate = DateTime.Parse(ConfigurationManager.AppSettings.Get("holdingServiceStartDate"));
var semaphoreCount = int.Parse(ConfigurationManager.AppSettings.Get("semaphoreCount"));
Then I have some repositories consuming these settings:
// Repositories
var _accountRepository = new AccountRepository(con, conAzure);
var _aggregatedPortfolioRelationshipRepository = new AggregatedPortfolioRelationshipRepository(conAzure);
var _aggregatedClientRelationshipRepository = new AggregatedClientRelationshipRepository(con, conAzure);
var _assetBondRepository = new AssetBondRepository(con, conAzure);
var _assetClassRepository = new AssetClassRepository(con, conAzure);
var _assetDerivativeRepository = new AssetDerivativeRepository(con, conAzure);
var _assetRepository = new AssetRepository(con, conAzure);
var _benchmarkRepository = new BenchmarkRepository(con, conAzure);
var _benchmarkWeightRepository = new BenchmarkWeightRepository(con, conAzure);
var _clientRepository = new ClientRepository(con, conAzure);
var _defaultPriceRepository = new DefaultPriceRepository(con, conAzure);
var _emailRepository = new UpdateEmailOutput(conAzure);
var _exchangeRateRepository = new ExchangeRateRepository(con, conAzure);
var _failedHoldingRepository = new FailedHoldingRepository(conLocal);
var _GICSRepository = new GICSRepository(con, conAzure);
var _holdingRepository = new HoldingRepository(conAzure);
var _limitLineRepository = new LimitLineRepository(con, conAzure);
var _PFSMLRepository = new PFSMLRepository(PfsmlPath);
var _portfolioRepository = new PortfolioRepository(con, conAzure);
var _sitecoreReportRepository = new SitecoreReportRepository(conSitecore, reportUploadPath);
var _systemInfoRepository = new SystemInfoRepository(conAzure);
var _transactionRepository = new TransactionRepository(con, conAzure);
And later some services consuming the repositories and a few of the settings.
Since most of the repositories share a common interface IRepository<T> (besides an individual interface like IAssetRepository that extends IRepository with the type Asset) I would like to be able to use batch creation /auto-wiring. Also I would like to avoid changing the DI setup every time a change is made to my main code (ie. new constructor parameter, new repository interface/class etc.). Also I would like to avoid using lambda's, "new" and getInstance in the registration process because this will require changes to the DI setup whenever I change a constructor.
I have already adopted the convention mentioned in the blogpost (using AzureConnectionString, PortManConnectionString etc.) in the constructors. All I need to do now is make sure Simple Injector handles value type parameters according to the conventions :)
I posted the same question on Github (as Steven noted).
https://github.com/simpleinjector/SimpleInjector/blob/v4.0.x/src/SimpleInjector.CodeSamples/ParameterConventionExtensions.cs contains an updated version of the convention-based approach although Steven/dotnetjunkie convinced me to take a different approach (using settings-objects).

C# Ninject to Structure map converter

In ninject I have code like this:
var resourceManagers = new ResourceManager[1];
resourceManagers[0] = Validation.ResourceManager;
kernel.Bind<ILocalizedStringProvider>().To<ResourceStringProvider>()
.WithConstructorArgument("resourceManager", resourceManagers);
kernel.Rebind<ModelValidatorProvider>().To<LocalizedModelValidatorProvider>();
I want to convert this to StructureMap
I did like this:
IContainer container = new Container();
var ioC = new IoC();
ioC.Initialize(container);
container.Configure(x =>
{
var resourceManagers = new ResourceManager[1];
resourceManagers[0] = ModelValidation.ResourceManager;
x.For<ILocalizedStringProvider>().Use<ResourceStringProvider>.Ctor<string>(#"resourceManager").Is(resourceManagers);
x.For<ModelValidatorProvider>().Add<LocalizedModelValidatorProvider>();
});
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver(container);
but I get exception:
Severity Code Description Project File Line Suppression State
Error CS0119 'CreatePluginFamilyExpression.Use()'
is a method, which is not valid in the given context
How to do this with StructureMap?
Use () because is a method
var resourceManagers = new ResourceManager[1];
resourceManagers[0] = ModelValidation.ResourceManager;
x.For<ILocalizedStringProvider>().Use<ResourceStringProvider>().Ctor<ResourceManager[]> (#"resourceManager").Is(resourceManagers);
x.For<ModelValidatorProvider>().Add<LocalizedModelValidatorProvider>();
As the error message says, this:
.Use<ResourceStringProvider>
Should be:
.Use<ResourceStringProvider>()
Because it is a method.

The calling of an instance method by using reflection throws TargetException.

I have MyServiceLibrary.dll which represents few classes such as UserStorageService, Storage, User. The service contains a storage and saves users into storage.
I created a new console application with new application domain inside it.
AppDomain masterDomain = AppDomain.CreateDomain("servicedomain");
string serviceLibraryPath = #"G:\Git\Service";
Assembly serviceAssembly = Assembly.LoadFrom(serviceLibraryPath);
Here I get all types which I use.
Type userType = serviceAssembly.GetType("MyServiceLibrary.User");
Type storageType = serviceAssembly.GetType("MyServiceLibrary.UserStorage");
Type userStorageServiceType = serviceAssembly.GetType("MyServiceLibrary.UserStorageService");
New instances of these types were creted into masterDomain.
var storage = masterDomain.CreateInstanceFromAndUnwrap(serviceLibraryPath, storageType.FullName);
var user = masterDomain.CreateInstanceFromAndUnwrap(serviceLibraryPath, userType.FullName);
var userStorageService = masterDomain.CreateInstanceFromAndUnwrap(
serviceLibraryPath, // assemblyFile
userStorageServiceType.FullName, // typeName
false, // ignoreCase
BindingFlags.CreateInstance, // bindingAttr
default(Binder), // binder
new object[] {storage}, // args
CultureInfo.CurrentCulture, // culture
new object[] {} // activationAttributes
);
All of my types which I used were inherited from MarshalByRefObject class.
Now I want to add my new user.
MethodInfo addMethod = userStorageServiceType.GetMethod("Add");
addMethod.Invoke(userStorageService, new object[] { user });
I got an exception:
TargetException: The object does not match the target type.
In logfile I saw that the instance of UserStorageService was created. I can call a static method of this class, but instance methos don't work.
did you try using GetType to be sure you reflected the exact type?
userStorageService.GetType().GetMethod("Add")

devdefined OAuth IConsumerRequest error

I'm getting this error:
"For the RSASSA-PKCS1-v1_5 signature method you must use the constructor which takes an additional AssymetricAlgorithm "key" parameter"
when I try to make a request with my IOAuthSession object.
I assume its referring to IOAuthSession constructor but IOAuthSession doesn't have a "key" parameter in the constructor.
Here's my code:
IOAuthSession consumerSession = new OAuthSession(consumerContext, requestTokenUrl, UserAuthoriseUrl, accessTokenUrl);
IConsumerRequest getOrganisationRequest = consumerSession
.Request()
.ForMethod("GET")
.ForUri(new Uri("https://api.xero.com/api.xro/2.0/Organisation"))
.SignWithToken(accessToken);
Any Help will be much appretiated.
I think that error message is wrong, there is no constructor overload that takes a key.
That said I believe what's wrong is you are failing to assign the key to the consumer context:
You should have something like this:
var consumerContext = new OAuthConsumerContext
{
ConsumerKey = "weitu.googlepages.com",
SignatureMethod = SignatureMethod.RsaSha1,
Key = certificate.PrivateKey // this is what you're missing
};
IOAuthSession consumerSession = new OAuthSession(consumerContext, requestTokenUrl, UserAuthoriseUrl, accessTokenUrl);
...
Let me know if that helps.

Is there a way to build a new type during Runtime?

I am going to ask a question that might sound weird.
Is there a way to build a new class during Runtime? Or at least, add a new property to an existing class.
I mean creating a class that doesn't exist and not an instance of an existing class. I could later on use reflections to load and use this class.
Adding a property to an existing type is not possible, but you can create a new type at runtime using Reflection.Emit. It's pretty complicated stuff, and it goes something like this:
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
assemblyName , AssemblyBuilderAccess.Run, assemblyAttributes);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"MyNamespace.TypeName" , TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Add a method
newMethod = typeBuilder.DefineMethod("MethodName" , MethodAttributes.Public);
ILGenerator ilGen = newMethod.GetILGenerator();
// Create IL code for the method
ilGen.Emit(...);
// ...
// Create the type itself
Type newType = typeBuilder.CreateType();
This code is just a sample. It could contain errors.
You can also generate classes by compiling C# source code at runtime using System.CodeDom, but I don't know a lot about that.
Take a look at the System.Reflection.Emit namespace. I've never used it myself but the classes in this namespace can be used to generate IL (intermediate language).
This is not a weird question - in some cases it might be very useful. For instance I use this technique for performance tests sometimes:
public static Type[] DynamicTypes;
public void CreateObjects()
{
var codeNamespace = new CodeNamespace( "DynamicClasses" );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System" ) );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System.ComponentModel" ) );
for( var i = 0; i < 2000; i++ )
{
var classToCreate = new CodeTypeDeclaration( "DynamicClass_" + i )
{
TypeAttributes = TypeAttributes.Public
};
var codeConstructor1 = new CodeConstructor
{
Attributes = MemberAttributes.Public
};
classToCreate.Members.Add( codeConstructor1 );
codeNamespace.Types.Add( classToCreate );
}
var codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add( codeNamespace );
var compilerParameters = new CompilerParameters
{
GenerateInMemory = true,
IncludeDebugInformation = true,
TreatWarningsAsErrors = true,
WarningLevel = 4
};
compilerParameters.ReferencedAssemblies.Add( "System.dll" );
var compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom( compilerParameters, codeCompileUnit );
if( compilerResults == null )
{
throw new InvalidOperationException( "ClassCompiler did not return results." );
}
if( compilerResults.Errors.HasErrors )
{
var errors = string.Empty;
foreach( CompilerError compilerError in compilerResults.Errors )
{
errors += compilerError.ErrorText + "\n";
}
Debug.Fail( errors );
throw new InvalidOperationException( "Errors while compiling the dynamic classes:\n" + errors );
}
var dynamicAssembly = compilerResults.CompiledAssembly;
DynamicTypes = dynamicAssembly.GetExportedTypes();
}
You might take a look at the System.CodeDom namespace. According to one of the pages linked from there:
The .NET Framework includes a mechanism called the Code Document Object Model (CodeDOM) that enables developers of programs that emit source code to generate source code in multiple programming languages at run time, based on a single model that represents the code to render.
I'm not at all an expert in this, I just remembered seeing it on my .NET Framework poster on my wall. :)
Edit: Since writing this answer, I have played with System.CodeDom a bit. I've written a blog post that uses some basic CodeDom that may help those wanting to get started with it.

Categories