"Configuring" DependencyInjection Scope

Posts   
 
    
Koubessus
User
Posts: 28
Joined: 30-Dec-2004
# Posted on: 05-Dec-2008 11:21:17   

Hi.

Maybe I am missing something but is there a way how to "configure" a specific DI scope?

I am using v2.6 and I have a following scenario:

  • In one assembly we have all UI forms which are of two types - CreateEntity (Wizard) or EditEntity (View).

  • We have configured separed assembly for validator injection.

Now what do I do if I want a different validation in my View and Wizard forms? E.g. some fields are editable only in wizard etc.

Based on your documentation I would need to create a DependencyInjectionScope class and use it while creating new entity in my Wizard form. And that's where my confusion begins:

  • using specific Scope class will force me to reference my DI library
  • even if I reference the library, I will have to add every specific type mapping to my WizardScope

I would like to use a simple solution, like for example marking my DI class with a specific attribute and leave all the handling to DI classes. Is this in any way possible? By app.config file maybe? Some specific attribute?

If not, can I use some auto discovery features of your in my Scope?

Thanks for your help.

Jakub

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 05-Dec-2008 12:04:18   

even if I reference the library, I will have to add every specific type mapping to my WizardScope

Use typeof(IEntity).

Koubessus
User
Posts: 28
Joined: 30-Dec-2004
# Posted on: 05-Dec-2008 13:09:06   

I'm sorry - how exactly will this solve my problem?

The scenario is as follows (simplified):

I have SchemaEntity with Name and Description.

By default, Name cannot be edited, which is (for the sake of this sample) implemented in SchemaValidator (maybe authorizer would be more exact).

When I create a new Schema a need to enter its name. So I will have to validator classes:

  • SchemaValidator (which is default)
  • CreateSchemaValidator (which should be used only when creating new schema from UI)

All my Wizard forms use same base class so it is ease to do:


using (WizardScope scope = new WizardScope)
{
   this.newEntity = this.CreateNewEntity();
}

And the WizardScope would be somethinig like:


    public class WizardScope : DependencyInjectionScope
    {
        protected override void InitializeScope()
        {
            this.AddInjectionInfo(typeof(CreateSchemaDescriptor), typeof(SchemaEntity), "Validator");
        }
    }

But considering that I have large number of entities, several different types of injected classes (Validator, Authorizer, Initializer, Descriptor,...) and I don't want my UI to reference this service layer, I am not seeing a simple solution to this.

Except maybe for creating custom attribute and evaluating every class in the assembly, but I would still need to reference the Scope class.

Any ideas?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 06-Dec-2008 11:30:59   

There are two different systems: 1) global system, which is configured through the attributes on the injectables (validator etc.) and config file / autodiscovery. If you don't use a scope, this system is what's used 2) local system, through dependency injection scopes. The scopes define an area inside the scope where different injections occur. It overrules the global system on the definitions it contains.

The main thing is that you should define the injectables through the global system and then override them at given special occasions through scopes.

What you are facing is something which shouldn't be done this way. You should do it differently, namely through the validator itself: you should create 1 validator for SchemaEntity and in ValidateFieldValue, check whether the involvedEntity is new or not. If it's new, name can be changed, if it's not new, it's a violation and false should be returned.

Frans Bouma | Lead developer LLBLGen Pro
Koubessus
User
Posts: 28
Joined: 30-Dec-2004
# Posted on: 08-Dec-2008 09:56:35   

Hi Otis.

Thanks for the reply. The situation you described makes total sense to me.

Unfortunately for me, the situation is slightly different. As I mentioned before, we are using your DI to configure different injectables, in this case an entity descriptor (ICustomTypeDescriptor implementation).

The descriptor returns collection of properties which are further used by .NET framework itself - DataBinding, PropertyGrid, etc. And the current design (or the ICustomTypeDescriptor) is bound to entity type, not instance.

So I have three options:

  • pass the entity to the descriptor while getting list of properties - which would work in my code, but not in .NET framework
  • use my own discovery system to setup a scope
  • use different way to inject proper descriptor

Frankly- the first one is not really an option since I would need to remember to bypass all the .NET data binding and infrastructure functionality base on TypeDescriptor.

So in case number two - is there a way to access list of assemblies configured for autodiscovery?

In any case, I'll let you know what I've managed to do after I - hopefully - solve this simple_smile

Thanks again.

Jakub

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 08-Dec-2008 19:10:46   

Koubessus wrote:

Hi Otis.

Thanks for the reply. The situation you described makes total sense to me.

Unfortunately for me, the situation is slightly different. As I mentioned before, we are using your DI to configure different injectables, in this case an entity descriptor (ICustomTypeDescriptor implementation).

The descriptor returns collection of properties which are further used by .NET framework itself - DataBinding, PropertyGrid, etc. And the current design (or the ICustomTypeDescriptor) is bound to entity type, not instance.

I'm not sure why this is prevents you from adding a check to the validator if the entity is new or not (as that's the distinction you're making if I'm correctly interpreting your posts). Could you elaborate on that?

Btw, MS told me in a bugreport related to ICustomTypeDescriptor to avoid the interface, as it's sometimes giving problems. Not sure if it is required for your application or not.

So I have three options:

  • pass the entity to the descriptor while getting list of properties - which would work in my code, but not in .NET framework
  • use my own discovery system to setup a scope
  • use different way to inject proper descriptor

