WebClientApplication has problems with TypeMapping?

Topics: Web Client Software Factory, User Forum
Apr 23, 2007 at 1:26 PM
Hi!

I am having problems understanding if I have understood this correctly. And if I have understood I have a problem with TypeMapping in the Web Client Software Factory.

  • Somebody please explain to me if I have understood this right?
  • Somebody please comment on my approach to using the ITypeMappingPolicy.

Looking at the WebClientApplication class (the one which controls the whole web application - launched from the global.asax) I notice this comment in the InnerPreRequestHandlerExecute (which gets called on every request to the application):

// We need to use a non-singleton based builder object here, otherwise
// every object created from the aspx page with the BuildNew attribute
// will be created with hard references on the lifetime container
// and will never be released, causing a memory leak.
CompositionContainer.BuildItem(PageBuilder, moduleContainer.Locator, context.Handler);

The BuildItem method called is a 'Utility method to initialize an object instance without adding it to the container'. Each object built up is keyed in the system using it's type and a string id. This static BuildItem method uses a Guid id making each one unique.

Now I understand the English in the comment text above but I find it rather tricky to understand what the leak would be like had I not used this builder? It is hard to analyze code which is not there!

If I have for instance a page which depends on (CreateNew) a Presenter which in turn depends on some class which in turn depends on some other class - and so on - I get this chain of dependent objects built up by the ObjectBuilder. Great. That's exactly what I need. But I have a twist to this. I'd like to be able to use TypeMapping. Here's the reason:

Say I have Login.aspx which depends on LoginPagePresenter which depends on say an object which communicates with my autentication store - call it AD (contacts our Active Directory in our special way). When I try to build up this chain of dependent objects I get calls to build up each having a Guid id. And this is my problem. I want to be able to set into my CompositionContainer a policy which replaces my type 'AD' at build up with a different type say a type called ADMock. This is, as I'm sure you all understand by now, used for testing my application. I do not need it to contact a real AD - in fact I do not even have a real AD - when I run my test suite.

What you need to do is use the TypeMappingStrategy and have it pull out a policy for mappnig your type-id combo to something else. To easily understand this concept here's the comment to the Microsoft.Practices.ObjectBuilder.TypeMappingStrategy:

/// <summary>
/// Implementation of <see cref="IBuilderStrategy"/> which remaps type and ID.
/// </summary>
/// <remarks>
/// This strategy looks for policies in the context registered under the interface type
/// <see cref="ITypeMappingPolicy"/>. The purpose of this strategy is to allow a user to
/// ask for some generic type (say, "the IDatabase with an ID of 'sales'") and have it
/// mapped into the appropriate concrete type (say, "an instance of SalesDatabase").
/// </remarks>
public class TypeMappingStrategy : BuilderStrategy

A 'context' refered to in the comment is the IBuilderContext built on each page request and filled up with policies registered in the PageBuilder which is specific to WCSF: WCSFBuilder.

This is the problem as I see it (and again I hope I've understood this correctly please correct me if I'm wrong):

  • We are trying to avoid a memory leak by using a special utility method to BuildUp our objects - one that does not put our objects in the lifetime container.

  • This means we build up all (?) our objects with a Guid id regardless of what id they had before.

  • Since we are building up all (?) our objects with a Guid identifier we cannot map them using the TypeMapper. All attempts to look up a type-Guid combo in our policyList will result in a miss.

  • Furthermore this means that we cannot create a DependencyAttribute using a special name in the way Brad Wilson intended when he wrote (?) the TypeMappingStrategy (see code comment text above).

  • We could use the default policy for ITypeMappingStrategy to lookup the correct type when the policy mapping type and id fails. However that feels strange to me: I want to be able to map a specific type AND id if I use a dependency to an interface which is intended to have more than one implementing class. This way I have to write code that intercepts all mapping misses (which in our case is all of them) and then map the type alone not the id since it is a Guid) to another type. This way I also loose the ability to ask for "the IDatabase with an ID of 'sales'" - I can only ask for the mapping IDatabase to one specific implementation and not more than one can exist else we will get abiguity. Say we have IDatabase-'Sales' and IDatabase-'Personel'. How do we handle that?

Has anyone else pondered this and can help? Or could you guys who develop the Web Client Software Factory 1) Explain to me where the memory leak is (since I am not able to figure out what the reverse situation would be if I did not use your specific builders) and 2) please comment on the issue of the difficulties to properly map typeof(inteface)-id when requesting typeof(interface)-Guild.NewGuid().ToString()!?

Anything anyone could do to shed light is greatly appreciated!

Cheers,

/Magnus - Noopman
Coordinator
Apr 23, 2007 at 6:07 PM
Hi NoopMan,
You said:

  • Say I have Login.aspx which depends on LoginPagePresenter which depends on say an object which communicates with my autentication store - call it AD (contacts our Active Directory in our special way). When I try to build up this chain of dependent objects I get calls to build up each having a Guid id. And this is my problem. I want to be able to set into my CompositionContainer a policy which replaces my type 'AD' at build up with a different type say a type called ADMock. This is, as I'm sure you all understand by now, used for testing my application. I do not need it to contact a real AD - in fact I do not even have a real AD - when I run my test suite.

