Urgent: How important is resolving non-public objects?

Apr 1, 2008 at 6:19 PM
We're running into issue with partial trust and IL generation, and we have a bunch of tradeoffs to make, none of which are satisfying. I would like some input from the community on where you think the tradeoffs should lean.

Right now, in order to support injecting non-public types, we attach the generated dynamic method to the type that we're resolving, or to the module it lives in if it's an interface. You cannot do this in partial trust.

We could attach the dynamic method to one of the Unity modules instead, but then we cannot do anything with non-public types (like call the constructor).

We have a couple of options I can see.

1) Require only public types for injection.
2) Remove the IL, and do reflection based invocation instead (no dynamic code, no issue). This costs us at least an order of magnitude in performance and penalizes the full trust case
3) Require public types when running in partial trust, can inject internal or private types in full trust. I don't like this one because it'll result in some nasty breakage as permissions change.
4) Use IL in full trust, reflection in partial trust. This doesn't penalize the full trust case, but makes extensions much harder, since there's now two paths to create the build plan.

So, I'd like to ask you guys - where are your priorities? We need to support the partial trust case for Entlib if nothing else. Do you see "only public types" as a serious limitation or something you can live with? (I don't, but I'm willing to be convinced).

-Chris
Apr 1, 2008 at 7:27 PM
Edited Apr 1, 2008 at 7:28 PM


ctavares wrote:

1) Require only public types for injection.



Definately would make it harder to violate encapsulation and OOP principals... I was once worked on a team that had an uphill battle because we had a project where a (very bright) C team wrote the infrastructure for a C# application - all of the UI controls were made public and, via UI references, exposed to all layers. Throw in a misunderstood/misused event pattern and we had a very hard to debug/maintain application.

In the ObjectBuilder/2 arena I am a newbie so I trust I don't understand the benefit of being able to inject non-public types but I suspect that the vast majority of developers fall into my category and we should be protected from ourselves ;)

Food for thought ---- download the Prism project and see how long it takes you (the community - not ctavares;) to figure out how the Presenter gets injected with the view (without reading my Voodoo message in the discussion area;). A misunderstood/misused Unity project could be costly to client projects and development teams that are spending more time debugging than coding.

My 2 cents - now I'm broke :)



Apr 1, 2008 at 7:50 PM
@Chris: From what I can see, the problematic case is injecting PartialTrust+NonPublic Type. Can't we write an extension that when a non-public type is registered, it automatically registers a Reflection-Based IBuildPlanPolicy to override the dynamic build plan policy?

Do you see any complexity in developing such a build plan policy? Would there be too much code duplication? Or is complexity somewhere else?

If I had to vote, I'd say I don't really care about non-public types as they aren't easily testable per-se so I'd go with 1) as I believe we can build the new Reflection-based BuildPlan later on.

@Bill: Prism creation is pretty straight-forward. The module registers the mapping IPositionSummaryView/PositionSummaryView, it then creates the PositionSummaryPresenter which has a ctor dependency on IPositionSummaryView, Unity does the rest.
Apr 1, 2008 at 8:05 PM
@Francois: I wrote a reflection-based build plan implementation in about 20 minutes. I suspect others would take a little longer, though. The complexity concern is more for people developing extensions, since there would need to be TWO build plan strategy chains: one for partial trust, one for full trust. And as such, assuming you're trying to customize the

The main reason I think non-public types are important is this:

container.RegisterType<ILogger, MyInternalLoggerImplementation>();

But if you're not concerned that MyInternalLoggerImplementation needs to be public, I'll stop worrying.

@Bill: Hate to tell you, but the prism stuff is par-for-the-course with DI containers. The same process would be used if you're using Unity, Windsor, StructureMap, Spring, or any other DI container.
You just have to get used to it.
Apr 1, 2008 at 8:24 PM


@Bill: Prism creation is pretty straight-forward. The module registers the mapping IPositionSummaryView/PositionSummaryView, it then creates the PositionSummaryPresenter which has a ctor dependency on IPositionSummaryView, Unity does the rest.

@Bill: Hate to tell you, but the prism stuff is par-for-the-course with DI containers. The same process would be used if you're using Unity, Windsor, StructureMap, Spring, or any other DI container.


Ahhh, but you guys are gurus... I'm a newbie and learning - I trust there will be those like me that will stumble upon my ignorant questions and learn from you guys as I am learning ;)



Apr 1, 2008 at 9:31 PM
@Chris: Well, by now I think I showed the hard way my position on public/internal :(

I didn't realize that 2 BuildPlanStrategies chains would be needed; but now that I've looked at it, of course. Maybe the BuildPlanStrategies should be part of the extension configuration.
Apr 1, 2008 at 9:47 PM
Right now, we're going with the existing behavior for Full trust, and public types only for partial trust. It seems to be working and doesn't require major backflips in the code. It turned out that dealing with non-public types with reflection required elevated permissions anyway, so it didn't really buy us anything.

-Chris
Jul 10, 2008 at 3:55 AM
Let me start by apologizing for opening work item #2422 as it appears to be a duplicate of the discussion here (somewhat). That being said, I would like to voice my support for Unity working with non-public types (internal ones, specifically). Where this really becomes helpful is when doing interface-based design where the author wants (needs?) to intentionally prevent callers from instantiating concrete types. My organization is particularly enamored with this style of programming, but is also very fond of Unity. We are reduced to either creating complex FxCop rules that catch newbies trying to new up a concrete type or finding these during code reviews. Neither case is ideal (too many false positives in FxCop, too many mistakes in code reviews).

That being said, the most compelling cases for our use are 1) instantiating public classes with internal instance constructors, and 2) instantiating internal classes with internal instance constructors. In both cases, the classes implement a public interface, which is the type that is used to resolve against the container at runtime. Additionally, I have to differ with Francois about the testability of non-public types insofar as internal types are concerned, as the InternalsVisibleToAttribute allows for this functionality already. Moreover, MSTest is capable of introducing private accessors that give you full access to all members, although this is a more specialized case--one that Unity likely need not support.

At this point I don't have any suggestions as to how this would be implemented. Indeed, I am remarkably less qualified than you gentlemen to make such suggestions, anyhow. I only wanted to chime in that this is a feature that would be appreciated by myself and (I'm sure) others who prescribe to strict interface-based design.
Jul 10, 2008 at 5:54 AM
At this point, in full trust you can inject instances of internal types. I had to make a change due to a codegen bug in the .NET framework which means you can no longer inject private types, but we didn't see that as that big a deal. So I think your scenarios are covered. If not, let me know.

In partial trust scenarios, you're limited to public types only. No easy way around this one unfortunately, as it's a specific security limitation in the .NET framework.