Updates to Code

Topics: Developer Forum
Mar 6, 2007 at 9:01 PM
Thank you for creating this wonderful project. It has saved our .NET projects here, as we load our MasterPages and common error pages from a central assembly which is referenced from multiple apps. I have made some changes to the code if you are interesting in including them:

- MasterPageFile is set automatically by the code if needed (if it detects a master page served as precompiled) at the latest possible moment, allowing for a MasterPageFile property to be set in the aspx source for Designer support.

- changed PrecompiledMasterPage class to support nested master pages

- changed PrecompiledPageFactory to return a handler from an assembly installed in the GAC

Let me know how I should contact you ar send me an email if you would like to take a look at the code.
Coordinator
Mar 7, 2007 at 8:45 AM
Thank you, its good to know the projects helped you. Theres not been many posts by other people and I often wonder if there are many people out there using it!

Those additions sound very interesting, I've sent you a message with my e-mail address if you'd be so kind as to send me your code.

Cheers
Mar 26, 2007 at 12:01 AM
Hi Jeff,

Any chance I could get a copy of your changes to as that sure would save me a lot of time and heartache...

cmschick@insightbb.com

Chris



jam40jeff wrote:
Thank you for creating this wonderful project. It has saved our .NET projects here, as we load our MasterPages and common error pages from a central assembly which is referenced from multiple apps. I have made some changes to the code if you are interesting in including them:

- MasterPageFile is set automatically by the code if needed (if it detects a master page served as precompiled) at the latest possible moment, allowing for a MasterPageFile property to be set in the aspx source for Designer support.

- changed PrecompiledMasterPage class to support nested master pages

- changed PrecompiledPageFactory to return a handler from an assembly installed in the GAC

Let me know how I should contact you ar send me an email if you would like to take a look at the code.

Coordinator
Mar 26, 2007 at 8:31 AM
Check out version 1.3 in the releases page, its got implimentations of Jeffs changes (inc. source code).

Graham


cmschick wrote:
Hi Jeff,

Any chance I could get a copy of your changes to as that sure would save me a lot of time and heartache...

cmschick@insightbb.com

Chris



jam40jeff wrote:
Thank you for creating this wonderful project. It has saved our .NET projects here, as we load our MasterPages and common error pages from a central assembly which is referenced from multiple apps. I have made some changes to the code if you are interesting in including them:

- MasterPageFile is set automatically by the code if needed (if it detects a master page served as precompiled) at the latest possible moment, allowing for a MasterPageFile property to be set in the aspx source for Designer support.

- changed PrecompiledMasterPage class to support nested master pages

- changed PrecompiledPageFactory to return a handler from an assembly installed in the GAC

Let me know how I should contact you ar send me an email if you would like to take a look at the code.


Mar 26, 2007 at 3:06 PM
Hi Graham,

First of all, thank you for the reply and this project. I too am wondering why we don't see more responses, it's very valuable to be able to precompile user controls and pages for site upgrades. Anyway, I am having some trouble understanding how it is all put together. I have been trying to set a break point in the Wapl library but cannot get it to stop on it. I tried removing the reference and adding the library as a project reference but vs complains that a reference already exists.

In the end, I am trying to see how to get the virtual path to my user controls. I am working on a custom WebParts Catalog that reads webpart types from the dlls in the bin at run time and loads them into the catalog. I need to be able to also load user controls (as webparts) that have a base type as "PrecompiledUserControl" to my catalog at run time as well. I am using the WebPartManager.CreatWebPart() and all is working well but it complains about "type usercontrol" requires path argument.... Do you have any idea how I can set the path?

Also, would you mind giving me a brief explanation how I can replicate the release project in a new project? I tried it but for some reason my version of the WAPL Test Library created a InSite.Web.WaplTestLibrary.partial.dll instead of the InSite.Web.WaplTestLibrary.dll. Am I missing something? At what point do I need to run the WAPL Tool?

Thank you in advance for your help.

Chris
Coordinator
Mar 27, 2007 at 10:18 AM
Hi Chris,

I think the level of responses may be due to the lack of documentation about the project, having people post their problems is a good way for me to figure out whats needed to know and how to explain it best.

