OK, I'm trying to set a property on a type I'm registering with SM.
Here's the code from the registry in one of my components. This
registry is being added during the configuration from a console app.
When I try to access the EndorsementSpecs property of the instance
AutoMandatoryEndorsementAggregator object, I get the 202. What's
interesting is that I can call
GetAllInstances>() from my
console app and it resolves just fine. Is there something about
accessing this code from within OnCreation that is causing the 202? I
can see everything I expect in WhatDoIHave(). I've also tried a TypeInterceptor with the same results.
//register all open generics
cfg.ConnectImplementationsToTypesClosing(typeof
(MandatoryEndorsementSpecBase<>));
ForSingletonOf<IMandatoryEndorsementAggregator<AutoPolicy>>()
.Use<AutoMandatoryEndorsementAggregator>()
.OnCreation((context, x) =>
{
var specs =
context.GetAllInstances<MandatoryEndorsementSpecBase<AutoPolicy>>();
x.EndorsementSpecs = specs;
})
;
Sorry to deflect your real questions, but are you just trying to inject all instances of MandatoryEndorsementSpecBase into AutoMandatoryEndorsementAggregatory?
If so, you can probably get away with just making it a constructor parameter so that they are all automatically injected.
public AutoMandatoryEndorsementAggregatory(MandatoryEndorsementSpecBase<AutoPolicy>[] endorsementSpecs){
EndorsementSpecs = endorsementSpecs;
}
Related
I'm trying to avoid referencing the concrete type library in my main project, but I'm getting this error:
No default instance or named instance 'Default' for requested plugin type StackExchangeChatInterfaces.IClient
1.) Container.GetInstance(StackExchangeChatInterfaces.IClient ,{username=; password=; defaultRoomUrl=; System.Action`2[System.Object,System.Object]=System.Action`2[System.Object,System.Object]})
I've setup my container to scan for assemblies, like so:
var container = new Container(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.ExcludeNamespace("StructureMap");
scan.WithDefaultConventions();
scan.AddAllTypesOf<IMessageHandlers>();
});
//x.For<IClient>().Use<Client>(); //GetInstance will work if this line is not commented out.
});
When I try to get an instance, I get the error, my code for getting an instance is here:
chatInterface = container
.With("username").EqualTo(username)
.With("password").EqualTo(password)
.With("defaultRoomUrl").EqualTo(roomUrl)
.With<Action<object, object>>(delegate(object sender, object messageWrapper)
{
string message = ((dynamic)messageWrapper).Message;
Console.WriteLine("");
Console.WriteLine(message);
foreach (var item in messageHandlers)
{
item.MessageHandler.Invoke(message, chatInterface);
}
}).GetInstance<IClient>();
If I explicitly map the concrete class to the interface, everything works hunky dory, but that means I need to reference the project that Client is in, which I don't want to do.
This is really interesting. Looks like default conventions are not able to register types with such constructor (tried on both versions 2.6.3 and 3+). I was only registered when only parameterless constructor was specified. Looking at sources of both versions it is really suspicious as it should be registered. Deeper dive into the code would be needed...
Anyway try using custom registration convention:
public class ClientConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsClass && !type.IsAbstract && !type.IsGenericType &&
type.GetInterfaces().Contains(typeof(IClient)))
{
registry.For(typeof(IClient)).Use(type);
}
}
}
Configure it like this:
var container = new Container(
c => c.Scan(
s =>
{
s.ExcludeNamespace("StructureMap");
s.WithDefaultConventions();
s.Convention<ClientConvention>();
s.AddAllTypesOf<IMessageHandlers>();
}));
and this should work just fine.
The default type scanning will not pick up concrete types whose constructor functions contain primitive arguments like strings, numbers, or dates. The thinking is that you'd effectively have to explicitly configure those inline dependencies anyway.
"but that means I need to reference the project that Client is in, which I don't want to do."
Does that actually matter? I think you're making things harder than they have to be by trying to eliminate the assembly reference.
I am new to Android development with Xamarin.Android and I would like to understand how to have the next issue fixed.
Sometimes after restoring my Android application from background I was facing the next error:
Unable to find the default constructor on type MainMenuFragment. The MainMenuFragment is used by the application NavigationDrawerActivity to allow users to switch between different Fragments inside the app.
In order to solve it, I added a default constructor to the MainMenuFragment as described inside the next links:
Xamarin Limitations - 2.1. Missing constructors
Added a default constructor, should fix the issue.
public class MainMenuFragment : DialogFragment
{
readonly NavigationDrawerActivity navigationDrawer;
#region Constructors
public MainMenuFragment () {} // Default constructor...
public MainMenuFragment (NavigationDrawerActivity navigationDrawer, IMenuType launchMenu = null)
{
if (navigationDrawer == null)
throw new ArgumentNullException ("navigationDrawer");
this.navigationDrawer = navigationDrawer;
...
Fragment UpdateTopFragmentForCurrentMenu (Fragment newMenuRootFragment = null)
{
Fragment currentMenuRootFragment = navigationDrawer.CurrentFragment; // issued line.
But now sometime in the future, the MainMenuFragment gets initialized using its default constructor and at the first time it tries to access its navigationDrawer it throws a System.NullReferenceException:
System.NullReferenceException: Object reference not set to an instance of an object
at MainMenuFragment.UpdateTopFragmentForCurrentMenu (Android.App.Fragment) <0x00018>
at MainMenuFragment.OpenMenu (IMenuType,bool) <0x0006b>
at MainMenuFragment.OnCreate (Android.OS.Bundle) <0x00053>
at Android.App.Fragment.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x0005b>
at (wrapper dynamic-method) object.3919a6ec-60c1-49fd-b101-86191363dc45 (intptr,intptr,intptr) <0x00043>
How can I have a default constructor implemented without facing this null reference exception?
You're programming like a C# developer, thats what the problem is :) I faced these same hurdles learning monodroid.
Take a look at the examples out there, in java, you'll see almost all the time they initialize using a static method like object.NewInstance() which returns object. This is how they initialize their views/receivers/fragments. At that point they populate the Arguments property and store that in the fragment. You need to remove all your constructors EXCEPT the empty ones and use arguments to pass your data around. If you try to do this using constructors and regular oo concepts you'll be in for a world of hurt. Arguments.putExtra and all those methods are there. It makes things a little verbose but once you get the hang of it you'll start creating some helper methods etc.
Once you get that sorted, you'll need to figure out if you need to recreate your fragments everytime the activity is resumed and if not, mark them as RetainInstance = true as well as get them onto a fragmentmanager which will help you retain all your state.
If you haven't built on android before it's weird and certainly not what I expected. But it's reeaaallly cool, much more awesome than I expected too. And same with Xamarin.
Great similar question: Best practice for instantiating a new Android Fragment
When I try to register my class with autofac I get the following error: "The instance registration 'GetAllDivisionsCommand' can support SingleInstance() sharing only".
I don't understand why I'm getting this error, but assume it's something to do with the class having static member variables used for caching as that's the only thing that's different about this class. I haven't had any trouble registering any other classes as either SingleInstance or InstancePerDependency.
Essentially, the class is used to retrieve a rarely changing list of divisions from the database, and caches the result. Each time the command is run, it first checks for changes on the database and then re-runs the query if changes are detected; if not, it returns the cached list.
So I am trying to register GetAllDivisionsCommand with Autofac as an IGetAllDivisionsCommand. IGetAllDivisionsCommand itself implements IInjectableCommand, which is just a marker interface, and ICachedListCommand. The concrete command class inherits from the abstract base class CachedListCommand which is where the static member variables live.
Does anyone know what would cause this error message? SingleInstance won't work for me as I can't keep reusing the same session.
Code:
Type commandType = typeof(IInjectedCommand);
Type aCommandType = typeof(GetAllDivisions);
var commands =
from t in aCommandType.Assembly.GetExportedTypes()
where t.Namespace == aCommandType.Namespace
&& t.IsClass
&& !t.IsAbstract
&& (commandType.IsAssignableFrom(t))
let iface = t.GetInterfaces().FirstOrDefault(x => "I" + t.Name == x.Name)
select new { Command = t, Interface = iface };
foreach (var cmd in commands)
{
builder.RegisterInstance(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
RegisterInstace as the name implies is for registering instances not types.
What you need is RegisterType:
foreach (var cmd in commands)
{
builder.RegisterType(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
And by the way with the Autofac scanning feature your registration code is roughly equivalent:
builder
.RegisterAssemblyTypes(aCommandType.Assembly)
.AssignableTo<IInjectedCommand>()
.InNamespace(aCommandType.Namespace)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
In my case, I did want RegisterInstance because I actually have an instance in hand that I wanted to register.
I had
builder.RegisterInstance(myInstance).InstancePerDependency();
The documentation for InstancePerDependency reads:
Configure the component so that every dependent component or call to
Resolve() gets a new, unique instance (default.)
On closer inspection, it makes sense that registering an instance with "instance per dependency" is not possible, since it is not possible for Autofac to give back a new instance each time Resolve is called if there is in fact 1 instance registered.
So, in my case, the solution was this.
builder.RegisterInstance(myInstance).SingleInstance();
The Autofac exception could possibly have been worded more clearly to explain this problem.
In the C# language, using StructureMap 2.5.4, targeting .NET Framework 3.5 libraries.
I've taken the step to support multiple Profiles in a structure map DI setup, using ServiceLocator model with Bootstrapper activation. First setup was loading default registry, using the scanner.
Now I like to determine runtime what Registry configuration I like to use. Scanning and loading multiple assemblies with registries.
Seems it's not working for the actual implementation (Getting the 202, default instance not found), but a stripped test version does work. The following setup.
Two assemblies containing Registries and implementations
Scanning them in running AppDomain, providing the shared Interface, and requesting Creation Of Instance, using the interfaces in constructor (which get dealt with thanx to the profile on Invokation)
Working code sample below (same structure for other setup, but with more complex stuff, that get's a 202):
What type of couses are possible for a 202, specifically naming the System.Uri type, not being handles by a default type?? (uri makes no sense)
// let structure map create instance of class tester, that provides the registered
// interfaces in the registries to the constructor of tester.
public class Tester<TPOCO>
{
private ITestMe<TPOCO> _tester;
public Tester(ITestMe<TPOCO> some)
{
_tester = some;
}
public string Exec()
{
return _tester.Execute();
}
}
public static class Main {
public void ExecuteDIFunction() {
ObjectFactory.GetInstance<Tester<string>>().Exec();
}
}
public class ImplementedTestMe<TSome> : ITestMe<TSome>
{
public string Execute()
{
return "Special Execution";
}
}
public class RegistryForSpecial : Registry
{
public RegistryForSpecial()
{
CreateProfile("Special",
gc =>
{
gc.For(typeof(ITestMe<>)).UseConcreteType(typeof(ImplementedTestMe<>));
});
}
}
Background articles on Profiles I used.
How to setup named instances using StructureMap profiles?
http://devlicio.us/blogs/derik_whittaker/archive/2009/01/07/setting-up-profiles-in-structuremap-2-5.aspx
http://structuremap.sourceforge.net/RegistryDSL.htm
EDIT:
It seemed the missing interface was actually the one being determined runtime. So here is the next challange (and solved):
I provided a default object whenever StructureMap needs to create the object. Like:
x.ForRequestedType<IConnectionContext>()
.TheDefault.Is.Object(new WebServiceConnection());
This way I got rid of the 202 error, because now a real instance could be used whever structure map needed the type.
Next was the override on runtime. That did not work out at first using the ObjectFactory.Configure method. Instead I used the ObjectFactory.Inject method to overide the default instance. Works like a charm.
ObjectFactory.Inject(typeof(IConnectionContext), context);
Loving the community effort.
Error code 202 means a default instance could not be built for the requested type. Your test code is apparently not equal to your real code that fails. If you are getting an error about Uri, you likely have a dependency that requires a Uri in its constructor. It may not be the class you are asking for - it may be one of that classes dependendencies - or one of the dependencies dependencies... somewhere down the line someone is asking StructureMap to resolve a Uri, which it cannot do, without some help from you.
I have this configuration in my GeneralRegistry:
ForRequestedType<IClientBonusHistoryLoadTask>().AlwaysUnique().TheDefaultIsConcreteType<ClientBonusHistoryLoadTask>();
And I have this code:
public ClientAdvantagesUpdateTask(IBaseRepo<Client> repository, INHUnitOfWorkProvider uowProvider, IClientBonusHistoryLoadTask clientBonusHistoryLoadTask, ClientBonusHistoryLoadTask masterClientBonusHistoryLoadTask) : base(repository, uowProvider)
{
_clientBonusHistoryLoadTask = clientBonusHistoryLoadTask;
_masterClientBonusHistoryLoadTask =
masterClientBonusHistoryLoadTask;
bool y = clientBonusHistoryLoadTask.Equals
(masterClientBonusHistoryLoadTask);
var task = ObjectFactory.GetInstance<IClientBonusHistoryLoadTask>
();
var task2 =
ObjectFactory.GetInstance<IClientBonusHistoryLoadTask>();
bool x = task.Equals(task2);
}
For some reason, y is true (which is the problem) and x is false
(which works as expected). Is this a bug, or am I doing something
wrong?
Hi I have the same problem, always unique is not making it always unique.
but there is little documentation to know what it is supposed to do.
I use the following:
For<ILeadRepository>().Use<LeadRepository>();
and then inside an object factory method:
LeadRepository instance = ioc.GetInstance<LeadRepository>();
ioc.Inject(typeof(ILeadRepository), instance);
ioc.Inject(typeof(LeadRepository), instance);
where ioc is an IContainer.
Again, I am not sure Inject is supposed to be used like that, but this always pulls the same
instance of LeadRepository out the ioc container after the inject code was run.
Hope this helps or somebody could post on how it is supposed to be done.
I dont like using static factories or static methods, so i made my own factory and everything inside this factory pulls out unique instances out the ioc container, using the code above.
Assuming you want a unique instance, that is a singleton per factory.
and you always want the same instance returned. I found a better way to do this and that is to use subcontainers in the factory:
e.g.
myParentContainer = new Container(x => {
x.AddRegistry<ObjectFactoryModelRegistry>();
x.AddRegistry<ServiceRegistry>();
});
myIoc = myParentContainer.GetNestedContainer();
myIoc.AssertConfigurationIsValid();
then can get same instance by using code below:
myIoc.GetInstance<T>;