简体   繁体   中英

How to discover and load one web application into another?

I've been googling for a bit now, and maybe I'm not searching for the correct term. I want to have a single "shell" asp.net web application that is able to load/run other web applications (much like prism does with Silverlight xap files). However, I can't seem to find any verbage other than "sub projects", which require one to add the project to the solution. I simply want to drop WebApplicationB.dll into the Bin folder and have ShellWebApplication load the dll and display the default page in an iframe or something.

How can this be done or where can I find information on how this can be done?

Update: Offering a bounty to someone who can show code or point me to a sample project that shows how this can be done. Want to be able to "load" another asp.net web site/web application and its dependencies (dll or no) AND display that loaded asp.net web application's default.aspx start page without altering a Visual Studio solution that already contains the shell asp.net web application.

This is actually fairly trivial to accomplish; we do it.

The main key is that your "modules" should either have their own content folders or you need to be careful not to have the exact same file names at the same location.

Consider the following contrived example:

Shell
  \default.aspx
  \login.aspx
  \Images          <- images used by shell
  \css             <- primary CSS files
  \Pages\Accounts  <- all of the account editing pages here.

Module1
  \Module1\Pages       <- web pages specific to Module 1 
  \Module1\Images      <- images specific to module 1
  \CSS\Module1.css     <- Optionally, you can place the Module 1 CSS file into the main CSS directory.  

With this structure you'll be able to copy both web applications into the same target directory. Due to how .Net functions this will work just fine and both will be executed within the same process space.

Of course, you need a way for the Shell to know about Module 1. And you want to be able to deploy Shell without Module1. The best way here is to add an assembly project that contains the interface definition you need. You add a reference to this project to both Shell and Module 1. Something like:

Core
  \ObjectModel\MenuOption.cs
  \Extension\IAppModule.cs
  \Extension\PluginFactory.cs

Where IAppModule.cs looks something like:

public interface IAppModule {
  Collection<MenuOption> GetMenu( );
}

MenuOption.cs looks something like:

public class MenuOption {
  public string Href { get; set; } // url the option goes to
  public string Title { get; set; } // display name of the menu option
}

The PluginFactory.cs is similar to:

public sealed class PluginFactory {
  PlugingFactory() { }

  public static IAppModule LoadPlugin( string typeName ) {
    Type theType = Type.GetType(typeName);
    return (IAppModule)Activator.CreateInstance(theType);
  }
}

The purpose of GetMenu here is to return a collection of references to the available pages in the module.

Inside Module1 you would implement the interface like:

public class AppModule : IAppModule {
  public Collection<MenuOption> GetMenu() {
    Collection<MenuOption> result = new Collection<MenuOption>();
    result.add(new MenuOption() { Href = "~/Module1/Pages/AccountList.aspx", Title="Account List"});
    result.add(new MenuOption() { Href = "~/Module1/Pages/NewAccount.aspx", Title="New Account"});

    return result;
  }
}

So, at this point we have 2 web app projects and 1 assembly project. The web app projects don't know anything about each other.

The next step is to tell the Shell that Module1 exists. We do this by having a database table of available modules. You could do the same thing in a web.config file. The main thing is that the shell project needs the Type Name and reference to Module 1's AppModule class. For example: " Module1.AppModule, Module1 "

Then, inside your shell master page you can do something like:

protected void LoadMenu() {
  // get list of available modules, just assuming mdules is string[] 
  foreach(String moduleId in moduleIds) {
    IAppModule module = PluginFactory.LoadPlugin(moduleId);    // now you have a reference to the module
    Collection<MenuOption> options = module.GetMenu();
    // and now we have all of the menu options for that module...

  }
}

For bonus points, we have a Master page in the root of our shell project called "Main.master" Each of our modules also has a "Main.master" master page in their root. The ones in the modules have the build action set to none and copy to output set to Do not copy.

The master page is where we actually load the menu options. Also, all of the other masters within each module inherit from this primary one. Interestingly, descendent master pages don't care about the actual "type" of the parent, just the location of that page. This means you can control your main master page from the shell and have each module "inherit" that simply by NOT deploying their overall master page.

For example:

Shell
  /main.master  <- includes the basic CSS references, content structure and loads the various menus.

Module1
  /main.master  <- this file will NEVER be deployed and is only here to aid in testing the module independently of the shell
  /Module1/Module1.master <- inherits from main.master, adding other common elements for the module.

Because of how master page inheritence works, the Module1.master file refers to it's parent by "~/main.master". By not deploying the modules main.master and instead just deploying the shell's main.master we are given a LOT of flexibility.

At the end, you can deploy the shell project onto an IIS server. Later you can deploy ModuleX right on top of the shell project (no virtual directories needed) and it will just work.

The dll contains the compiled code of your web application. There is no point in 'loading the dll'. You probably want to load a control or a page, then let the user navigate to another page or control within this application which its code also contained in this dll. So there are a few options for you:

  1. Use an iframe and point it to load a page of the other web application. This will load the dll of that application in order to execute the code behind of that page. You can let the user navigate from that page to other pages of the application.

  2. Put a link in the shell application that when clicked will navigate the user to a page of the other application. Again, the dll of the other application will be loaded in order to execute the code behind of that page.

  3. Load a user control of the other application dynamically. In your shell application you can have Page.LoadControl and then add the control to some place holder in your shell application. The dll of the other application will be loaded in order to execute the control's code behind. The Page.LoadControl requires you to give the a URL to the ASCX file. You can put this URL in your web.config file or in your database and can load different controls (which can also be controls of different applications) in your shell application.

  4. Use reflection to dynamically create objects of classes of the other application. If you do so, you would probably want your shell application to introduce an interface which can be implemented by classes of other web applications, so when you use reflection to create an instance of such a class, you know what interface it implements, and can execute its methods.

The two first options are the easiest, the two other options are more advanced and are more powerful. If you give some more information about your use case perhaps I can recommend what would best fit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM