Part 2 of 3: Creating shared user controls and master pages with sub-projects

Part 2 of 3: Creating shared user controls and master pages with sub-projects

Rate This
  • Comments 42

This is the Part 2 of a 3 part series on using sub-projects with the Web Application Projects add-in for Visual Studio 2005. 

Part 1 of the series can be found here

I apologize to folks for the delay in getting this second post out, we've been super busy the past few weeks.  This post covers two concepts when using sub-projects with the Web Application Projects add-in:

  • Creating a shared master page in the root project and using it in sub-projects
  • Creating a shared user control in the root project and using it sub-projects

Prerequisite

  • Visual Studio 2005 with Web Application Projects add-in installed
  • This article assumes the user has already done the steps described in the Part 1 of this series which sets up a root project and sub-project in Visual Studio 2005.   NOTE: It is very important to have done these prerequisite steps as the examples below will not work otherwise.

Creating a shared master page and using it in sub-projects

In this example, i'll show how to setup a master page in the root project and then use that master page in sub-projects in the same solution.

1) The first step is to create a master page in the root project.  To do this right-click on the root project's node in solution explorere and select Add New Item.  In the dialog select the Master Page item and provide a name for it (e.g. - RootProject.master).

2) Once the master page is created in the root project, edit it Design view and add some default content as shown below.

3) Now that we have a master page created in the root project, we need to create a content page in the sub-project which will use the master page from the root project.  To do this right-click on the sub-project's node in solution explorere and select Add New Item.  In the dialog select the Web Form item and provide a name for it (e.g. - ContentPage.aspx).

4) The next step is to convert the web form created in the sub-project to a content page.  To do this first remove all the content from the Web Form so it only has the Page directive line left as shown below.

5) Next add in a MasterPageFile attribute and one or more asp.net content control to use the master page from the root project as shown in the diagram below.  In the MasterPageFile attribute, refer to the master page in the root project using a relative path from the current document.  Add as many content controls as "contentplaceholder" areas in the master page that you would like to override.

Note: Visual Studio 2005 will indicate an error on the MasterPageFile and ContentPlaceHolderID attributes.  Both of these are known bugs in Visual Studio and can be ignored as they really aren't errors when the page is run.

6) If one switches to Design view on the content page in the sub-project, you will notice that only the content from the content page renders and the master page itself does not render.  This also is a known limitation of Visual Studio 2005.  Although the master page portion of the content is not shown in Design view when using a master page from a root project, the content page can still be fully edited like any other page, so this limitation should not be too impactful to most users.

7) To test that the master page is actually working with the content page, right click on the content page in the sub-project. and select View in Browser.  This will launch the web broswer and show the content page merged with the master page from the root project.

Creating a shared user control and using it in in sub-projects

The previous section described how to create a shared master page in the root project and then how to use that master page with content pages in sub-projects.  This section describes how to use the similar technique but to create a shared user control in the root project which can be used on pages in sub-projects.

1) The first step is to create the shared user control in the root project.  To do this right-click on the root project's node in solution explorere and select Add New Item.  In the dialog select the Web User Control item and provide a name for it (e.g. - RootUserControl.ascx).

2) Once the user control is created in the root project, edit it Design view and add some default content as shown below.

3) Now that the shared user control is created in the root project, the next step is to use it within a page inside of a sub-project.  When using a user control from another project, Visual Studio 2005 does not provide drag/drop support (i.e. - you can't drag the ASCX file to the design surface), so one must manually type in a Register directive and add an instance of the user control.  To do this, modify a page in the sub-project (default.aspx in this case), as shown in the diagram below.  For the Src attribte of the Register directive use a relative path to refer to the shared user control in the root project.

Note: you may see several compile errors in the task list at this step.  Those can be ignored for now as the next step addresses them.

4) To use the shared user control in the sub-project, one additional step is requried.  The sub-project will need a project reference to the root project.  To do this right-click on the sub-project's node in solution explorer and select Add Reference.  In the Add Refernece dialog go to the Projects tab and select the root project to reference (MyLargeWeb in this example).

5) As long as the output folder of the sub-project is set to the target the \bin of the root project, then just adding a project reference to the root project should be enough and this step can be skipped.  However if the output directory of the sub-project project is set anywhere else, then one should bring up the sub-project's references list and modify the reference to the root project in the property grid and set its Copy Local property to False as shown below.

