views:

332

answers:

4

I have an ASP.NET Web Forms page which the presenter needs to populate with controls. This interaction is somewhat sensitive to the page-life cycle and I was wondering if there's a trick to it, that I don't know about.

I wanna be practical about the whole thing but not compromise testability.

Currently I have this:

public interface ISomeContract
{
    void InstantiateIn(System.Web.UI.Control container); 
}

This contract has a dependency on System.Web.UI.Control and I need that to be able to do things with the ASP.NET Web Forms programming model. But neither the view nor the presenter may have knowledge about ASP.NET server controls.

How do I get around this? How can I work with the ASP.NET Web Forms programming model in my concrete views without taking a System.Web.UI.Control dependency in my contract assemblies?

To clarify things a bit, this type of interface is all about UI composition (using MEF). It's known through-out the framework but it's really only called from within the concrete view. The concrete view is still the only thing that knows about ASP.NET Web Forms. However those public methods that say InstantiateIn(System.Web.UI.Control) exists in my contract assemblies and that implies a dependency on ASP.NET Web Forms.

I've been thinking about some double dispatch mechanism or even visitor pattern to try and work around this but I don't yet know in which direction I want to go and I would really like some input on the matter.

A: 

One way you can decouple your contract from your web control is to have a separate writer that handles getting the information from ISomeContract and places it in your Control container. This could reside in an assembly that references both the contract assembly and System.Web.

JNadal
Could you give a concrete example?
John Leidegren
A: 

I have been reading about agile techniques, tdd, unit testing, solid, design patterns and felt utterly powerless to bridge the gap from all this wonderful theory to asp.net webforms.

I had another go at trying to find a solution to this problem earlier today and found this article:

It is an excerpt from a book which I thought would solve all my problems but this chapter is really just an introduction to the possibilities of implementing the MVP pattern in webforms and it concludes with saying that its not really practical. The rest of the book is about testing asp.net MVC as far as I gathered.

There is also this new project which aims to bring the love back to the webforms platform:

rtpHarry
A: 

In "normal" ASP.NET web forms, your page/user control is technically "in charge" of the processing, and imposes its life-cycle on the code. The page is the Presenter and the View, whether you like it or not.

Most attempts to implement the MVP pattern in this environment simply add excess complexity to an already overly complex environment! Pretending that another class is the Presenter is just that... pretending. (In MVC web sites, the Controller truly does control the code, and the View does not, so this argument no longer applies.)

My recommendation is to let the view look after its own life-cycle, and let it invoke Repositories and Model classes to retrieve/save data and invoke commands.

In this approach, the Model classes do not need to know anything about System.Web. These same Model classes could then be used in future MVC web sites, or Silverlight, or as a web service for WPF applications, or embedded in a WPF application, etc. It is up to the View to determine how to implement (using Controls) the response/data it gets from the Model.

The Model classes can be tested as much as you like if you correctly set them up to support dependency injection.

Hope that helps!

Glen Little
+1  A: 

Not sure how a visitor would solve the problem. But why not have your contracts look like this:

public interface ISomeContract
{
    void InstantiateIn(IControl container); 
}

with an IControl implementation, possibly in another assembly to keep your contract assembly clean, that wraps over the ASP.NET System.Web.Control, like:

public class AspnetControl : IControl
{
    public AspnetControl(System.Web.Control control) { }

    // IControl members that dispatch to control
}

Although there's a high likelihood that eventually IControl would end up looking very much like a System.Web.Control (and hence defeat the point of abstracting it in the first place), it'd still be very testable, and your view and presenters won't have to know a thing about ASP.NET.

CodeMangler
Your IControl Interface can expose certain "lifecycle" events that your controller can listen for - most of the time you end up just wrapping the web forms events (maybe a little helper class might ease that pain?) but, if you want your views to be entirely stupid, then you need to live with it.
David Kemp