getting error when validator is injected

Posts   
 
    
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 07-Apr-2008 22:50:46   

I get this error when i run the code edited for correctness: MainBusComponentConstructorTest() edited for (when it executes AddInjectionInfo it fails)

SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionInfoProvider.BeginScope(DependencyInjectionInfoStorage scopeStorage) SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionScope.BeginScope() SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionScope..ctor() DependencyScope.Components.Main.MainScope..ctor() in C:\Projects\genprodb\dependencyscope\DependencyScope.Components\Main\MainScope.cs: line 12 DependencyScope.Components.Main.MainBusComponent..ctor() in C:\Projects\genprodb\dependencyscope\DependencyScope.Components\Main\MainBusComponent.cs: line 18 DependencyScope.Components.Test.MainBusComponentTest.MainBusComponentConstructorTest() in C:\Projects\genprodb\dependencyscope\source\DependencyScope.Components.Test\MainBusComponentTest.cs: line 83


        [TestMethod()]
        public void MainBusComponentConstructorTest()
        {
            MainBusComponent target = new MainBusComponent();
            target.Mytable.Col1 = "good";
            string actual = target.Mytable.Col1;
            string expected = "good";
            Assert.AreEqual(expected, actual, "Value not equal");
            
        }
public class MainBusComponent
    {
        private MytableBusEntity _mytable;
        public MytableBusEntity Mytable
        {
            get { return _mytable; }
        }

        public MainBusComponent()
        {
            using (MainScope scope = new MainScope())
            {
                _mytable = new MytableBusEntity();
                _mytable.Col1 = "good";
            }

        }
    }
public class MainScope : DependencyInjectionScope
    {
        public MainScope()
            : base()
        { }
        protected override void InitializeScope()
        {
            AddInjectionInfo(typeof(Main.MytableEntityValidator), typeof(Main.MytableBusEntity), "Validator", DependencyInjectionTargetKind.Absolute, DependencyInjectionContextType.Singleton);
        }
public class MytableBusEntity : MytableEntity
    {
        public MytableBusEntity()
            : base()
        { 
        }
    }
    public class MytableEntityValidator : ValidatorBase
    {
        public MytableEntityValidator()
            : base()
        { }

        public override bool ValidateFieldValue(IEntityCore involvedEntity, int fieldIndex, object value)
        {
            bool successInd = base.ValidateFieldValue(involvedEntity, fieldIndex, value);
            if (successInd == false)
            {
                return false;
            }
            else
            {
                if (fieldIndex == (int)MytableFieldIndex.Col1)
                {
                    string newvalue = value as string;
                    if (newvalue == null)
                    {
                        involvedEntity.SetEntityFieldError("Col1", "Col1 is null", true);
                        successInd = false;
                    }
                    if (successInd == true)
                    {
                        if (newvalue == "yeah" | newvalue == "nope")
                        {
                            involvedEntity.SetEntityFieldError("Col1", "Col1 cannot have value yeah or nope", true);
                            successInd = false;
                        }
                    }
                }
                return successInd;
            }
        }
    }


vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 03:11:23   
public MainBusComponent()
        {
                _mytable = new MytableBusEntity();
                _mytable.Validator = new Main.MytableEntityValidator();
                _mytable.Col1 = "good";
            }

        }

the above code works & infact the validation also happens correctly. what that I might be doing here wrong in the following code line

Do i have to pass instance of Main.MytableEntityValidator.type rather than the type of the class or how to instantiate the class?

AddInjectionInfo(typeof(Main.MytableEntityValidator), typeof(Main.MytableBusEntity), "Validator", DependencyInjectionTargetKind.Absolute, DependencyInjectionContextType.Singleton);

I am using v 2.5 genPro .net 3.5 VS 2008 Professional using adapter
for sql anywhere 10.0.1.3619

thanks

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 08-Apr-2008 07:15:31   

Hi Vairam,

Please:

  • Show me your config file to see if you have some DI Information there.

  • I'm curious. Plese try use DependencyInjectionContextType.NewInstancePerTarget instead of DependencyInjectionContextType.Singleton

  • Post the LLBLGenPro runtime libraries version (http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=7725)

