Autofac SingleInstance not working - singleton

I am trying to get a Singleton instance working with Autofac. I'm kind of doing a quasi-mvvm type thing with Winforms, just an experiment so don't get to hung up on that. But I am trying you have my model be a single instance with a reference in a command (ICommand here is not the WPF variety):
I have the following setup of a container:
var cb = new ContainerBuilder();
cb.RegisterType<CalculateCommissionCommand>().As<ICommand<TradeEntry>>().SingleInstance();
cb.RegisterType<CalculationsModel>().As<ICalculationsModel>().SingleInstance();
cb.Register(c => new CalculationsView() { Model = c.Resolve<ICalculationsModel>() }).SingleInstance();
cb.Build();
Now the Command takes an ICalculationsModel as a constructor parameter. However, when I set a value in the Model being passed to the Command, that value does not appear within the model that has already been set withing the CalculationsView. It seems that the command and the view are being passed different instances of the CalculationsModel despite the "singleInstance" method being called. Am I missing something? Why is this happening?

We hit a similar problem today and this seems to be the only post where this question is asked, so I thought I'd share our experience in the hopes it helps someone out. In the end it was something right in front of our eyes and of course they're usually the hardest problems to solve :-).
In our scenario, we were:
Registering a specific implementation of a configuration provider
Auto-registering certain types within an assembly.
Something along these lines:
var cb = new ContainerBuilder();
cb.RegisterType<FileBasedConfigurationProvider>()
.As<IConfigurationProvider>()
.SingleInstance();
cb.RegisterAssemblyTypes(typeof(MailProvider).Assembly)
.Where(t => !t.IsAbstract && t.Name.EndsWith("Provider"))
.AsImplementedInterfaces();
Stupidly, we didn't think about/realise that the FileBasedConfigurationProvider was in the same assembly as the MailProvider, so the second registration call basically overwrote the first one; hence, SingleInstance "wasn't working".
Hope that helps someone else out!

It's not clear from your code how you are storing/using the container. It is likely you have created multiple containers.

In my case the problem was that the parameter to the method generating the second instance was defined as the class instead of the interface
i.e.
SomeMethod(ClassName parameter)
instead of
SomeMethod(**I**ClassName parameter)
Obvious mistake, but took a few minutes to see it.

In my case I had two registrations for a class for different interfaces declaring that each was single instance. I assumed there would be a single instance of the class... no there's a single instance for each registration.
e.g
builder.RegisterType<MyClass>().As<IMyFirstInterface>().SingleInstance(); // 1st instance
builder.RegisterType<MyClass>().As<IMySecondInterface>().SingleInstance(); // 2nd instance
The correct way to do this was...
builder
.RegisterType<MyClass>()
.As<IMyFirstInterface>()
.As<IMySecondInterface>()
.SingleInstance();

Related

Dynamic model attribute with SAILSJS

