Extra Parameters, and Resolving internal constructors

May 13, 2008 at 11:50 AM
Hello,

Extra Parameters
when resolving a class is it possible to pass extra parameters which are just instances of objects?

I.e. I don't want to register one of the parameters, and just want to pass through a value to the constructor like a DTO.
So I am passing a DTO as well as all the class dependancies.

Can I use resolve to load in the dependancies as well as pass through other parameters?

Alternatively would I have to create a seperate container that was just used in this one location, and register the DTO to be sent through. I wouldn't want to register the DTO in the main application container, or else it might get used in different parts of the application, and might have conflicts with other threads registering different DTO's.

The only other way I thought of is moving these extra parameters as setters, but I don't want to have to do this. As you then start to have objects that exist which might not have been setup correctly.

Resolving internal constructors
Is it possible to resolve internal constructors? Seems to throw an error when I try.

I have an internal constructor on an object as I only want it created from within the current project, or the test project (using [assembly: InternalsVisibleTo ... )

Or do I have to use a factory, and use Unity as a service locator to get the dependencies and pass them through to the internal constructor?

Regards


May 13, 2008 at 5:57 PM
The nearest I have got is

ConfigureInjectionFor/InjectionConstructor

http://msdn.microsoft.com/en-us/library/cc440941.aspx

But haven't got any further.


An example of what I am trying to achieve is:

public class TestClass
{
        private EmployeeDto _dto;
        private ILogger _logger;

        //throws error if internal on Resolve<TestClass>, hack change to public
        internal TestClass(EmployeeDto dto, ILogger logger)
        {
                _dto = dto;
                _logger = logger;
        }
...
}


//Setup code
.RegisterType<ILogger, Logger>();

 

 

//Calling code, how to pass in dto, and keep ILogger being resolved automatically??
Container.Resolve<TestClass>()

May 13, 2008 at 8:56 PM
Edited May 13, 2008 at 9:00 PM

Have you considered InjectionMethod()?


            IUnityContainer container = new UnityContainer()
                .RegisterType<IMylogger, MyLogger>();

            TestClass SetItUpTheWayIWant = new TestClass(new EmployeeDto("My Name"));
            container.BuildUp<testclass>(SetItUpTheWayIWant);

            SetItUpTheWayIWant.MyProcess();

    public interface IMyLogger
    {
        void write(string message);
    }
    public class MyLogger : IMyLogger
    {
        public void write(string message)
        {
            Debug.Write(message, "LOGGER");
        }
    }

    public class EmployeeDto
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public EmployeeDto(string name)
        {
            _name = name;
        }
    }

    public class TestClass
    {
        private EmployeeDto _dto;
        private IMyLogger _logger;

        [InjectionMethod]
        public void Initialize(IMyLogger logger)
        {
            _logger = logger;
        }
        internal TestClass(EmployeeDto dto)
        {
            _dto = dto;
        }
        public void MyProcess()
        {
            _logger.write(string.Format("Name: {0}", _dto.Name));
        }
    }
May 13, 2008 at 11:16 PM


ijones wrote:
Hello,

Extra Parameters
when resolving a class is it possible to pass extra parameters which are just instances of objects?

I.e. I don't want to register one of the parameters, and just want to pass through a value to the constructor like a DTO.
So I am passing a DTO as well as all the class dependancies.

Can I use resolve to load in the dependancies as well as pass through other parameters?

Alternatively would I have to create a seperate container that was just used in this one location, and register the DTO to be sent through. I wouldn't want to register the DTO in the main application container, or else it might get used in different parts of the application, and might have conflicts with other threads registering different DTO's.

The only other way I thought of is moving these extra parameters as setters, but I don't want to have to do this. As you then start to have objects that exist which might not have been setup correctly.

Resolving internal constructors
Is it possible to resolve internal constructors? Seems to throw an error when I try.