I’m not sure if I understood the whole scenario but I don’t see why you need to use the type mapping strategy to solve your requirement. I see this example as the perfect place to use a ServiceDependency in the presenter’s constructor. This way you register the AD service in the module’s initialization, so the presenter we’ll not create a new instance of AD on each request, but instead get the registered service.
When you are testing the Presenter, you then pass the MockAD object to the constructor, without the use of the builder, and that’s it. No need to start changing the builder just to add testability support. Testing should be as less intrusive as it could, and fortunately CWAB already provides the needed decoupling that we often need.
Here’s a code sample:

//In the ModuleInitializer
protected virtual void AddModuleServices(IServiceCollection moduleServices)
{
    moduleServices.AddNew<ADService, IADService>();
}
 
//Add the following contructor to the presenter
private IADService _adService;
public LoginViewPresenter([ServiceDependency] IADService adService)
{
                _adService = adService;
}
 
//In your Test class use the presenter in the following way. There is no need to use the builder here.
[TestMethod]
public void MyTest()
{
    LoginViewPresenter presenter = new LoginViewPresenter(new MockADService());
    presenter.View = new MockLoginView();
    presenter.OnViewLoaded();
    
    // test code here
}

Please let me know if this helps,
Julián Domínguez
http://staff.southworks.net/blogs/jdominguez
Apr 26, 2007 at 10:21 PM
Edited Apr 27, 2007 at 8:42 AM
Hey Julián!

Thank you for your prompt reply it was partially useful and insightful. I will definitely use that technique where appropriate.

The part where I can not use your answer lies in some information that my sample situation did not convey and therefor I am posting again on this issue. To elaborate and hopefully get another useful reply to the rest of my situation.

I have implemented a TypeMappningService as I call it which will initialize after the Modules have loaded and inspect all the code for two things:

1) Dependencies on interfaces.
2) Implementations of the interfaces which are dependent by other classes.

I have also implemented a strategy to read dependencies from interfaces. When it is appropriate I like to put dependency attributes on the interface rather than on the implementing classes. Reason is that I like to design my code with several important issues in mind. Briefly they are: Testability with interfaces in place for easy mocking, loose coupling and last but not least I like to try to let the interfaces carry the intent of my code. The last issue is why I like to put the dependencies on the interfaces. That way you can read the interfaces and automatically see how I intend for my system to hang together and my implementation code avoids unnecessary clutter. To read further on what I mean you can go to my blod and read: Let your interfaces carry your intent (http://blog.noop.se/2007/04/26/Let+Your+Interfaces+Carry+Your+Intent.aspx).

For the purposes of this discussion suffice to say that I want TypeMapping working since I want to be able to say:

[Dependency(CreateType=typeof(IADService))]

or even

[Dependency(CreateType=typeof(IDatabase), Name="Sales")]

For the latter case I've added an attribute to put on implementation classes called ImplementationAttribute which would be used like this:

[Implementation("Sales")]
public class SalesData: IDatabase
{
[...]
}

This attribute would guide my TypeMappingService when there are more than one implementation of IDatabase that needs to be mapped.

I realize that to some extent this question should be posed to Brad Wilson and the guys in the ObjectBuilder team. But the problem I am facing originates the way I see it from the fact that the memory leak avoided by the WCSF team by using a Guid tempId disables the use of proper TypeMapping. Either I've not fully understood the code which is very likely or the fact is that this leak conflicts with my wish to use TypeMapping in which case I'm hoping for confirmation from this forum.

First I'd like to say how much I've appreciated learning about ObjectBuilder and the WCSF. Finding out more and more about how neatly all this hangs together has been quite a pleasant trip!

Second I'd like to understand exactly what causes this leak which is dodged by using the Guid Id?

Third it would be great if someone could confirm that indeed all things built up in the WCSF are built with a Guid tempId. This seems to indicate that TypeMapping is off the table!

Hopefully you Julián can find the time and interest to look at this some more or find someone who would.

Cheers,

/Magnus
Coordinator
May 2, 2007 at 5:16 PM
Hi Magnus,
The memory leakage is not the reason for using a Guid as a temporary Id. The static method BuildItem in CompositionContainer is asigning a random Guid, because it just needs to assign a new Id to the object being built (in our case, the Web Page).
In your case, if you want to use TypeMapping, you should be able to assign an id to the CreateNew attribute, but this attribute does not support it, and it is too assigning a Guid to the new object to build (this is part of Object Builder, not CWAB).
I wrote a post that shows how to use an attribute similar to CreateNew, but lets you specify an interface instead of a concrete implementation, so the code would behave as you need to, but without the use of TypeMapping at all. Check it out here: How To: Extend Object Creation in the Web Client Software Factory. All feedback is appreciated.

Let me know if this helps,
Julián Domínguez
http://staff.southworks.net/blogs/jdominguez