I tried to reconstruct the problem in LinqPad:
/*
“Named and Keyed Services”
http://autofac.readthedocs.org/en/latest/advanced/keyed-services.html
*/
const string A = "a";
const string B = "b";
const string MyApp = "MyApp";
void Main()
{
var builder = new ContainerBuilder();
builder
.RegisterType<MyClassA>()
.As<IMyInterface>()
.InstancePerLifetimeScope()
.Keyed<IMyInterface>(A);
builder
.RegisterType<MyClassB>()
.As<IMyInterface>()
.InstancePerLifetimeScope()
.Keyed<IMyInterface>(B);
builder
.RegisterType<MyAppDomain>()
.Named<MyAppDomain>(MyApp);
var container = builder.Build();
var instance = container.ResolveKeyed<IMyInterface>(A);
instance.AddTheNumbers().Dump();
var myApp = container.ResolveNamed<MyAppDomain>(MyApp);
myApp.Dump();
}
interface IMyInterface
{
int AddTheNumbers();
}
class MyClassA : IMyInterface
{
public int AddTheNumbers() { return 1 + 2; }
}
class MyClassB : IMyInterface
{
public int AddTheNumbers() { return 3 + 4; }
}
class MyAppDomain
{
public MyAppDomain([WithKey(A)]IMyInterface aInstance, [WithKey(B)]IMyInterface bInstance)
{
this.ANumber = aInstance.AddTheNumbers();
this.BNumber = bInstance.AddTheNumbers();
}
public int ANumber { get; private set; }
public int BNumber { get; private set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendFormat("ANumber: {0}", this.ANumber);
sb.AppendFormat(", BNumber: {0}", this.BNumber);
return sb.ToString();
}
}
when MyApp is “dumped” I am seeing ANumber: 7, BNumber: 7 which tells me that WithKey(A) is not returning the expected instance. What am I doing wrong here?
Looks like you forgot to register the consumers using WithAttributeFilter which is what allows this to work. Like:
builder.RegisterType<ArtDisplay>().As<IDisplay>().WithAttributeFilter();
Related
I am new to write Apex test class. Can anyone help me or suggest how to start writing apex text. Below is my Apex Class
public class RadioBtn_SmileyTable_Apex
{
public RB_Rating__c ratobj {get;set;}
public user lgflag {get;set;}
public string Selected {get;set;}
public string EnteredText {get;set;}
public string Redirect {get;set;}
public string QAppname {get;set;}
public string Qimprove {get;set;}
public RadioBtn_SmileyTable_Apex()
{
QAppname = 'How satisified you are with '+getAppName();
Qimprove = 'How could we improve?';
}
Public void SelectedAnswer()
{
Selected = Apexpages.currentPage().getParameters().get('conid');
}
public pagereference savefeedback()
{
system.debug('Submit Started : '+ Redirect);
RB_Rating__c ratobj = new RB_Rating__c();
ratobj.Application_Name__c = getAppName();
if(string.isBlank(Redirect))
{
ratobj.Application_Rating__c = Selected;
}
else
{
ratobj.Application_Rating__c = Redirect;
}
ratobj.Description__c = EnteredText;
insert ratobj;
updateflgusertb();
return Auth.SessionManagement.FinishLoginflow('/'+ratobj.Id);
}
public static void updateflgusertb()
{
List<user> userupdate = new List<user>();
for(user usr : [SELECT id,Login_Flows_YN__c FROM USER WHERE ID = :UserInfo.getUserId() LIMIT 1])
{
usr.Login_Flows_YN__c = true;
userupdate.add(usr);
}
update userupdate;
}
public pagereference feedbackexit()
{
updateexitcount();
return Auth.SessionManagement.FinishLoginflow('/');
}
public void updateexitcount()
{
integer exitcnt;
List<user> updatecnt = new List<user>();
for(user cnt : [SELECT Rating_Exit_Count__c FROM USER WHERE ID = :UserInfo.getUserId() LIMIT 1])
{
if (cnt.Rating_Exit_Count__c == null)
{
cnt.Rating_Exit_Count__c = 0;
}
exitcnt = Integer.valueOf(cnt.Rating_Exit_Count__c) + 1;
cnt.Rating_Exit_Count__c = exitcnt;
updatecnt.add(cnt);
}
update updatecnt;
if (exitcnt ==3)
{
insertzerorating();
}
}
public pagereference loginflowsexornot()
{
lgflag =[SELECT Login_Flows_YN__c FROM USER WHERE ID = :UserInfo.getUserId() LIMIT 1];
if (lgflag.Login_Flows_YN__c == true)
{
return Auth.SessionManagement.FinishLoginflow('/');
}
else
{
return null;
}
}
public pagereference redirect()
{
PageReference pg = new PageReference('/apex/Slider_Rating_Redir_VF?retURL='+Selected);
Redirect = ApexPages.currentPage().getparameters().get('retURL');
pg.setRedirect(false);
return pg;
}
public static String getAppName()
{
UserAppInfo userAppInfo = [SELECT Id, AppDefinitionId FROM UserAppInfo WHERE UserId = :UserInfo.getUserId() LIMIT 1];
AppDefinition appDefinition = [SELECT DurableId, Label FROM AppDefinition Where DurableId = :userAppInfo.AppDefinitionId LIMIT 1];
return appDefinition.Label;
}
public pagereference insertzerorating()
{
RB_Rating__c ratobjZero = new RB_Rating__c();
ratobjZero.Application_Name__c = getAppName();
ratobjZero.Application_Rating__c = '0';
ratobjZero.Description__c = EnteredText;
insert ratobjZero;
updateflgusertb();
return Auth.SessionManagement.FinishLoginflow('/'+ratobjZero.Id);
}
}
Wrote below test class. Please suggest to further:
#isTest (SeeAllData = FALSE)
public class Slider_VF_TestClass
{
public static testmethod void SliderTestClass()
{
RB_Rating__c testRBRating = new RB_Rating__c();
testRBRating.Application_Name__c = 'FoxiPedia';
testRBRating.Application_Rating__c = '9';
testRBRating.Description__c='Testing the testclass for the Rating 9';
insert testRBRating;
Test.startTest();
RadioBtn_SmileyTable_Apex smileyapex = new RadioBtn_SmileyTable_Apex();
PageReference page1 = page.Slider_Rating_VF;
Test.setCurrentPage(page1);
smileyapex.ratobj.Application_Name__c= 'FoxiPedia';
smileyapex.ratobj.Application_Rating__c = '8';
smileyapex.ratobj.Description__c = 'Testing the testclass for the Rating 9';
PageReference pageRef = smileyapex.savefeedback();
ApexPages.currentPage().getParameters().put('id',smileyapex.ratobj.Id);
Test.setCurrentPage(pageRef);
Test.stopTest();
}
}
Try to write Apex Test class. Need some sample code
So, I have values in getter setter variables when I click on form submit but now want to have those values in variables and check combination of them to run code from another java class
I have tried using parametrized constructor or may be having a common setter but that did not help.
package com.grt.dto;
import java.util.Set;
public class WDPayrollRecon {
public Set<String> dataType;
public String planCountry;
public String payPeriod;
public String currentPeriod;
public String lastPayPeriod;
Set<String> test;
public Set<String> getdataType() {
return dataType;
}
public void setdataType(Set<String> dataType) {
this.dataType = dataType;
System.out.println("this is dataType" +dataType);
test = dataType;
}
public String getPlanCountry() {
return planCountry;
}
public void setPlanCountry(String planCountry) {
this.planCountry = planCountry;
}
public String getPayPeriod() {
return payPeriod;
}
public void setPayPeriod(String payPeriod) {
this.payPeriod = payPeriod;
}
public String getCurrentPeriod() {
return currentPeriod;
}
public void setCurrentPeriod(String currentPeriod) {
this.currentPeriod = currentPeriod;
}
public String getlastPayPeriod() {
return lastPayPeriod;
}
public void setlastPayPeriod(String lastPayPeriod) {
this.lastPayPeriod = lastPayPeriod;
}
public WDPayrollRecon()
{
}
public WDPayrollRecon(Set<String> dataType,String planCountry,String payPeriod,String currentPeriod,String lastPayPeriod)
{
this.dataType = dataType;
this.planCountry = planCountry;
this.payPeriod = payPeriod;
this.currentPeriod = currentPeriod;
this.lastPayPeriod = lastPayPeriod;
if(dataType.contains("GTLI")& planCountry.equals("USA")){
System.out.println("This is test");
}
else{
System.out.println("This is not test");
}
}
}
In the code below, I am trying to inject a ViewModel into a View, while the ViewModel requires a Model to wrap and another service that is in the container. The Model is not registered as it is not really a "service".
How do I:
a) not have to provide the IService instance as an argument (let the container resolve it),
b) not have to register a factory for my ViewModels (there will be many)
So what I'm really asking the container to do is treat my Model (that I pass as an argument) as if it were a registered "service" for the duration of this call to GetInstance.
If this is not possible with LightInject, are there any containers out there that have something like this?
public static class Program
{
public static void Main()
{
var container = new LightInject.ServiceContainer();
var service = new Service1();
container.RegisterInstance<IService>(service);
// Have to register the factory
container.Register<IService, PersonModel, PersonViewModel>(
(f, s, p) => new PersonViewModel(s, p));
container.Register<View>();
var person = new PersonModel(); // this is contextual -- not a service.
object view = CreateView(container, typeof(View), service, person);
// ultimate desired code:
//var view = container.GetInstance(typeof(View), new object[] { person });
}
private static object CreateView(ServiceContainer container, Type viewType, IService service, object model)
{
var ctor = viewType.GetConstructors()[0];
var parameters = new List<object>();
foreach (var param in ctor.GetParameters())
{
var attr = param.GetCustomAttributes(typeof(ModelAttribute), false).FirstOrDefault();
if (model != null && attr != null)
{
parameters.Add(model);
}
else
{
parameters.Add(container.GetInstance(param.ParameterType, new object[] { service, model }));
}
}
return Activator.CreateInstance(viewType, parameters.ToArray());
}
}
public interface IService
{
}
public class Service1 : IService
{
}
public class PersonModel
{
}
public class PersonViewModel
{
public PersonModel PersonModel { get; set; }
public PersonViewModel(IService service, [Model] PersonModel person)
{
PersonModel = person;
}
}
public class View
{
public PersonViewModel PersonViewModel { get; set; }
public View(PersonViewModel vm)
{
PersonViewModel = vm;
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class ModelAttribute : Attribute
{
}
I have solved the issues with a combination of techniques...
a) use a Scope and register the ViewModel and View with PerScopeLifetime.
b) use a "ModelTracker" registered with a factory to allow an instance not created by the container to be injected (since models will be created by client code or a DbContext).
This combination also allows me to not register a factory for every ViewModel type -- but instead use the built-in mass registration functions (like RegisterAssembly).
public static class Program
{
public static void Main()
{
var container = new LightInject.ServiceContainer();
container.RegisterInstance<IService>(new Service1());
container.Register<View>(new PerScopeLifetime());
container.Register<PersonViewModel>(new PerScopeLifetime());
container.Register<ModelTracker>(new PerScopeLifetime());
container.Register<PersonModel>((f) => (PersonModel)f.GetInstance<ModelTracker>().Instance);
using (var scope = container.BeginScope())
{
var tracker = scope.GetInstance<ModelTracker>();
tracker.Instance = new PersonModel() { Name = "person1" };
var view = scope.GetInstance<View>();
}
}
}
public class ModelTracker
{
public object Instance { get; set; }
}
public class PersonModel
{
public string Name { get; set; }
}
public class PersonViewModel
{
private readonly IService service;
private readonly PersonModel person;
public PersonViewModel(IService service, PersonModel person)
{
this.service = service;
this.person = person;
}
}
public class View
{
public PersonViewModel PersonViewModel { get; set; }
public View(PersonViewModel vm)
{
PersonViewModel = vm;
}
}
public interface IService { }
public class Service1 : IService { }
My problem is that I want to use Func<> factory to resolve dependency. And in if I use ContainerBuilder Update() (I need it for mocking some services in integration tests), this factories still resolve outdated instances.
I created simple scenario to reproduce the problem:
class Program
{
static void Main(string[] args)
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<Test>().As<ITest>();
containerBuilder.RegisterType<Test1Factory>().As<ITestFactory>();
containerBuilder.RegisterType<TestConsumer>().AsSelf();
var container = containerBuilder.Build();
var tc1 = container.Resolve<TestConsumer>();
var cbupdater = new ContainerBuilder();
cbupdater.RegisterType<Test2>().As<ITest>();
cbupdater.RegisterType<Test2Factory>().As<ITestFactory>();
cbupdater.Update(container);
var tc2 = container.Resolve<TestConsumer>();
Console.ReadLine();
}
}
public interface ITest
{
int Id { get; set; }
}
public class Test : ITest
{
public Test()
{
Id = 1;
}
public int Id { get; set; }
}
public class Test2 : ITest
{
public Test2()
{
Id = 2;
}
public int Id { get; set; }
}
public interface ITestFactory
{
ITest Create();
}
public class Test1Factory : ITestFactory
{
public ITest Create()
{
return new Test();
}
}
public class Test2Factory : ITestFactory
{
public ITest Create()
{
return new Test2();
}
}
public class TestConsumer
{
public TestConsumer(Func<ITest> testFactory, ITest test, ITestFactory customFactory)
{
Console.WriteLine("factory: " + testFactory().Id);
Console.WriteLine("direct: " + test.Id);
Console.WriteLine("MyCustomFactory: " + customFactory.Create().Id);
Console.WriteLine("*************");
Console.WriteLine();
}
}
The output is:
factory: 1 direct: 1 MyCustomFactory: 1
factory: 1 direct: 2 MyCustomFactory: 2
Notice "factory: 1" in both cases.
Am I missing something or I have to create my cusom factory in this scenario?
P.S.
Autofac 3.5.2 or 4.0 beta 8-157
.net 4.5.1
That's by design unfortunately, the reasons, I don't know. Looking at the Autofac code gives you a better insight on how they register items with the same interface definition, in short, all registrations are maintained but the last registration wins (ref). Wait...that's not all, weirdly, for Fun<...>, you actually get them in order. You can easily test by changing the constructor of the TestConsumer class to:
public TestConsumer(Func<ITest> testFactory, IEnumerable<Func<ITest>> testFactories, IEnumerable<ITest> tests, ITest test, ITestFactory customFactory)
{
// ...
}
Note that you get all the Funcs and the ITest registration. You are simply lucky that resolving ITest directly resolves to Test2.
Now, having said all of the above, there is a way described here. You have to create a container without the registration you want to override, therefore:
/// <summary>
/// This has not been tested with all your requirements
/// </summary>
private static IContainer RemoveOldComponents(IContainer container)
{
var builder = new ContainerBuilder();
var components = container.ComponentRegistry.Registrations
.Where(cr => cr.Activator.LimitType != typeof(LifetimeScope))
.Where(cr => cr.Activator.LimitType != typeof(Func<ITest>));
foreach (var c in components)
{
builder.RegisterComponent(c);
}
foreach (var source in container.ComponentRegistry.Sources)
{
builder.RegisterSource(source);
}
return builder.Build();
}
And you can simply change your main method to the following:
static void Main(string[] args)
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<Test>().As<ITest>();
containerBuilder.RegisterType<Test1Factory>().As<ITestFactory>();
containerBuilder.RegisterType<TestConsumer>().AsSelf();
var container = containerBuilder.Build();
var tc1 = container.Resolve<TestConsumer>();
container = RemoveOldComponents(container);
var cbupdater = new ContainerBuilder();
cbupdater.RegisterType<Test2>().As<ITest>();
cbupdater.RegisterType<Test2Factory>().As<ITestFactory>();
cbupdater.Update(container);
var tc2 = container.Resolve<TestConsumer>();
Console.ReadLine();
}
PS: Wouldn't it be great to have a method which does the exact opposite of PreserveExistingDefaults()
Please explain the following behaviour.
class Base
{
public int num = 3;
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
}
class child
extends Base
{
public int num = 4;
public child()
{
}
public child(int i)
{
this.num = i;
}
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
}
public class Main
{
public static void main(String[] args)
{
Base obj2 = new child();
System.out.println(obj2.num);
System.out.println(obj2.getNum());
Base obj3 = new child(10);
System.out.println(obj3.num);
System.out.println(obj3.getNum());
}
}
Output :
3
4
3
10
Here how obj2.num and obj3.num still point to the value 3 which is assigned in the Base class instance variable. Wont it get overidded like the obj2.getNum() and obj3.getNum().
Thanks in advance.
Because the objects are declared with super class type, you get the super member variable value.
If the object was declared with sub class type, the value would be overridden value.
If the Base obj3 = new child(10); is modified to child obj3 = new child(10); the output would be 3 4 10 10
This is well explained here