David Elizondo | LLBLGen Support Team
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 09:31:04   

I'm curious. Plese try use DependencyInjectionContextType.NewInstancePerTarget instead of DependencyInjectionContextType.Singleton

this didn't work.

  • Show me your config file to see if you have some DI Information there.

This didn't work.

Post the LLBLGenPro runtime libraries version

file version 2.5.08.0228 assembly version 2.5.0.0 product version 2.5.08.0228

If i don't use dependencyinjectionscope & set the validators it worked.

I was puzzled to find out where it is failing internally.

So I compiled the ORMSupportClasses source code for 20 after I changed the project target to c#3.5. And found it fails for this code as property not found.

AddInjectionInfo(typeof(Main.MytableEntityValidator), typeof(Main.MytableBusEntity), "Validator", DependencyInjectionTargetKind.Absolute, DependencyInjectionContextType.Singleton);


if I switch it to instancetype & targettype was swapped earlier.

AddInjectionInfo(typeof(Main.MytableBusEntity), typeof(Main.MytableEntityValidator),"Validator", DependencyInjectionTargetKind.Absolute, DependencyInjectionContextType.NewInstancePerTarget);

I get System.NullReferenceException: Object reference not set to an instance of an object.. error SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionInfoProvider.BeginScope(DependencyInjectionInfoStorage scopeStorage) in <ProjectPath>\ORMSupportClasses\DependencyInjectionInfoProvider.cs: line 163 SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionScope.BeginScope() in <ProjectPath>\ORMSupportClasses\DependencyInjectionScope.cs: line 98 SD.LLBLGen.Pro.ORMSupportClasses.DependencyInjectionScope..ctor() in <ProjectPath>\ORMSupportClasses\DependencyInjectionScope.cs: line 81 ....

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 08-Apr-2008 10:03:50   

As MytableBusEntity inherits from MytableEntity

Please try the following:

AddInjectionInfo(typeof(Main.MytableEntityValidator), typeof(Main.MytableBusEntity), "Validator", DependencyInjectionTargetKind.Hierarchy, DependencyInjectionContextType.Singleton); }

Or

AddInjectionInfo(typeof(MytableEntityValidator), typeof(MytableEntity), "Validator", DependencyInjectionTargetKind.Hierarchy, DependencyInjectionContextType.Singleton); }

vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 18:09:59   

AddInjectionInfo(typeof(Main.MytableEntityValidator), typeof(Main.MytableBusEntity), "Validator", DependencyInjectionTargetKind.Hierarchy, DependencyInjectionContextType.Singleton); }

Or

AddInjectionInfo(typeof(MytableEntityValidator), typeof(MytableEntity), "Validator", DependencyInjectionTargetKind.Hierarchy, DependencyInjectionContextType.Singleton); }

Test method DependencyScope.Components.Test.MainBusComponentTest.MainBusComponentConstructorTest threw exception: System.NullReferenceException: Object reference not set to an instance of an object..

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 08-Apr-2008 18:24:44   

The method you have a problem with is just 1 line: /// <summary> /// Marks the begin of a scope and therefore creates the scope data storage. /// </summary> /// <param name="scopeStorage">The scope storage to use. This scopestorage is passed in by the di scope started.</param> internal static void BeginScope(DependencyInjectionInfoStorage scopeStorage) { // push the scope onto the stack _scopeStorages.Push(scopeStorage); }

This variable is a ThreadStatic variable. This variable is set in the Init() method of the class, so for every thread a new instance is created.

I.o.w.: I have a hard time imagining how that stack could possibly be null. Especially because our tests run fine...

You also posted the wrong unittest. You posted the clinic test, while the error occurs in: MainBusComponentConstructorTest

(edit) The thing is that the DependencyInjectionProvider is a singleton, and it gets initialized by static ctors. This already should have been done when an entity class is instantiated. Apparently this isn't done in your case, the DependencyInjectionProvider's CTor (the non-static one) is never ran, which means DependencyInjectionInfoProviderSingleton is never used in code. THAT means that an entity has never been instantiated.

This could be a small bug though. In our tests, the singleton already is there, so we don't run into this issue. Could you, for testing, first request the DependencyInjectionInfoProviderSingleton.GetInstance() in your test, and then do the code you want to run in your test? That would make the stack get initialized.

