We have a solution with multiple web projects, and there are some pages that should be present in several of them. So we'd need some sort of a shared project which contains aspx files, and which can be referenced by other web projects.
Now there are a few implementations out there:
One implementation described by ScottGu which involves building the shared project, and than copying the output aspx into the host project, and referencing the dll of the aspx. This method has the disadvantage that if the apsx gets modified it must been recopied.
Another option, based on David Ebbo's post would be to convert the aspx into ascx-es which can be referenced as custom controls, and than include those custom-control-aspx-es into the host project inside of some placeholder pages. But my concerns are: can all apsx pages transformed into an ascx? I mean there's no Page.LoadComplete event in user controls for example.
And yet another option is to use virtual directories that map into the shared webproject, as described in a Microsoft KB article. The problem again with this method is that the shared aspx-es must be in predefined directories(that is the virtual directory).
If the name of virtual directory overlaps a physical directory, the virtual overrides it and no pages from the latter can be used.
Is it perhaps possible to merge these two together?
Any thoughts? Thanks in advance
P.S. How about debugging the shared pages?
I solved this problem by making shared Class Library that contains .ascx controls. Have not found real difficulties when converting from .aspx pages to .ascx controls. Found this sample by ScottGu really simple and good place to start. http://webproject.scottgu.com/CSharp/usercontrols/usercontrols.aspx.
The solution which we are using is ScottGu's method, which involves copying the aspx files from the shared project to the host projects.
A post build event in the shared project copies the files to their place, like this
xcopy "$(ProjectDir)Forms\Techs\AddEditTech.aspx" "$(SolutionDir)..\TTAdmin\Forms\Companies" /i /d /y
if errorlevel 1 goto BuildEventFailed
xcopy ....
goto BuildEventOK
:BuildEventFailed
echo POSTBUILDSTEP for $(ProjectName) FAILED
exit 1
:BuildEventOK
echo POSTBUILDSTEP for $(ProjectName) COMPLETED OK
Have you thought about baseclassing the functionality into classes that inherit from Page and place those classes in the shared DLL. All implementing applications could then implement that page by inheriting from it and still be able to change functionality assuming the base classes provide overridable methods. I've had pretty good success with this when I had a lot of pages that were used in many applications and all had the same code. Just a possibility.
Have you considered service oriented development? Build the functionality into services you can share. Build your functionality like widgets. This way you only have one codebase but you can use it in multiple sites.
Think outside the (.Net box)
Related
I am inheriting some ASP.NET code (I am an OS guy, not a web dev (yet ;-)). The solution has been re-factored and there are multiple projects (libraries and asp.net sites) in it. Aside from the libraries, there are two asp.net projects (called MAINSITE and SUBSITE). Only MAINSITE is being used as the official site (as an asp.net site), and MAINSITE has a depency on the code in the SUBSITE asp.net site, but doesn't use the site itself. I am trying to figure out how to clean this up and convert SUBSITE into a library.
My quick question is, whenever I debug the MAINSITE (set as default), it runs two asp.net processes: MAINSITE and SUBSITE. And so, at the very least, how can I avoid this? Is there a quick/temporary solution to this?
My detailed question is this:
What makes an asp.net site an asp.net site? For instance, in C the difference between an dll and exe could be defined (superficially anyway) as the presence of a main, and potential export information for the library (among other things, of course). If I were to convert an exe to dll I might:
1. remove the main code
2. make sure the public interface was correct (and exported correctly)
3. convert the makefile to build a dll rather than an exe.
Can someone point me to some similar steps for asp.net to .net lib?
Maybe:
1. get rid of index.aspx
2. get rid of web.config
3. any *.cs files to remove?
4. how do I change the properties?
5. any gotchas?
Thanks so much for your help.
Details: Visual Studio 2008/.NET 3.5
There are many, many components to make an application run as an ASP.Net application. However, in terms of your actual Web Application project, there's really not that much difference between it and generic library code except for the fact that much of your code relies on the existence of the HttpApplication runtime.
Any code that utilizes the System.Web (especially System.Web.UI) is going to be suspect in terms of having this dependency. For example, all the code in page or webcontrol event handlers (Init, Load, PreRender, etc.) relies on the fact that there is an HttpHandler (running inside an HttpApplication) raising these events. If you run the same WebControl out of a library that's not in an ASP.Net project, none of this will ever happen and the control will be useless. However, that exact same library would be quite functional if executed in the context of an ASP.Net process.
It really boils down to what process you're running the library in. In most cases, ASP.Net processes are spawned by IIS, although it is possible to host an ASP.Net process in other types of programs as well.
There isn't a simple 5-step process for converting a web project to a library unfortunately. But as a rule of thumb, webcontrols, .aspx and .ascx codebehind aren't going to convert.
For a more detailed look at what makes code into an ASP.Net program, see Rick Strahl's "A Low level look at ASP.Net".
If you go to "File" > "New" > "New Project..." and then click on the (assuming you're using C#) "Visual C#" in the list on the left, you're given the ability to create a "Class Library" project. You can extract all the relevant code to one of these and then reference in in your "MAINSITE".
You will need to reference it in the "References" section of your MAINSITE project and may need to import your library project using the import keyword.
I'm onto a real head scratcher here ... and it appears to be one of the more frustrating topics of ASP.NET.
I've got an assembly that implements a-lot of custom Linq stuff, which at it's core has zero web functionality. I have an additional assembly that extends this assembly with web specific behaviour.
The web specific behaviour comes with a couple of user controls marked up inside ASCX templated UserControls.
I'm having trouble putting a nice finish on this assembly so that it is simple to redeploy for use in other applications. Let me run through what I've tried so far:
Copied the ASCX files to the consuming web application using build events; far from ideal and quite a deployment nightmare.
Implemented a custom VirtualPathProvider and embedded the ASCX templates within the assembly as embedded resources. Unfortunately when using the Register directive in the consuming application it creates the designer declaration as a UserControl, where I would require a declaration of the actual control type; unforeseen (typically) and undesirable.
Created a Web Deployment Project to compile the UserControls, but the compiled user controls then become part of another assembly, and no longer descend from the class definitions in my web assembly--the assembly needs to instantiate them dependent on the request context.
So number 1 is just crap, number 2 doesn't give me the type support I desire and number 3 I think I'm about to produce a reasonable solution with:
Lump all non-control classes into the App_Code folder, prepare a factory class that will construct an object of the desired control type using reflection and the expectation that the type being reflected will be present in the deployment output (hopefully guaranteed by the presence of the ClassName attribute in the Control directive).
Theres also always the other option of rewriting the ASCX controls into custom controls, but just don't have the resources to consider it at the moment, and we've got no expertise in doing that, and they work fine as UserControls.
Am I missing something obvious, something maybe much simpler, or is this just purposefully difficult? I've read stories of the ASP.NET compilation process being very unfortunate in it's design on my travels across this topic.
Well I think I've done it ... by being mindful of a few of a few annoying pitfalls with my last approach, I recommend the following when compiling ASCX user controls in a Web Application Project using a Web Deployment Project:
Avoid putting classes in App_Code unless they're standalone or helper classes, ASP.NET treats this as a speshul folder, the meaning of which is lost on me, mayhem, confusion and chaos follows. Code in this folder does get output in the Web Deployment Project, though.
Pay close attention to your assembly names, their root namespaces and deployment output assembly name- you'll get access is denied errors if you have any naming conflicts during the aspnet_merge process.
Ultimately you'll most likely end up deploying 2 assemblies, I tried to create only one but the deployment output was still pointing to type definitions in the source assembly. This isn't a problem if you don't have any other types in your Web Application Project--I have so it was a problem for me. In my case, my final output was:
<Organisation>.<TechnologyName>.Web.DLL - Compiled Web Application Assembly (containing the ASCX templates)
<Organisation>.<TechnologyName>.Web.UI.DLL - ASP.NET Compiled UserControl assembly, created by Web Deployment Project
Clean often, and check that the Web Application Project's bin and obj paths are cleared of any previous junk built when you perhaps hadn't finalised your namespace or assembly naming scheme--the Web Deployment Project will be quite keen to include these, causing a fine mess.
Check your imported namespaces, the ASP.NET compiler likes to refer to the Import directive in the ASCX template, and it also considers imported namespaces present in web.config's <configuration><system.web><pages><namespaces> element, tweak if you get unknown definitions appearing during the deployment process.
Have some patience spare, it's quite tricky! But you do get some nice re distributable UserControls at the end of it!
Phew!
I am trying to better understand how the App-Code folder operates, and in particular I am curious how new objects that a new class in the App-Code folder are included in the current AppDomain. Is a second, temporary AppDomain created in the same manner as when I compile new objects with the CodeDom?
In many ways the capability of moving new classes / objects into a Web Application is very compelling. Rob Connery's MVC Storefront is a good illustration. If you have used the App-code folder to deploy new functionality were there any trade-offs or gotchas that should be considered?
UPDATE:
I found an article in CoDe Magazine with this interesting passage:
Your application-specific code can go
inline of the ASPX page or control, it
can go into a CodeBeside partial
class, or you can create completely
autonomous classes in the APP_CODE
folder. The APP_CODE folder is a
special folder in an ASP.NET 2.0
project and any non-page or
control-related source code in your
Web project must go into this folder.
ASP.NET treats the content of APP_CODE
like a library project and compiles
the content into a separate assembly.
This assembly is then referenced by
all of the page or directory-level
assemblies that ASP.NET creates from
your ASPX/ASCX pages that use any of
the classes defined in APP_CODE.
My question still stands - is a second AppDomain created that supports this libary, and if so are the impacts on performance minimal?
I don't know the details, but it will certainly be in different dynamic assemblies. A class can't be in another AppDomain. Only an instance of a class can be in another AppDomain, and then it's really a hassle to access from another AppDomain (only through remoting)
This question is a follow up to my question about sharing resources between web applications, because I have not yet found a good solution.
I have a web application with user controls and resources that are shared by three other web applications.
Solution
|
+-CommonControlsWebApp
| +- resources
| | +- images
| | +- scripts
| | +- stylesheets
| +- UserControls
|
+-WebApp1
|
+-WebApp2
|
+-WebApp3
This is what I know this far:
I can not compile CommonControlsWebApp into a single dll since I am creating user controls. This is only possible with custom server controls, where everything is in the code-behind file. So I need a way to share the ascx files between the four projects.
Copying the files from CommonControlsWebApp into the three other projects does not update their files in the solution explorer. I would have to 'add exting items' all in all three WebApps when a file is added or renamed in CommonControls.
Changing to the Web Site model would remedy this, but I am worried about the compile time for WebApp1-3 if I do this.
'Add as link' does not work for directories.
I could use Subversion to share the files between the projects, but i believe that this would require me to check the files in and out again all the time if I am developing a user control that I have to test through one of the WebApps.
Can it really be true that ASP.NET does not have a good solution for this? How are you guys organizing large web applications?
Edit: Thanks a lot for all the answers. I am going to copy my user controls with a build event for now, and then see if we have time to refactor them into server controls.
The way we do it at my present company is to make sure CommonControlsWebApp
is a WebApplication, not a web site. Then you use names for the folders that would help identify it as the common ones that are distinct from the individual web apps. (CommonUserControls instead of just UserControls)
In your other web apps, you create a virtual directory to the CommonUserControls, etc, and add a file based reference to the CommonControlsWebApp.dll
This requires you to use IIS for development (not casini), and Visual Studio won't believe that the controls really exist, but it will work at runtime, and you can build just fine with only warnings about blahblah.ascx or blahblah.master path invalid.
If you do use common master pages and Visual Studio 2008, you will need SP1 for 2008 and use a __fallback.master in the root of the individual web projects to go in to design mode.
However, I saw this on another thread, and I am going to look into doing more like this:
http://webproject.scottgu.com/CSharp/UserControls/UserControls.aspx
You could compile it into a dll
Turning an .ascx User Control into a Redistributable Custom Control
Brief Outline of the Steps
The basic steps to make this happen
are as follows:
Write your user control as you normally would, typically using the
Visual Studio designer.
Test it using a simple page before trying to deploy it.
Deploy the application to precompile it.
Grab the user control's assembly produced by the deployment step, and
you're essentially done: You have your
custom control.
Finally, use your custom control in other apps
Further info here http://www.nathanblevins.com/Articles/Compile-a-Web-User-Control-into-a-DLL-.Net-c-.aspx
In order to share controls between web apps, the only way I found was to either rewrite them into server controls or to use virtual directory to make the user controls actually in folder be in each project.
Unfortunately, asp.net doesn't really have a good solution for this. The same is true for sharing master pages.
You might consider using source control and sharing your controls at that level. We do this for a sizable user control library and it works quite well.
Using SourceGear Vault but you should be able to do this with any source control product.
Check this post for how to solve this issue.
The basic idea is to change your project to have a prebuild step to copy over the .ascx files to a subdirectory of the web application. Then just refer to those copies when using them. Of course you also need to reference the UserControls assembly as well.
One option is to try "Add existing" and in the dialog that appears, the OK button has a drop arrow next to it, change it to Add with a link.
If that doesn't work, rewrite your controls as Custom Controls.
It will take a little while, but will make it much more maintainable in the future.
hey this is not the best way to do things but i used to do this in my asp.net 1.1 days - you can try this - shift your user controls into a seperate project, and publish this project as a virtual directory under iis
as long as you are not using codebehind - your updates would be cool (only update shared user control folder)
if you do use codebehinds - redeploy the user control dlls into different projects
once you are done with this - map these user controls into all projects using their virtual paths
check these links - http://aspadvice.com/blogs/ssmith/archive/2006/10/05/Tip_3A00_-Share-User-Controls-Between-Applications-in-ASP.NET.aspx
AND
http://www.123aspx.com/redir.aspx?res=30887
I have two different asp.net web applications both referencing the same dll e.g. SharedLibrary.dll.
I want to know if there is a way of adding some web.config setting to one of the application's config files to avoid the need to have two copies of the dll lying around.
My [simplified] directory structure is as follows:
\root
\Admin
\web.config
\Addins
\AdminWebAppPage.aspx
\bin
\AdminWebApp.dll
\SharedLibrary.dll <- this is the duplicated dll (I'd like to remove it from here ideally)
\Websites
\MyWebsite
\webroot
\web.config
\MainWebPage.aspx
\bin
\MainWebsite.dll
\SharedLibrary.dll
If you register the assembly in the Global Assembly Cache (GAC), all your apps can access it without having a copy around. However, from a versioning and deployment perspective, I'd say keeping a per-site copy is preferable.
Clarification: keepin a per-site copy is preferable when the sites are not related. Obviously if a shared library changes, you'd want both the main web site and the admin site to get the updated copy. :-)
I have done this in the past where virtual ROOTS under a website shared a DLL. That is, I had a website with some DLL's and an administrative virtual root underneath it. Since it is a child of the main website it inherits the website's DLL's. But I'm not sure about seperate websites...
If you're on a Vista machine you could look at using a NTFS symbolic link
If you're pre-Vista but on Win2k or later a NTFS Junction Point might help
You can put that DLL in Directory where all web-apps you want this DLL to be shared among have the read rights.
In the Application_OnStart event you can dynamically load the assembly using this code..
Assembly SampleAssembly;
SampleAssembly = Assembly.LoadFrom("c:\\Sample.Assembly.dll");
And you can also try resolving the reference by using Assembly_Resolve event.