ServiceDependency in MasterPage

Topics: Web Client Software Factory
Mar 23, 2007 at 11:20 AM
Hi,
I'm using WCSF in a new project and I've run into some problems with the ServiceDependency attribute.
In my MasterPage I have some logic that uses a service so I would like to always have an instance of one my services.

My dependency code looks like this:

IUserService _userService;
ServiceDependency
public IUserService UserService
{
set { _userService = value; }
}

But the _userService is always null.

I'm getting the same error in a webservice I've created. Does the service depenency only work with ASP.NET pages or am I using incorrect syntax?

Thanks in advance
/Mats
Mar 23, 2007 at 11:33 PM
Off the top of my head, I would recommend adding a getter as well. I have seen this happen in the past when only the setter was written.

Let me know if that doesn't not work.
Mar 25, 2007 at 3:15 AM
Edited Mar 25, 2007 at 3:20 AM
Hey Mats,

I am curious about this too. I spent the better part of a day trying to wire the shell and the Master page together by implementing the same PVC pattern that is used in other pages without much success. In order to invoke Object builder, I had to create a reference to the Application root composite container and manually build the presenter/controllor (i.e. CompositeContainer.Buildup(MyPresenter)). This worked, but it left presenter and controller abandoned after the request was finished because the teardown stage is never called (I think this would cause a memory leak :0)

In my case, I, like you, just wanted access to a service so I ended up with this:
// Master Page Constructor
public DefaultMaster()
{
WebClientApplication wca = HttpContext.Current.ApplicationInstance as WebClientApplication;

if (wca.RootContainer.Services.Contains(typeof(MyAPP.MyServicesModule.Services.ExceptionHandler)))
this.ExcHandler=wca.RootContainer.Services.Get (typeofMyAPP.MyServicesModule.Services.ExceptionHandler))
as MyAPP.MyServicesModule.Services.ExceptionHandler;

}

which as you can see, fishes out the Exceptionhandler service that was added to the global services collection when the application initialized one of my modules(watch the dependencies order).

I don't really have a good explaination for why the master page is not considered an extension of the ASPX page that is being handled by the factory, but alas, it seems not. I couldn't get Object builder to pay any attention to it ;)

I think the same PVC pattern for the Master page (possibly tying it to the shell module) is a must-have for future versions of the factory. I think this would be a very powerful concept for managing various application-level features.

It is also possible that I'm way over-complicating the matter and I reserve the right to be completely wrong.

-r
Mar 26, 2007 at 7:11 AM
Hi,
Thanks for the replies. I tried adding a getter but I still got the same result. I went with RSmallwoods solution and added the following code:

    public DefaultMaster()
    {
        WebClientApplication webClientApplication = HttpContext.Current.ApplicationInstance as WebClientApplication;
        _userService = webClientApplication.RootContainer.Services.Get<IUserService>();
    }

It seems quite strange to me that the object builder would ignore the master page, aswell as my web service.

Would greatly appreciate further input from you guys. Thanks again for the responses.

/Mats
Mar 26, 2007 at 8:40 PM
It has nothing to do with getters or setters.

ObjectBuilder Attributes will not work in the MasterPage Class because ObjectBuilder does not create that class / usercontrol.

ObjectBuilder is injecting dependencies into the Page Class before the page life cycle starts. The MasterPage is a UserControl that gets created and added to the Page Class Controls Tree Hierarchy during the Page Life Cycle, which is after ObjectBuilder has done its thing.

This is why, for example, you can programmatically choose your MasterPage dynamically during the Pre_Init Event of the Page LifeCycle.

Regards,

Dave

_________________________

David Hayden
Microsoft MVP C#
Mar 26, 2007 at 9:49 PM
This discussion has been copied to Work Item 9163. You may wish to continue further discussion there.
Mar 26, 2007 at 9:50 PM
Thanks David. I should have looked at the code, instead of relying on my memory. (Bad Programmer. No Pizza!)

I opened a work item for our second release.
Mar 28, 2007 at 10:16 AM
David> Thanks for the clarification!

Best regards,
/Mats
Apr 3, 2007 at 5:06 AM
Hi All,

Here is our solution for allowing the Attributes to operate correctly and use the standard MVPC pattern in both MasterPages and UserControls (sorry it's in VB for all you purists out there. I'm sure you can work it out...):
  • Inherit the WebClientApplication class
Imports Microsoft.Practices.CompositeWeb
Imports Microsoft.Practices.CompositeWeb.Web
Imports Microsoft.Practices.CompositeWeb.Interfaces
Imports Microsoft.Practices.CompositeWeb.Utility
Imports System.Web.UI
 