AddInjectionInfo simply stores data in internal buckets in the scope till the init is done. This thus means that can't call into the callchain you posted.

The initially error you posted in the topicstart is I think indeed an edge case when nothing has been done and a scope is created -> the thread specific stack hasn't been created.

I'll try to see if I can repro it without any injection info set so it's close to your situation.

(edit) btw your classes are internal inside another class, this requires different type specifications. Make the classes normal classes (so not nested classes)

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 08-Apr-2008 18:48:27   

Ok reproduced.


        [Test]
        public void ScopeTest()
        {
            using(MainScope scope = new MainScope())
            {
                CustomerEntity c = new CustomerEntity();
                Assert.IsNotNull(c.Validator);
                Assert.AreEqual(typeof(TestValidator), c.Validator.GetType());
            }
        }
    }


    public class MainScope : DependencyInjectionScope
    {
        public MainScope()
            : base()
        { }
        protected override void InitializeScope()
        {
            AddInjectionInfo(typeof(TestValidator), typeof(CustomerEntity), 
                    "Validator", DependencyInjectionTargetKind.Absolute, DependencyInjectionContextType.Singleton);
        }
    }

    public class TestValidator : ValidatorBase
    {
        public TestValidator()
            : base()
        {
        }
    }

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 08-Apr-2008 18:55:59   

It's easy to fix, I'll attach a fixed dll in a minute or two.

This situation is normally not likely to happen, as the singleton is for the main thread, which creates its own stack, so all scopes created on separate threads will only run into this if on that thread NO entity is instantiated ever.

(edit) attached is a fixed build.

Frans Bouma | Lead developer LLBLGen Pro
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 20:12:03   

I am sorry i got into a meeting, now I have I edited with correct test. Also I attached my source. However, I have questions about the thread usage.

This situation is normally not likely to happen, as the singleton is for the main thread, which creates its own stack, so all scopes created on separate threads will only run into this if on that thread NO entity is instantiated ever.

Did you mean that the main thread is the Testing Process & the scope is creating another thread? I am a bit of a novice in threading, please explain. Do you mean that we can't use dependency injection without creating at least one entity before?

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 08-Apr-2008 20:21:09   

Please see my last message, it has the fixed dll attached.

Frans Bouma | Lead developer LLBLGen Pro
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 20:24:51   

Otis wrote:

It's easy to fix, I'll attach a fixed dll in a minute or two.

This situation is normally not likely to happen, as the singleton is for the main thread, which creates its own stack, so all scopes created on separate threads will only run into this if on that thread NO entity is instantiated ever.

(edit) attached is a fixed build.

Update: However, when I tested with your build it worked.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 08-Apr-2008 20:37:03   

vairam2008 wrote:

Otis wrote:

It's easy to fix, I'll attach a fixed dll in a minute or two.

This situation is normally not likely to happen, as the singleton is for the main thread, which creates its own stack, so all scopes created on separate threads will only run into this if on that thread NO entity is instantiated ever.

(edit) attached is a fixed build.

Update: However, when I tested with your build it worked.

Glad it's sorted. As I explained earlier: the system should take care of threading for you, i.o.w.: no matter what you do with threading, it should work. Normally it would, but in your case, there wasn't any code calling the singleton yet, so the CLR didn't call the static CTor of that class so nothing was initialized.

Frans Bouma | Lead developer LLBLGen Pro
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 08-Apr-2008 23:32:12   

what is the best practice, should I be initializing the singleton in my application startup. thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 09-Apr-2008 09:35:11   

vairam2008 wrote:

what is the best practice, should I be initializing the singleton in my application startup. thanks

No, you don't have to. The singleton isn't meant to be used by your code anyway, you just use scopes when you want to use a scope or define dependency injection info when you need it. I mentioned that for testing purposes.

Btw, scopes have effect on entities created INSIDE the scope. So if you define a scope, an existing entity doesn't get its injected objects changed.

Frans Bouma | Lead developer LLBLGen Pro
vairam2008
User
Posts: 86
Joined: 11-Mar-2008
# Posted on: 09-Apr-2008 17:37:24   

got it thanks