7)  After the reference to the root project has been added, switching to Design view for pages in sub-projects should render controls from the root project.  Selecting a page in a sub-project that uses a user control from the root project and running it should work fine in the web browser also.

Note: you will still continue to get markup validation errors against some of the attributes on pages opened for editing which are using shared user controls from the root project.  Similar to the master pages scenario in the last section, those validation errors are bugs in Visual Studio 2005 and since these are not compile errors they can be ignored.

Additional Note: there is a known intermittment bug when using the Web Application Projects add-in where switching a page to Design view may cause the IDE to hang.  The bug is very intermittment and may or may not occur when doing a sub-project scenario with Web Application Projects.  The product team has identified a fix for this issue and it will be fixed in the next servicing release of Visual Studio 2005.  If you do happen to encounter this issue, and are blocked by it, please contact me via this blog or directly at omark-at-microsoft-dot-com and we will make a hotfix available to you.

Summary

As is described in this post, creating and using shared master pages and user controls is fairly straightforward when using the Web Application Projects add-in.  There are a few extra steps one needs to take but other than that the pattern is fairly similar to how master pages and user controls are used within a single project.

Looking forward to hearing your feedback again on this topic, and I will try to get Part 3 of the series done in shorter time than it took for this one ;-).

-- Omar

Leave a Comment
  • Please add 1 and 1 and type the answer here:
  • Post
  • So what's the best way to deploy one of these projects?

    One web setup project for each project, one for the whole thing, or should I try the web deployment project?

    VS2005 sure has a lot of choices for deployment.
  • Some great info in both parts so far.  I'm using the techniques to overhaul our very basic  website (all tables!) into something much more manageable and visually appealing (least I hope so!)  My experiences of this approach so far are:

    1. Deployment is easy (we host our own web server). Individual projects can be compiled separately in the solution, so only the effected DLL and aspx page(s) need to be copied across.

    2. Resources seem to load ok as long as you use the correct app-relative syntax.  The ~/ works fine so long as you add some folder structure.  Sub projects referencing the master just need the same as a normal root level page, eg "~/siteroot.master".  This will offer an IDE error (red squiggle underline), but operates fine (nested master pages will still work fine as well).  Similarly for other resources, e.g. some of my sub-projects include their own set of images, so I have a sub-folder of "images" under that project, then reference the image using "~/subprojfoldername/images/myimage.png".
    Using a root level resource is the same as the master page, so for example a generic image (banner, etc) would be "~/images/banner-1.png".

    3. An annoyance is that the solution will always offer a warning dialogue when opening - one for each sub-project - of "Changing the URL or output path affects intellisense.  you need to close and re-open the project for these changes to take effect."  This despite the fact you're just starting VS2005...  The cause is the setting for using a specified IIS path instead of the default VS server on the Web tab of the project properties.

    I haven't tried data connections yet, so can't comment on that, but I intend to use the DAAB model.  If anyone's already tried this, I'd be interested to hear your experiences.

    Overall a great approach, but as Mike mentions above, it would be nice to see better comprehension by the VS IDE of the WAP requirements. (lots of "Could not find" errors anyone?)

    Cheers,
    Al
  • Following on from my previous comments, I've found that the code-behind designer isn't being updated with controls I'm adding to the content page under a specific circumstance.

    I use a ContentPlaceHolder for targeting a custom banner graphic (changing between content pages), which is implemented using the Bewise FlashControl wrapper component.

    If I comment out the CPH holding the Bewise control, the designer picks up all the added controls as expected.

    I've made the assembly reference for the BeWise control in the <pages>... <controls> section of the web.config, rather than having to add the control register to every content page.

    I have tested the control with a local page register declaration as well - no difference.

    In both cases the IDE error is reported as "Generation of designer file failed: unknown server tag 'Bewise:FlashControl'", so it's pretty clear this is the problem area.

    I can of course just comment it out until I've completed my coding, then reveal it again, but I wondered if anyone might have an idea why the inclusion of the control should cause this issue?

    Thanks,
    Al
  • Hi - me again!
    Ok, so now I've progressed on to coding one of my sub-projects.  I've had the following (not-so-good) experiences:

    1. In order to perform debugging of a sub-project, that sub-project must be manually built/rebuilt before hitting the F5/debug button.  If you don't, the debug symbols are not updated and you can't step into your breakpoints.

    2. Issuing the build command also causes that "Changing the URL affects intellisense ..." warning dialogue to pop up again (once for each sub-project you have in the solution).

    3.  The interpreter seems to have a problem with some conditional statements.  For example, I set up a simple "If" condition in the page load event of a sub-project's content page.  When debugging, the last line of the enclosed conditional logic is run _regardless_ of the value determining the condition.  For example, using Page.IsPostBack;

    If Page.IsPostBack Then 'First loading of page, so false.
    ..do something specific 1
    ..do something specific 2
    ..do something specific 3 '<- This still executes when Page.IsPostBack = false!
    End if

    After some further testing, this always seems to be a case of the yellow line highlighter always going to the last statement within the page-load, regardless of the logic state.  It doesn't seem to actually execute the statement however.  I only tested this very simplistically by using two panels and a button to change their visibilty settings.

    This set of issues only seems to occur in the sub-projects.  Operation is quite normal in the parent (root) project code files.

    BTW, I don't want to seem a nuisance and create loads of extra yardage on your blog.  If there's a more discreet mechanism I'd be happy to use it (msdn-wap at copeohs dot com).

    Al
  • Omar,

    Thanks for all the great info!  I'm having good success with the sub projects and think it is the way we need to go.  I'm running into problems with the accessability of session variables in the sub project created by the root project.  You have any ideas on what may be my hold up?

    Thanks,
    Terryb
  • Hi Terry,

    Session variable should work exactly the same in a sub project as a the root project.  In IIS manager you should verify there is only one "application" icon on the root project and the sub-project folders just appears as folders in IIS and not "sub-apps".  As long as the root and sub-projects share the same applicaiton in IIS, the session variables should be shared.  Note - when you are debugging you may be running two different sessions so that might be a one reason it seems like session is not working.  Hope this helps.

    --Omar
  • In step 7 of sharing a master page, it doesn't work for me.  Instead, it goes to: http://localhost:10653/ContentPage.aspx.  If I go to the proper location, it does work.

    When setting the MyLargeWebApp to the startup project it sometimes goes to the localhost:10653 too... But, I just checked it again and it's going to the right place.  Another feature I guess.

    Anyways, is there a way to force the contentpage to use the application in the solution?  Or is this just another bug?  Will these bugs be fixed in the next sp or do we just have to deal with them?  I was really hoping this would all be easier than 1.1 & built-in...

    It doesn't feel like 2.0 was written for large sites that have to be updated incrementally and want to share common features.  It feels like it was written for small sites that don't have much updating going on and can be updated all together...

    Thanks,
    Ember
  • I've followed the steps exactly, except I need my website to run at the root IIS website (not in a virtual directory).

    Also, all computers are running server 2003 as the main OS for development.

    The error I get when I try to work this is:

    Parser Error ...

    Parser Error Message: The virtual path '/MasterPage.master' maps to another application, which is not allowed.

    Any thoughts?
  • Hi Ryan,

    The error leads me to believe the sub-project is setup on a seperate application in IIS.  Please make sure the folder for the sub-project does not have a special icon and is just shown as a folder in the IIS console.

    See the diagram of the IIS consolde Part 1 of this series which shows how the sub-project folder should look in IIS console.
  • Omar Khan, GPM for the VS 2005 web tools has posted a lengthy example of how to create a partitioned
  • I have been working on doing just what you are suggesting here, but with a Web Site Project.  Everything would work great if within VS2005 I could reference the parent Bin directory as a virtual directory within the child application.  When I try this I get a "Control Type cannot be found within the Control Assembly" error.

    For instance, I setup a parent application in the web root.  This parent application has a bin directory with all of the controls I want to use throughout all parent and child applications.  I create a sub-directory for the child application.  Within this directory I create a virtual directory pointing to the parent bin directory.

    Everything works fine when displaying in the browser, because the child application is not really an application.  All the references to the parent work great.  The problem is that within VS2005 the bin virtual directory shows in the solution explorer, but when I drop one of the controls on the page, cannot reference the directory.

    Is there a way to add a reference or to trick VS2005 into recognizing the bin directory?

    I know that you say that WAP is a better method, but it has more problems than using WSP, especially with our source control software.  If I could just find a way to get the bin directory reference working then we would have a very reliable and easy to use system for creating parent child applications.

    Thanks,

    Raymond
  • OK, I figured it out.  I added the controls to the GAC, and they no longer copy to the bin.

    I have decided to setup the root application as a WAP.  I am going to try setting up the sub-applications as WSP.  I can setup virtual directories within the sub-applications that point to the root application.  I can always add sub-applications as WAP if a good reason arises.

    Here is what I did:

    Created a WAP in the root, using the same methodology as mentioned above.

    Added all of the dll files I needed to the bin directory for the new site.  Registered the dll files in the GAC.

    Created a MasterPages directory within the root application.  Created a master page within that directory.  Added menu controls to the master page.

    Created a new web form and added the reference to the master page and added the content placeholder.  There was no way to do this when creating the web form.  Added a tab strip control within the content section.

    Tested the page, and it displayed properly.  The page displays properly within the designer as well.

    Added a directory within IIS under the root application.  Within the directory I added a virtual directory called MasterPages and pointed it to the MasterPages directory within the root application.

    Within VS2005 I added an existing web site to my solution (the new sub-directory).  I then deleted the web.config file, as you instruct above.

    I added a master page within the root of the sub application (with the same name as the one in the root application).  I then created a new web form and attached that master page.

    The master page directory from the root application displays, but if you choose that one instead of one in your sub-application the content section will not create properly.  The reason for the one in the sub application directory is to ensure that everything creates correctly when the page is generated.

    After the new page is generated, modify the source to point to the ~/MasterPages/ directory.  The master page from the root application will display properly in the designer and when the page is ran.  The master page you have in your sub application can either be deleted or left for when you create more pages.  It is not used except in the creation process.

    The methods I used are a little clunky, but they work pretty well overall.  There are no errors in the designer.  There is one bin directory, instead of multiple dll files everywhere.  There is one central place for master pages.  I am sure that other directories can be done the same way.  VS2005 does not seem to work when a pre-designated directory is done this way, like bin or app_data.  It might work for themes.  I have not tested that.

    I am not sure of the advantage of using WAP at this point.  These are some disadvantages I have found:

    When creating a new web form the option (checkbox) to select a master page is not available.

    When creating a DataSet within the App_Data directory, that DataSet does not show up automatically when creating a data source object within the Telerik Rad Controls I am using.  This is likely a problem with Telerik not VS2005, but it is still a problem.  See next item.

    When creating a DataSet it does not ask me if I want to put it into the App_Data directory.  I have to create it in the root and copy it into the App_Data directory.  Then it is available to the control.  Unless it is created in the root it does not work.

    Disadvantages of setting up this way is that you cannot access app_data from the root.  Datasets have to be setup independently for each application.  A virtual directory will not work.  It looks like this is due to the lack of a web.config file in the sub-application directory.

    I am sure that there will be other errors and work arounds.  This is an alternative to the WAP solution above, that seems to have some errors within the designer.

    Any suggestions for improvement?

    Thanks,



  • This is very close to out situation.  Except  our Master Page project is at the same IIS level (as opposed to a sub-project) as the other 15 web projects we currently have working under 1.1.

    Thus, when my page in a brother project (as opposed to a child project) refers to the master, it sees the file but can't see the controls on the master page.  Also tried creating a virtual directory BELOW the brother project which points to the master project but that doesn't change anything.  Note that I have not installed Web Application Projects yet but am opening the projects using IIS.  Can it be done without it?

    Any help would be appriciated!

    Reed C.

  • I've got another Problem:

    I have one MasterProject that has a .sitemap-file and a couple of subprojects containing .sitemap-Files. Funny thing is that the resx.-Files have to be in the masterpro, but that is another issue... At the moment I add the .sitmap-files from the subpros into the the sitemap of the masterpro using:

    <siteMapNode siteMapFile="~/SubProject1/Web.sitemap" />

    I expect the project to become larger and I don't want to touch the sitemap manually each time a new subproject is added. So, how do I merge or combine all existing sitemaps into one XmlSiteMapProvider programmatically? Any ideas or hints would be helpful!

    Thanks in advance!

  • Not able to access the master page custom defined properties like PageTitle from the content page getting compile time error "Error'System.Web.UI.MasterPage' does not contain a definition for 'PageTitle'. Please suggest............

Page 2 of 3 (42 items) 123