Public Class WebClientApplication
    Inherits Microsoft.Practices.CompositeWeb.WebClientApplication
 
    Protected Overrides Sub PrePageExecute(ByVal page As System.Web.UI.Page)
        AddHandler page.PreInit, AddressOf OnPagePreInit
    End Sub
 
    Private Sub OnPagePreInit(ByVal sender As Object, ByVal e As EventArgs)
        Dim page As Page = DirectCast(sender, Page)
        RemoveHandler page.PreInit, AddressOf OnPagePreInit
 
        Dim moduleContainer As ICompositionContainer = GetModuleContainer(New HttpContext(System.Web.HttpContext.Current))
        ' Need to access the Master page in order to ensure it is created before accessing controls collection!?
        If Not page.Master Is Nothing Then
            Dim x As String = page.Master.ID
        End If
        BuildControls(moduleContainer, page.Controls)
    End Sub
 
    Private Sub BuildControls(ByVal moduleContainer As ICompositionContainer, ByVal controls As System.Web.UI.ControlCollection)
        For Each c As Control In controls
            If TypeOf c Is UserControl Then
                CompositionContainer.BuildItem(PageBuilder, moduleContainer.Locator, c)
            End If
            BuildControls(moduleContainer, c.Controls)
        Next
    End Sub
 
    Protected Overrides Sub PostPageExecute(ByVal page As System.Web.UI.Page)
        Dim moduleContainer As ICompositionContainer = GetModuleContainer(New HttpContext(System.Web.HttpContext.Current))
        TearDownControls(moduleContainer, page.Controls)
    End Sub
 
 
    Private Sub TearDownControls(ByVal moduleContainer As ICompositionContainer, ByVal controls As System.Web.UI.ControlCollection)
        For Each c As Control In controls
            If TypeOf c Is UserControl Then
                Me.PageBuilder.TearDown(Of System.Web.IHttpHandler)(moduleContainer.Locator, Context.Handler)
            End If
            TearDownControls(moduleContainer, c.Controls)
        Next
    End Sub
End Class
 

  • Change the Inherits directive in the Global.asax of your web application to point to the overridden WebClientApplication class instead of the standard one.

  • You should now be able to use the attributes such as CreateNew in your Master pages or User controls to create your presenter etc..
Apr 3, 2007 at 11:29 AM
I've cooked up something like this. It's not very well thought and targets only master pages and not user controls.

Adding Presenters to MasterPages in the Web Client Software Factory

--
Paulo Morgado
Apr 4, 2007 at 12:27 AM

PauloMorgado wrote:
I've cooked up something like this. It's not very well thought and targets only master pages and not user controls.

Adding Presenters to MasterPages in the Web Client Software Factory

--
Paulo Morgado



Hi Paulo,

I did see your article. It helped point me in the right direction, so thanks for that :).
The main differance with the solution above is that this solution above doesn't require you to modify the original WebClientApplication class (just inherit from it), it works for usercontrols and the tear down is performed..

Cheers

D
Apr 4, 2007 at 1:43 AM
Edited Apr 4, 2007 at 1:47 AM
I cooked up something similar, but use an HttpModule which means you just register the HttpModule in your web.config and toss the assembly in your bin and away you go. I did have to add an extensibility hook into the CWAB, however, so it all washes out in the end.

Also, if you have an application where the selection of the MasterPage is dynamic and assigned in PreInit event on the fly, your code probably won't work as your event will be called before the real MasterPageFile is assigned. You may end up injecting dependencies in the wrong MasterPage and controls.

As an FYI, I also wrote an article on how to do all this without using WCSF and using Castle Windsor instead of ObjectBuilder. It is rough code but good for a prototype and to learn from:

Wire-Up View-Presenter Pattern Like Web Client Software Factory - Castle Windsor for Dependency Injection

Great work guys as I love seeing all this cool code even if some of it is in VB :)

Regards,

Dave

___________________

David Hayden
Microsoft MVP C#
Apr 4, 2007 at 6:05 AM
Edited Apr 4, 2007 at 6:12 AM
Hi David,

Nice article!

I think you are right about dynamic master pages controls being an issue. In fact I am currently encountering this issue with the creation of dynamicly created user controls also..

Any ideas on how I might get around this?

---edit---

I just figured it out. Change the event handler to the Page.InitComplete instead of PreInit.
Apr 5, 2007 at 12:27 AM

davior wrote:

PauloMorgado wrote:
I've cooked up something like this. It's not very well thought and targets only master pages and not user controls.

Adding Presenters to MasterPages in the Web Client Software Factory

--
Paulo Morgado



Hi Paulo,

I did see your article. It helped point me in the right direction, so thanks for that :).
The main differance with the solution above is that this solution above doesn't require you to modify the original WebClientApplication class (just inherit from it), it works for usercontrols and the tear down is performed..

Cheers

D


This was cooked up ina hurry kind of in a dare to someone who told me it couldn't be done. And than I saw a work item in here and hurried it up.

And my intention was to improve the block itself and not only individual applications.

I hope they add this in the next release. Meanwhile, an "offical" guidance on how to do this would be nice.
May 4, 2007 at 12:05 AM
I translated davior's code to C# and included it in a project I am working on...worked great for the user control, but the PostBack on a page is broken for a FormView...for instance, I hit Cancel which causes a PostBack, and the event never fires...when I change back the inherits in global.asax, this problem goes away. I added a FormView in the GlobalBanking example and added this code to the ElectronicBankingApplication.cs in the App_Code folder and noticed the same issue. I have started poking around, but does anyone have any idea why this might be happening?

Thanks,
Joe
May 18, 2007 at 10:18 AM
Hi,
I've tried the solutions of extending the web client application suggested here and by ZeeshanWaheed in another thread.
But when I do this I run into problems with view state in repeater controls, the repeater looses view state on post back.

Has anyone found a solution that enables servicedependency in user controls while not breaking the repeater (and probably other controls as well, saw that someone had a similar problem with form view) view state?

Best regards,
Mats
Aug 29, 2008 at 11:36 AM
I agree with Mats.... there are some issues...

asp net web development

 
Sep 1, 2008 at 1:56 AM
I would recommend using the latest release of WCSF as it has native support for Master Pages and User Controls.