I think a key concept that I need to get across is that the WAPL Tool (which is included as a post-build step in the project libraries properties and runs automatically) actually takes the .partial.dll which visual studio has compiled (in the bin folder) adds the extra information that .aspx/.ascx/*.master files contains and merges them into a new dll in a sub-folder of the project called wapl. Using this other folder stops visual studio getting confused about which dll is which.

So when you are referencing a library project from another web site/web application project you must browse to the .dll in the wapl sub-folder and use not the project itself. Its also wise to set up your solution so it has a dependancy to the library project. This will make it recompile the library project when you compile/run the web site/web application project (this is done automatically when you use a project reference).

I too have tried using web parts, and have found a few extra difficulties with the way microsoft handles them. If a control decends from UserControl it seems to handle them differently and this behavour is burried deep inside their code. I've developed a class in InSite.Web.Wapl called InSite.Web.UI.WebControls.WebParts.SqlPersonalizationProvider which overrides SavePersonalizationState to help correct this.

Although I don't think that will rectify your particular problem of creating them programmatically. Just checking but you are implementing IWebPart on your PrecompiledUserControl classes?

Cheers,
Graham


cmschick wrote:
Hi Graham,

First of all, thank you for the reply and this project. I too am wondering why we don't see more responses, it's very valuable to be able to precompile user controls and pages for site upgrades. Anyway, I am having some trouble understanding how it is all put together. I have been trying to set a break point in the Wapl library but cannot get it to stop on it. I tried removing the reference and adding the library as a project reference but vs complains that a reference already exists.

In the end, I am trying to see how to get the virtual path to my user controls. I am working on a custom WebParts Catalog that reads webpart types from the dlls in the bin at run time and loads them into the catalog. I need to be able to also load user controls (as webparts) that have a base type as "PrecompiledUserControl" to my catalog at run time as well. I am using the WebPartManager.CreatWebPart() and all is working well but it complains about "type usercontrol" requires path argument.... Do you have any idea how I can set the path?

Also, would you mind giving me a brief explanation how I can replicate the release project in a new project? I tried it but for some reason my version of the WAPL Test Library created a InSite.Web.WaplTestLibrary.partial.dll instead of the InSite.Web.WaplTestLibrary.dll. Am I missing something? At what point do I need to run the WAPL Tool?

Thank you in advance for your help.

Chris

Mar 27, 2007 at 12:01 PM
Hi Graham,

I agree and I think most people have resigned to thinking that including precompiled user controls and page libraries is impossible.

Ah, thanks for the tip on the reference to the precompiled library from the website.

Yes, I am implementing the IWebPart interface on my user controls so that I get a better designer experience on the aspx where these user controls are added to a zone. Basically it just lets me set the properties on the control itself and results in the designer seeing properties like authorizationfilter etc.. as being valid aspx attributes. The other benefit is that the user control is still a user control but plays nicely as a webpart as well.

I appears to me that once the libraries are merged that the virtual path to the control from the main website is "~/MyControl.ascx" so I may try setting the AppRelativeVirtualPath property on the control after I do an Activator.CreateInstance(myControlType) and see if that works. i.e.

UserControl uc1 = Activator.CreateInstance(myControlType);
uc1.AppRelativeVirtualPath = "~/" + myControlType.Name;

What do you think?

Right now I am having problems with the build of my precompiled libary. It is telling me that 'clientBuildManager.CompileFile(userControlVirtualPath)' could not load type Test.Web.UI.MyControlBase. Unfortunately I only have a basic understanding of how it works at this level in the code. So for me personally, what I need to know is the naming conventions. For example, what do each of command line args really mean, and what do they map to? What I mean is, which event args need to match the names of classes, namespaces, and files...? Is there a correlation between the root namespace of Insite.Web and the namespace declared on the user control that is required for the merge process?


Another question I have is... is the Insite.VisualStudio.Wapl project required to get this all working? I see a number of ResolveAssemblyReference.cache files in the project but I'm not really sure what the project itself does. Can you explain that and do I need it to get things working?

Thanks,

Chris

Mar 27, 2007 at 2:54 PM
Okay I got that part figured out (the cannot load type thing). In a VB.NET project the rootnamespace property on the project needs to be blank on the property page because it was appending that to the namespace defined on the user control code behind so I was getting Test.Web.UI.Test.Web.UI in the assembly. So now my precompiled library builds and merges!

I should be good to go now as long as the AppRelativeVirtualPath setting works.... we'll see.

Thanks.

Chris
Mar 27, 2007 at 6:09 PM
Okay, FYI. Setting the AppRelativeVirtualPath="~/MyControlFileName.ascx" works both on the page and and in my custom catalog but for some reason the actual content of the webpart is not there (the user control). Also, Unfortunately it does not work on a second visit to the page after I have added the control from the catalog because it is looking for the path data in saved personalization state... I'll be working on that now but if you have any pointers I'd love to hear them.

Thanks,

Chris
Coordinator
Mar 28, 2007 at 9:10 AM
Good to see your making some progress.

As far as I'm aware AppRelativeVirtualPath is only used by the WebPartManager to work out if the control is authorized. I'd recommend using the control declaratively in a page to check that it works correctly outside of the webpart system and then (still declaratively) in a WebPartManager. You may end up having to inherit from WebPartManager to override some behavour.

Your second problem about revisiting personalization state can be fixed by using the InSite.Web.UI.WebControls.WebParts.SqlPersonalizationProvider class from the InSite.Web.Wapl as your personalizaton provider (or copy the functionality of the SavePersonalization method to your own provider).

Hope that helps,
Graham


cmschick wrote:
Okay, FYI. Setting the AppRelativeVirtualPath="~/MyControlFileName.ascx" works both on the page and and in my custom catalog but for some reason the actual content of the webpart is not there (the user control). Also, Unfortunately it does not work on a second visit to the page after I have added the control from the catalog because it is looking for the path data in saved personalization state... I'll be working on that now but if you have any pointers I'd love to hear them.

Thanks,

Chris

Mar 29, 2007 at 3:54 AM
Okay, stupid me... I was adding the 'Base' class and not the actual control name class so now I can dynamically load the compiled user controls into a dynamically created catalog at run time and then load them into a zone without problems.

However, I do still have the same problem when revisiting the page. I have your SqlPersonalizationProvider in place but it skips right past all of the controls because the customProperties("DynamicWebPartsShared") is always null. Where and how are you setting that custom property? It seems to me that if the WebPartManager will allow it to load once, it will allow it to load a second time but it just doesn't seem to know where to look.

For example. My test compiled user control is named MyWatchList.ascx. Even if I manipulate the AppRelativeVirtualPath property, when the WebPartManager hits the LoadPersonalizationState it defaults to looking for this control in "~/MyWatchList.ascx"... I see that you have this pretty much figured out (in terms of the virtual path to actual path mapping) in your WebResourceFromPath.cs and the PrecompiledPageFactory.cs classes so I thought you would know how to tackle this one...

Once again, any help you can provide is much, much, much, appreciated!

Thanks,

Chris
Coordinator
Mar 29, 2007 at 10:25 AM
Easy mistake to make. I think the project could do with some Visual Studio templates for creating library user controls/web part user controls/pages/master pages.

If you could post a dump of the customProperties you are getting then I might be able to see whats going on. I can't remember why that condition is there and I don't have any code with me at the moment to step through, but I'll take a look later when I'm on my own machine.

Keep at it you'll get there eventually :o)

Graham


cmschick wrote:
Okay, stupid me... I was adding the 'Base' class and not the actual control name class so now I can dynamically load the compiled user controls into a dynamically created catalog at run time and then load them into a zone without problems.

However, I do still have the same problem when revisiting the page. I have your SqlPersonalizationProvider in place but it skips right past all of the controls because the customProperties("DynamicWebPartsShared") is always null. Where and how are you setting that custom property? It seems to me that if the WebPartManager will allow it to load once, it will allow it to load a second time but it just doesn't seem to know where to look.

For example. My test compiled user control is named MyWatchList.ascx. Even if I manipulate the AppRelativeVirtualPath property, when the WebPartManager hits the LoadPersonalizationState it defaults to looking for this control in "~/MyWatchList.ascx"... I see that you have this pretty much figured out (in terms of the virtual path to actual path mapping) in your WebResourceFromPath.cs and the PrecompiledPageFactory.cs classes so I thought you would know how to tackle this one...

Once again, any help you can provide is much, much, much, appreciated!

Thanks,

Chris

Mar 29, 2007 at 8:16 PM
I would post a dump but since there are no properties... the dump would be blank. I have contacted Microsoft at this point to see what they can tell me about the controls not persisting as web parts.

It's very strange. Here is what I have noticed at this point.

Adding my control tag to the page in the designer creates the control witout problems as long as I don't create that control tag in a web zone. But if I drag and drop the control on the designer to a webzone, it creates it perfectly and it adds an attribute to the control (AppRelativeVirtualPath="~/MyControlName.ascx")

Now, since that control is static, it stays on the page between postbacks and remembers the personalization state of that control. However, when I add a control dynamically in the OnLoad event, it also saves some personalization state but it errors when trying to locate "~/MyControlName.ascx". For some reason, because this is control derives from UserControl, the WebPartManager expects to see a path instead of a type like it does for any other type of control like full blown server control or web part.

My thought is that since it is a standalone compiled control and everthing needed to instiate it is in the assembly, it should be looking for a type and not a Path. Anyway, we'll see what Microsoft comes up with on this one, I hope they find me a solution and don't just blow me off. It sounds like they never thought it would be possible to have an assembly of precompiled user controls. Otherwise, they would have surely thought of this scenario right? In my opinion they should make whatever changes are necessary to support this scenario as this scenario was created using standard coding practices and does not use reflection to force things. The only Reflection I can see is using it to sort of 'auto' command the aspnet_merge.exe utility but that shouldn't raise any eyebrows!

Later