Frankly- the first one is not really an option since I would need to remember to bypass all the .NET data binding and infrastructure functionality base on TypeDescriptor.

So in case number two - is there a way to access list of assemblies configured for autodiscovery?

Not directly, the class is internal. (dependencyinjectioninfoprovider). It's setup in such a way that changes aren't allowed to that meta-data. So you then should compile a changed ormsupportclasses dll yourself (which allows you then to access the interface types discovered and the normal types discovered. )

Still, if you want to override a lot of the injection data inside the DI provider so you get different validators which basicly differ only a little, it might not be an efficient thing to do it that way (and for example make sure the validator is a little more clever).

Frans Bouma | Lead developer LLBLGen Pro
Koubessus
User
Posts: 28
Joined: 30-Dec-2004
# Posted on: 09-Dec-2008 11:20:25   

The descriptor returns collection of properties which are further used by .NET framework itself - DataBinding, PropertyGrid, etc. And the current design (or the ICustomTypeDescriptor) is bound to entity type, not instance.

I'm not sure why this is prevents you from adding a check to the validator if the entity is new or not (as that's the distinction you're making if I'm correctly interpreting your posts). Could you elaborate on that?

This is more connected to the way we are using entities. We are building quite large (at least in our environment) data entry application which will be continually extended in the future. So we decided to "simplify" (seems the quotes are in order now) UI development and just created a basic lists and all extended details of entities are edited using PropertyGrid.

In order to define visible and editable properties, the CommonEntityBase implements ICustomTypeDescriptor interface and has an injected Descriptor property of type ICustomTypeDescriptor. If the descriptor is injected, the entity delegates all requests to this descriptor, otherwise it uses internal reflected descriptor of itself.

For some purposes (which I cannot remember right now) we also have a TypeDescriptionProvider attribute set on the CommonEntityBase in which case a new entity is returned cast to ICustomTypeProvider.

We've had some difficulties with this design, for example when testing ReadXml and WriteXml since LLBLGen runtime libraries also rely on TypeDescriptors, but we've managed to solve this.

Right now I would like to adjust property collection base on Scope - when creating a new entity or editing a loaded entity.

When I described the design I realized that I can do something similar to your Validator class - send the entity itself to my internal class (i.e. descriptor.GetProperties(entity)). I would need to create some caching mechanism and review all the consequences and required changes but it should work. It just complicates things a little bit disappointed

Btw, MS told me in a bugreport related to ICustomTypeDescriptor to avoid the interface, as it's sometimes giving problems. Not sure if it is required for your application or not.

By any chance, do you remember what problems they were? Basically the application is build around self describing entities....

Not directly, the class is internal. (dependencyinjectioninfoprovider). It's setup in such a way that changes aren't allowed to that meta-data. So you then should compile a changed ormsupportclasses dll yourself (which allows you then to access the interface types discovered and the normal types discovered. )

Still, if you want to override a lot of the injection data inside the DI provider so you get different validators which basicly differ only a little, it might not be an efficient thing to do it that way (and for example make sure the validator is a little more clever).

I am thinking about using already configured list of assemblies, not the types. I can go through the defined classes my self, I just don't want to create a new configuration for this sunglasses

Anyway, I think I'll look into redesigning the descriptor class so it has the entity at hand when building the property collection.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 10-Dec-2008 11:38:33   

Koubessus wrote:

The descriptor returns collection of properties which are further used by .NET framework itself - DataBinding, PropertyGrid, etc. And the current design (or the ICustomTypeDescriptor) is bound to entity type, not instance.

I'm not sure why this is prevents you from adding a check to the validator if the entity is new or not (as that's the distinction you're making if I'm correctly interpreting your posts). Could you elaborate on that?

This is more connected to the way we are using entities. We are building quite large (at least in our environment) data entry application which will be continually extended in the future. So we decided to "simplify" (seems the quotes are in order now) UI development and just created a basic lists and all extended details of entities are edited using PropertyGrid.

In order to define visible and editable properties, the CommonEntityBase implements ICustomTypeDescriptor interface and has an injected Descriptor property of type ICustomTypeDescriptor. If the descriptor is injected, the entity delegates all requests to this descriptor, otherwise it uses internal reflected descriptor of itself.

For some purposes (which I cannot remember right now) we also have a TypeDescriptionProvider attribute set on the CommonEntityBase in which case a new entity is returned cast to ICustomTypeProvider.

We've had some difficulties with this design, for example when testing ReadXml and WriteXml since LLBLGen runtime libraries also rely on TypeDescriptors, but we've managed to solve this.

Right now I would like to adjust property collection base on Scope - when creating a new entity or editing a loaded entity.

When I described the design I realized that I can do something similar to your Validator class - send the entity itself to my internal class (i.e. descriptor.GetProperties(entity)). I would need to create some caching mechanism and review all the consequences and required changes but it should work. It just complicates things a little bit disappointed

The validator gets the entity it has to work on with every call, so you can make any decisions live at that spot based on all information available. This thus would make it easier I think for you than through scopes, as that would simply make things more complex (the scope setup and also when which validator is injected into the entity).

Btw, MS told me in a bugreport related to ICustomTypeDescriptor to avoid the interface, as it's sometimes giving problems. Not sure if it is required for your application or not.

By any chance, do you remember what problems they were? Basically the application is build around self describing entities....

See: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93944

Frans Bouma | Lead developer LLBLGen Pro