I have an internal constructor on an object as I only want it created from within the current project, or the test project (using [assembly: InternalsVisibleTo ... )

Or do I have to use a factory, and use Unity as a service locator to get the dependencies and pass them through to the internal constructor?

Regards





There have been several requests for being able to pass parameters in the resolve method. There's also a lot of differing opinions on how that should work. The current best approach in my mind is to let you pass a dictionary and if the names and types in the dictionary line up with a constructor or method parameter or property, use the value from the dictionary. Yes, this is deliberately awkward.

Unity will only call public constructors, properties or methods. Internal constructors are not available to the Unity assembly, after all. We could theoretically use reflection over private members, but that only works in full trust, is very slow, and violates good design principles.

May 14, 2008 at 11:29 AM
Thanks for the input,

yeah I had thought about the BuildUp method, but didn't want to allow people to construct the object without the dependancies if they didn't call the BuildUp method.
However I guess with internal constructor this BuildUp call can be guaranteed (nearly) with the use of a factory class to construct the object. And since Unity can't call internal methods would need a factory method anyway.

It seems overkill though to use a factory for any class that takes non dependency parameters as well as dependencies, changing public constructors to internal, and setting up an initilize method.




The Dictionary idea doesn't sound too good, strings literals of parameters and types + refactoring = broken code? Ok so you could have constants in the class of the parameter names, and types, but this is more stuff to maintain.
Unless you have any ideas on how to keep string representations of property names & types/constructor variables in sync.

Ideally I would want the parameters strongly typed.

In the same way that you can call RegisterInstance, can there be a RegisterInstanceForResolve that only affects the current Resolve.
Ok people might complain that they can only pass in one type of each object, particularly strings or integers, but they can create a helper class and setup these values, then register the instance during the resolve call.

I imagine it would look something like

TestClass

 _testClass = Container.Resolve<TestClass>(); ->
TestClass _testClass = Container.RegisterInstanceForResolve<EmployeeDto>(dto).Resolve<TestClass>();

Alternatively is there a way to clone or copy the registered services in the container,
then I can just call
RegisterInstance<EmployeeDto>(dto)
on the clone without worrying about how other users of the container might be affected.

 

May 14, 2008 at 12:01 PM
Edited May 14, 2008 at 12:08 PM
Would be good if the UnityContainer class had a clone method.

 Maybe I can achieve the same effect by using CreateChildContainer, will investigate further.

 

May 14, 2008 at 2:09 PM


ctavares wrote:


ijones wrote:
Hello,

Extra Parameters
when resolving a class is it possible to pass extra parameters which are just instances of objects?

I.e. I don't want to register one of the parameters, and just want to pass through a value to the constructor like a DTO.
So I am passing a DTO as well as all the class dependancies.

Can I use resolve to load in the dependancies as well as pass through other parameters?

Alternatively would I have to create a seperate container that was just used in this one location, and register the DTO to be sent through. I wouldn't want to register the DTO in the main application container, or else it might get used in different parts of the application, and might have conflicts with other threads registering different DTO's.

The only other way I thought of is moving these extra parameters as setters, but I don't want to have to do this. As you then start to have objects that exist which might not have been setup correctly.

Resolving internal constructors
Is it possible to resolve internal constructors? Seems to throw an error when I try.

I have an internal constructor on an object as I only want it created from within the current project, or the test project (using [assembly: InternalsVisibleTo ... )

Or do I have to use a factory, and use Unity as a service locator to get the dependencies and pass them through to the internal constructor?

Regards





There have been several requests for being able to pass parameters in the resolve method. There's also a lot of differing opinions on how that should work. The current best approach in my mind is to let you pass a dictionary and if the names and types in the dictionary line up with a constructor or method parameter or property, use the value from the dictionary. Yes, this is deliberately awkward.

Unity will only call public constructors, properties or methods. Internal constructors are not available to the Unity assembly, after all. We could theoretically use reflection over private members, but that only works in full trust, is very slow, and violates good design principles.




I vote for this approach.  Other approach could Unity have a custom collection class that can be used to populated and pass it to Resolve
May 14, 2008 at 2:50 PM
Edited May 14, 2008 at 3:05 PM

I tried the

IUnityContainer

childContainer = container.CreateChildContainer();

 

childContainer.RegisterInstance<

EmployeeDto>(new EmployeeDto());

 

childContainer.Resolve<

TestClass>();

and worked fine.

Of course not with my internal constructor where I do
TestClass employee = new TestClass(dto);
Container.BuildUp(employee);

 

as suggested by BillKrat, in my factory

I was thinking about a custom class to pass to Resolve which contains the property of the parameters to fill out, unity would then use reflection to get the property names, types and values. I think this would be better than a string dictionary, but you still would have to keep the custom class propertys in sync with the constructor parameters.

Registering the instance on the child container works for me, anyone spot any potential issues with this? Any better approaches welcomed.

 

 

May 20, 2008 at 8:35 AM
I would very much like this feature implemented as well. Currently it is available in the Castle Project Windsor which i'm currently using. This feature is an absolute must and is the only thing stopping me from converting my application to use Unity instead of Windsor.

Currently Windsor implements this feature by passing an IDictionary in the resolve method. This works for me in 95% of the cases it does however have a big shortcoming. Consider the "ID" property which is often present on business entities as the primary key. When an argument is supplied to the resolve method it will set all properties with name and type of "ID" to the value supplied. This is not always what you want as you may want to just initialize the "ID" of 1 top level business entity.

For example: A new City is constructed for which you supply an "ID" and at the same time City has a dependency on Country. Both City and Country have an "ID" field as primary key so when the container resolves the dependencies it will set both City and Country to the same supplied "ID".

This is a shortcoming for me in Windsor at the moment although I have adjusted my way of working so that this is no longer an issue right now. If this functionality is included in Unity it should have some sort of scope so that you can limit it to a certain type of class for example. As I said, I don't really see right away an easy solution here...
May 20, 2008 at 7:35 PM
 If Windsor is currently working for you why do you want to switch?

The feature is on the backlog, but I can pretty much guarantee we won't do any "scoping" for child objects. At that point, you shouldn't be using a DI container, you should be either newing it up directly or using the container to get a factory which has all the detailed knowledge of how to build subsidiary objects (and could use the container to do it).


May 21, 2008 at 7:48 AM
Reason for switching would be due to the fact that Unity has other features which Windsor doesn't have that I would like to integrate (to replace custom code) in my application. However due to the fact that my current framework components rely heavily on the possibility to pass arguments to the resolve method I will not be migrating until this feature is present.

I understand that scoping is indeed a difficult problem to solve and through slightly different design (as I have done now) there are indeed other solutions to this problem.

Thanks for the reply!