My use case needs me to use Dynamic Model attributes with my Sails.Js project and all of my methods fail. First I tried to call model1 method from model2 but it doesn't works. I also tried to use global variables but this fails too because, the global is set after the load of the application, and finaly I called model1Controller from the model2 but it still not working.
This is the mothod in my model2Controller
getbyTable:function(req,res){
let field = Field.find({fTable:req.param('tableName')});
field.exec(function(err, response) {
if(err) {
res.status(500);
return res.view('500', {data: err});
}
//res.json(response);
return response;
});
},
And this is my model2
'use strict';
const fieldController = require('../controllers/Model1Controller');
const donnees = fieldController.getbyTable('person');
module.exports={
}
When run it fires as error that req.param is not a function.
Need help!!! Thanks.
This looks like an interesting way to organize - I'd be curious to see how successful a project could be without Model attributes set in stone.
I can see a few specific errors in your code, maybe seeing them will help you move forward.
From your model2 you invoke getbyTable('person') with a string argument - but all controller methods are really intended to have reqest/response arguments (as in the definition getbyTable(req, res). Directly invoking a controller method is a bit unusual - if you ever did it, I'd expect to pass along a request and response from some other controller method.
Inside getbyTable, you try to return the response, but the response is only defined inside the exec callback. The response would be an array of objects fetched from your database - if that's what you need, you can't return them directly since database calls are async.
Your controller should probably do something with res in all logical branches, such as res.json, res.send, etc.
It's a bit hard to see exactly what you're trying to achieve, so maybe if you could explain the goal I could have some more relevant advice. For now, I could say that you might want to consider putting some code inside a service rather than a controller. Create file /api/services/MyService.js and use it to export a method that can be called from your model2 (you can require the service just like the controller). Keep the controller methods strictly for handling requests.
Good luck.

How can you use SessionAsSigner in a Java Bean called from an XPage?

According to Phillip Riand (see: discussion on openNTF) this is not possible... They need to know the design element to find out who signed it. Therefore, it is only available in SSJS.
There are 2 ways that I know of to use the sessionAsSigner object in Java beans:
1 By resolving the sessionAsSigner object:
FacesContext context = FacesContext.getCurrentInstance();
Session sessionAsSigner = context.getApplication().getVariableResolver().
resolveVariable(context, "sessionAsSigner");
2 By using the getCurrentSessionAsSigner() function from the com.ibm.xsp.extlib.util.ExtLibUtil class in the Extension Library.
To be able to use it (in Java as wel as SSJS) you'll want to make sure that all design elements were signed by the same user ID. If that's not the case, the sessionAsSigner object will not be available ('undefined').
I found that the solution is right at hand :-)
I changed my XPage (in this example an XAgent) to:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
This is an xAgent returning json data...
<xp:this.afterRenderResponse><![CDATA[#{javascript:Controller.verify(sessionAsSigner)}]]></xp:this.afterRenderResponse>
and in the bean I simply used the session in the argument when I needed to open a database/document as signer. Sometimes the solution is so simple :-)
/John
This is quite an old post that I just stumbled upon. Tried some of the solutions mentioned above:
resolveVariable did not work for me, at least not for sessionAsSigner as this throws a runtime error (I can resolve plain old session, though...)
to be honest I didn't quite understand the Controller.verify(sessionAsSigner) method; is Controller something specific to XAgents? If so, I don't have an XAgent here, so can't use it
didn't feel like importing extra ExtLib classes here...
So I came up with another solution that appears to be very simple:
created a method in my javaBean that takes a session object as argument; since sessionAsSigner belongs to the same class as session I don't have to import something new.
Javacode is:
public void testSession(Session s) throws Exception{
System.out.println(" > test effective user for this session = "
+ s.getEffectiveUserName());
}
This is called from SSJS as either
mybean.testSession(session);
or
myBean.testSession(sessionAsSigner);
Maybe helps others, too

Unable to determine the identity of domain using System.IO.Packaging

I am getting "Unable to determine the identity of domain" when using System.IO.Packaging through COM Interop, there are a few articles describing why this is happening and the solution is to run the offending function in its own AppDomain.
So I took the sample code, which looks like the below but I still get the error, I am wondering what i am doing wrong and also, with VS 2010 it says AddAssembly and AddHost are obsolete - I wonder if that means they are no longer implemented, but if thats the case I dont really understand how to use the new methods (AddAssemblyEvidence and AddHostEvidence)??
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
evidence.AddAssembly(Assembly.GetExecutingAssembly().FullName);
evidence.AddHost(new Zone(SecurityZone.MyComputer));
AppDomain domain = AppDomain.CreateDomain("BlobPackage", evidence, setup);
BlobPackage blob_interal = (BlobPackage)domain.CreateInstanceAndUnwrap(typeof(BlobPackage).Assembly.FullName, typeof(BlobPackage).FullName);
blob_interal.pack(FilePath, RootPath, m_source_files); <-- STILL FAILS
AppDomain.Unload(domain);
I solved this one myself, I forgot to inherit my class from MarshalByRefObject.
Its a bit stupid, it allows you to create an instance and call it except its still running in the default domain, you would think it would throw an exception or something, anyway by marking the class as [Serializable()] and deriving from MarshalByRefObject fixes it.

Ninject: More than one matching bindings are available

I have a dependency with parameters constructor. When I call the action more than 1x, it show this error:
Error activating IValidationPurchaseService
More than one matching bindings are available.
Activation path:
1) Request for IValidationPurchaseService
Suggestions:
1) Ensure that you have defined a binding for IValidationPurchaseService only once.
public ActionResult Detalhes(string regionUrl, string discountUrl, DetalhesModel detalhesModel)
{
var validationPurchaseDTO = new ValidationPurchaseDTO {...}
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
...
}
I'm not sure what are you trying to achieve by the code you cited. The error is raised because you bind the same service more than once, so when you are trying to resolve it it can't choose one (identical) binding over another. This is not how DI Container is supposed to be operated. In your example you are not getting advantage of your DI at all. You can replace your code:
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
With this:
this.ValidationPurchaseService = new ValidationPurchaseService(validationPurchaseDTO:validationPurchaseDTO, confirmPayment:true)
If you could explain what you are trying to achieve by using ninject in this scenario the community will be able to assist further.
Your KernelFactory probably returns the same kernel (singleton) on each successive call to the controller. Which is why you add a similar binding every time you hit the URL that activates this controller. So it probably works the first time and starts failing after the second time.

How do I utilize a named instance within the ObjectFactory.Initialize call for StructureMap?

I am trying to do the following bootstrapping:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
x.For(Of IErrorLogger).Add(
Function()
Return New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
End Function).Named("Disk")
But it shows this error:
StructureMap Exception Code: 200
Could not find an Instance named "Disk" for PluginType Logging.IErrorLogger
I sort of understand why this is happening.. the question is, how do I utilize a named instance within the registry? Maybe something like lazy initialization for the ctor argument for the SQLErrorLogger? I am not sure how to make it happen.
Thanks in advance for any help you can provide.
I found the correct way to do it in the latest version (2.6.1) of StructureMap:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(
Function(c) c.ConstructedBy(Function() ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
)
x.For(Of IErrorLogger).Add(Function() _
New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
).Named("Disk")
Notice for the Is method of Ctor, we need to provide a func(IContext), and use the IContext.ConstructedBy(Func()) to call ObjectFactory.Get... to successfully register the IErrorLogger in this case.
This is the only way to do it as far as I know. The other Icontext methods such as IsThis and Instance will only work with already registered type.
Your problem is that you are trying to access the Container before it's configured. In order to make structuremap evaluate the object resolution after the configuration you need to provide a lambda to the Is function. The lambda will be evaluated when trying to resolve the type registered.
x.[For](Of ILogger)().Add(Of SqlLogger)().Ctor(Of ILogger)("backupErrorLogger")_
.[Is](Function(context) context.GetInstance(Of ILogger)("Disk"))
x.[For](Of ILogger)().Add(Of DiskLogger)().Ctor(Of String)("errorFileName")_
.[Is](CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))_
.Named("Disk")
Disclaimer: I'm not completely up-to-date with the lambda syntax in VB.NET, but I hope I got it right.
Edit:
The working C# version of this I tried myself before posting was this:
ObjectFactory.Initialize(i =>
{
i.For<ILogger>().Add<SqlLogger>()
.Ctor<ILogger>("backup").Is(
c => c.GetInstance<ILogger>("disk"))
.Named("sql");
i.For<ILogger>().Add<DiskLogger>().Named("disk");
});
var logger = ObjectFactory.GetNamedInstance<ILogger>("sql");