Creating a plug-in based WebApp

M

Mats Lycken

Hi,
I'm creating a CMS that I would like to be plug-in based with different
plugins handling different kinds of content.
What I really want is to be able to load/unload plugins on the fly
without restarting the application.

What I did was to create an AppDomain that loaded the plugins and
everything was great, until I tried to pass something else that strings
between the domains...

My plugins inherit CompositeControl so that I can easily load .ascx file
to display the different dialogs and data in my plugins, I then do a
placeHolder.Controls.Add(plugin); to display the plugin data on my webform.
The problem is that I'm not able to transfer the plugin accross the
AppDomains since CompositeControl isn't Serializable.

I tried to make my base class inherit ISerializable and now I don't get
'doesn't support serialization' error anymore, but now it complains that
it can't find the assembly of my plugin when I try to display the contents.

My AppDomains look something like this:

PrimaryDomain
CMSCore
PlugInBase

OtherDomain
PlugInBase
StaticPage

My primary domain just knows about the PlugInBase class which implements
all the common public methods that I need, but it complains about the
StaticPage assembly anyway.

I hope I'm somewhat clear in what I'm trying to do and that anyone might
have any suggestions to what I can do.

Thanks in advance
/Mats
 
G

garethdjames

You can pass the object by reference instead, but as you are already
inheriting from CompositeControl you can't do this directly,

You will need to use the delegate pattern here,

Create an interface that covers all the methods on your plugin, make
the plugin implement it

Create another class that inherits from MarshalByRefObject, make this
object also implement your interface.

The class (that implements marshalbyrefobject) should have a property
of your plugin type,

then for the methods that you need to implement (interface methods)
simply route these to the plugin (via the property)

a bit long winded but as we can't do multiple inheritence this is one
way of getting around this,
 
M

Mats Lycken

Thanks for the fast reply!

I've already done this but it doesn't work for me... the thing is that I
want to add my control to a placeholders control collection, then I need
a direct reference to the plugin so that I can add it.

My plugin uses .ascx files to display the data and I can't create an
instance of it without having access to the WebForms context (as I
understand it), so I need to add the plugin the usual way,
Controls.Add(plugin);
 
S

Steven Cheng[MSFT]

Hi Mats,

The Mutiple subdomain Add-in architecture is ususally used in many destop
application, seems not quite common for asp.net scenario. Anyway, based on
my understanding, we'll meet the following problem here:

1. For ASP.NET's page processing, it is request/response based. So each
time a request is processed in a server worker thread( page class and other
control instances are contructed during this server pipeline....) , after
that , all the pages and control instances are destroyed and page content
being flush to clientside.... (later a new post back to server cause a new
worker thread and page structure to be constructed.....). So I think we
should not implement those add-ins as control, if so, we'll need to create
them in each request, and also I don't think ASP.NET page model will
support cross appdomain control communication.... So we need to
implement add-in as separate compent classes which will be loaded into
ASP.NET worker process (in separate appdomain ) at startup time .

2. Then, since we create those Add-in appdomains in asp.net woker process
(at startup time), what we need to do later is communicating with those
addins in the appdomain, this is another hard problem. What I can get
currently is creating those add-in instance's proxies at start up
time(right after they've been created in cross domain) and store these
proxy references in a gobal collection (ApplicationState or Application
Cache...). Thus, all the later requests can access them in events code....

Anyway, though this is possible, I really feel a bit nervous on it since
creating multiple sub appdomain in ASP.NET process may make it a bit
unstable and cross domain communication will hurt the ASP.NET runtime
performance .....

Thanks,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)


--------------------
| Date: Wed, 23 Nov 2005 19:07:04 +0100
| From: Mats Lycken <[email protected]>
| User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| X-Accept-Language: en-us, en
| MIME-Version: 1.0
| Subject: Re: Creating a plug-in based WebApp
| References: <[email protected]>
<[email protected]>
| In-Reply-To: <[email protected]>
| Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| Content-Transfer-Encoding: 7bit
| Message-ID: <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| Lines: 1
| Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!tk2msftngp13.phx.gbl
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:360511
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Thanks for the fast reply!
|
| I've already done this but it doesn't work for me... the thing is that I
| want to add my control to a placeholders control collection, then I need
| a direct reference to the plugin so that I can add it.
|
| My plugin uses .ascx files to display the data and I can't create an
| instance of it without having access to the WebForms context (as I
| understand it), so I need to add the plugin the usual way,
| Controls.Add(plugin);
|
| (e-mail address removed) wrote:
| > You can pass the object by reference instead, but as you are already
| > inheriting from CompositeControl you can't do this directly,
| >
| > You will need to use the delegate pattern here,
| >
| > Create an interface that covers all the methods on your plugin, make
| > the plugin implement it
| >
| > Create another class that inherits from MarshalByRefObject, make this
| > object also implement your interface.
| >
| > The class (that implements marshalbyrefobject) should have a property
| > of your plugin type,
| >
| > then for the methods that you need to implement (interface methods)
| > simply route these to the plugin (via the property)
| >
| > a bit long winded but as we can't do multiple inheritence this is one
| > way of getting around this,
| >
|
|
 
M

Mats Lycken

Hi Steven,
I rewrote my code some and abandoned the idea of having a separate
AppDomain for the add-ins. What I did instead was to create an object
factory that sits in my primary appdomain and creates instances of my
add-ins for each request. The add-ins are quite lightweight, just
parsing some parameters and loading the correct UserControl.

The add-in inherits CompositeControl so I can simply do a:
Control userControl =
this.Page.LoadControl(RequestedControlPath);
this.Controls.Add(userControl);
in my add-in to load the userControl. I then do a
Controls.Add(addInObj); on a placeholder object in my page.
Everything is dandy and postback works like a charm.

But I'm not that convinced that it is the best way to do it. Will my app
suffer a lot perfomance wise by this architecture?

Btw, which is the best way to restart a webapplication to make it reload
my addins. I would like to initiate the restart myself so that I can
minimize the downtime, ie. putting all the files in the correct place
and just click "Restart" and the webapp is up and running within a second.
 
S

Steven Cheng[MSFT]

Thanks for your response Mats,

Regarding on your further quesitons:

But I'm not that convinced that it is the best way to do it. Will my app
suffer a lot perfomance wise by this architecture?
================================================
Of course, dynamically adding webcontrols will add overhead to the asp.net
runtime at serverside processing. Also, since you add many additional layer
to abstract the "Add-in" /WebControls relationship.... that'll make the
application's performance more pressed. I suggest you turn on the Trace to
see how much time a typical page which use your current control/add-in
model will consume at serverside processing (normal loading and postback
processing).... Also, I think such application architecture suits
intranet application where network bandwith won't be the problem and the
concurrent requests number won't be two high...


Btw, which is the best way to restart a webapplication to make it reload
my addins. I would like to initiate the restart myself so that I can
minimize the downtime, ie. putting all the files in the correct place
and just click "Restart" and the webapp is up and running within a second.
================================================

I'm afraid there is no explicit or standard interfaces for us to manually
restart an asp.net application(appdomain). Restaring is controled by
runtime itself whenever there occur some certain incidents or meet some
certain points. e.g. when we change the components in private "bin" dir or
modify some critical setting in web.config.....

Why not just create and hold those add-in class instances in some
application cache , and when you need to update them , just remove them and
create new instances and update the caches ?

Thanks,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)



--------------------
| Date: Fri, 25 Nov 2005 11:33:36 +0100
| From: Mats Lycken <[email protected]>
| User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| X-Accept-Language: en-us, en
| MIME-Version: 1.0
| Subject: Re: Creating a plug-in based WebApp
| References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
| In-Reply-To: <[email protected]>
| Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| Content-Transfer-Encoding: 7bit
| Message-ID: <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| Lines: 1
| Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP12.phx.gbl
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:360872
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Hi Steven,
| I rewrote my code some and abandoned the idea of having a separate
| AppDomain for the add-ins. What I did instead was to create an object
| factory that sits in my primary appdomain and creates instances of my
| add-ins for each request. The add-ins are quite lightweight, just
| parsing some parameters and loading the correct UserControl.
|
| The add-in inherits CompositeControl so I can simply do a:
| Control userControl =
| this.Page.LoadControl(RequestedControlPath);
| this.Controls.Add(userControl);
| in my add-in to load the userControl. I then do a
| Controls.Add(addInObj); on a placeholder object in my page.
| Everything is dandy and postback works like a charm.
|
| But I'm not that convinced that it is the best way to do it. Will my app
| suffer a lot perfomance wise by this architecture?
|
| Btw, which is the best way to restart a webapplication to make it reload
| my addins. I would like to initiate the restart myself so that I can
| minimize the downtime, ie. putting all the files in the correct place
| and just click "Restart" and the webapp is up and running within a second.
|
| Steven Cheng[MSFT] wrote:
| > Hi Mats,
| >
| > The Mutiple subdomain Add-in architecture is ususally used in many
destop
| > application, seems not quite common for asp.net scenario. Anyway, based
on
| > my understanding, we'll meet the following problem here:
| >
| > 1. For ASP.NET's page processing, it is request/response based. So each
| > time a request is processed in a server worker thread( page class and
other
| > control instances are contructed during this server pipeline....) ,
after
| > that , all the pages and control instances are destroyed and page
content
| > being flush to clientside.... (later a new post back to server cause a
new
| > worker thread and page structure to be constructed.....). So I think
we
| > should not implement those add-ins as control, if so, we'll need to
create
| > them in each request, and also I don't think ASP.NET page model will
| > support cross appdomain control communication.... So we need to
| > implement add-in as separate compent classes which will be loaded into
| > ASP.NET worker process (in separate appdomain ) at startup time .
| >
| > 2. Then, since we create those Add-in appdomains in asp.net woker
process
| > (at startup time), what we need to do later is communicating with those
| > addins in the appdomain, this is another hard problem. What I can get
| > currently is creating those add-in instance's proxies at start up
| > time(right after they've been created in cross domain) and store these
| > proxy references in a gobal collection (ApplicationState or Application
| > Cache...). Thus, all the later requests can access them in events
code....
| >
| > Anyway, though this is possible, I really feel a bit nervous on it
since
| > creating multiple sub appdomain in ASP.NET process may make it a bit
| > unstable and cross domain communication will hurt the ASP.NET runtime
| > performance .....
| >
| > Thanks,
| >
| > Steven Cheng
| > Microsoft Online Support
| >
| > Get Secure! www.microsoft.com/security
| > (This posting is provided "AS IS", with no warranties, and confers no
| > rights.)
| >
| >
| > --------------------
| > | Date: Wed, 23 Nov 2005 19:07:04 +0100
| > | From: Mats Lycken <[email protected]>
| > | User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| > | X-Accept-Language: en-us, en
| > | MIME-Version: 1.0
| > | Subject: Re: Creating a plug-in based WebApp
| > | References: <[email protected]>
| > <[email protected]>
| > | In-Reply-To: <[email protected]>
| > | Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| > | Content-Transfer-Encoding: 7bit
| > | Message-ID: <[email protected]>
| > | Newsgroups: microsoft.public.dotnet.framework.aspnet
| > | NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| > | Lines: 1
| > | Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!tk2msftngp13.phx.gbl
| > | Xref: TK2MSFTNGXA02.phx.gbl
| > microsoft.public.dotnet.framework.aspnet:360511
| > | X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
| > |
| > | Thanks for the fast reply!
| > |
| > | I've already done this but it doesn't work for me... the thing is
that I
| > | want to add my control to a placeholders control collection, then I
need
| > | a direct reference to the plugin so that I can add it.
| > |
| > | My plugin uses .ascx files to display the data and I can't create an
| > | instance of it without having access to the WebForms context (as I
| > | understand it), so I need to add the plugin the usual way,
| > | Controls.Add(plugin);
| > |
| > | (e-mail address removed) wrote:
| > | > You can pass the object by reference instead, but as you are already
| > | > inheriting from CompositeControl you can't do this directly,
| > | >
| > | > You will need to use the delegate pattern here,
| > | >
| > | > Create an interface that covers all the methods on your plugin, make
| > | > the plugin implement it
| > | >
| > | > Create another class that inherits from MarshalByRefObject, make
this
| > | > object also implement your interface.
| > | >
| > | > The class (that implements marshalbyrefobject) should have a
property
| > | > of your plugin type,
| > | >
| > | > then for the methods that you need to implement (interface methods)
| > | > simply route these to the plugin (via the property)
| > | >
| > | > a bit long winded but as we can't do multiple inheritence this is
one
| > | > way of getting around this,
| > | >
| > |
| > |
| >
|
 
M

Mats Lycken

Hi, and thanks again for your response, it's really appreciated to get
help from you.

If I load a plugin assembly which holds the plugin type I have to load
it into a separate AppDomain to be able to unload it, right?
The thing is that since I want to inherit CompositeControl so that I can
simply add it to a PlaceHolders control collection I can't have it in
another AppDomain since it won't serialize.
Is there some other way to solve it?

On restarting the webapp I guess I could have a file in my bin-directory
that I simply "touch" when I want to restart the app.
Then I can control it from the app itself, although it might be a bad
idea to let the app have write access to the bin-dir, writing to the
..config file sounds like a no-no too..
If I add <probing privatePath="AnotherBin"/> to my .config file and
touch a file there, will the application restart itself then too?

I was planning on adding caching to solve the overhead involved with
loading the plugins. Either a "whole-page" cache or just cache the
output of the plugin based on the parameters that are sent to control
its output.

Thanks again for your reply, it feels great to be able to discuss this
with a professional.

Best regards,
Mats

Thanks for your response Mats,

Regarding on your further quesitons:

But I'm not that convinced that it is the best way to do it. Will my app
suffer a lot perfomance wise by this architecture?
================================================
Of course, dynamically adding webcontrols will add overhead to the asp.net
runtime at serverside processing. Also, since you add many additional layer
to abstract the "Add-in" /WebControls relationship.... that'll make the
application's performance more pressed. I suggest you turn on the Trace to
see how much time a typical page which use your current control/add-in
model will consume at serverside processing (normal loading and postback
processing).... Also, I think such application architecture suits
intranet application where network bandwith won't be the problem and the
concurrent requests number won't be two high...


Btw, which is the best way to restart a webapplication to make it reload
my addins. I would like to initiate the restart myself so that I can
minimize the downtime, ie. putting all the files in the correct place
and just click "Restart" and the webapp is up and running within a second.
================================================

I'm afraid there is no explicit or standard interfaces for us to manually
restart an asp.net application(appdomain). Restaring is controled by
runtime itself whenever there occur some certain incidents or meet some
certain points. e.g. when we change the components in private "bin" dir or
modify some critical setting in web.config.....

Why not just create and hold those add-in class instances in some
application cache , and when you need to update them , just remove them and
create new instances and update the caches ?

Thanks,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)



--------------------
| Date: Fri, 25 Nov 2005 11:33:36 +0100
| From: Mats Lycken <[email protected]>
| User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| X-Accept-Language: en-us, en
| MIME-Version: 1.0
| Subject: Re: Creating a plug-in based WebApp
| References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
| In-Reply-To: <[email protected]>
| Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| Content-Transfer-Encoding: 7bit
| Message-ID: <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| Lines: 1
| Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP12.phx.gbl
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:360872
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Hi Steven,
| I rewrote my code some and abandoned the idea of having a separate
| AppDomain for the add-ins. What I did instead was to create an object
| factory that sits in my primary appdomain and creates instances of my
| add-ins for each request. The add-ins are quite lightweight, just
| parsing some parameters and loading the correct UserControl.
|
| The add-in inherits CompositeControl so I can simply do a:
| Control userControl =
| this.Page.LoadControl(RequestedControlPath);
| this.Controls.Add(userControl);
| in my add-in to load the userControl. I then do a
| Controls.Add(addInObj); on a placeholder object in my page.
| Everything is dandy and postback works like a charm.
|
| But I'm not that convinced that it is the best way to do it. Will my app
| suffer a lot perfomance wise by this architecture?
|
| Btw, which is the best way to restart a webapplication to make it reload
| my addins. I would like to initiate the restart myself so that I can
| minimize the downtime, ie. putting all the files in the correct place
| and just click "Restart" and the webapp is up and running within a second.
|
| Steven Cheng[MSFT] wrote:
| > Hi Mats,
| >
| > The Mutiple subdomain Add-in architecture is ususally used in many
destop
| > application, seems not quite common for asp.net scenario. Anyway, based
on
| > my understanding, we'll meet the following problem here:
| >
| > 1. For ASP.NET's page processing, it is request/response based. So each
| > time a request is processed in a server worker thread( page class and
other
| > control instances are contructed during this server pipeline....) ,
after
| > that , all the pages and control instances are destroyed and page
content
| > being flush to clientside.... (later a new post back to server cause a
new
| > worker thread and page structure to be constructed.....). So I think
we
| > should not implement those add-ins as control, if so, we'll need to
create
| > them in each request, and also I don't think ASP.NET page model will
| > support cross appdomain control communication.... So we need to
| > implement add-in as separate compent classes which will be loaded into
| > ASP.NET worker process (in separate appdomain ) at startup time .
| >
| > 2. Then, since we create those Add-in appdomains in asp.net woker
process
| > (at startup time), what we need to do later is communicating with those
| > addins in the appdomain, this is another hard problem. What I can get
| > currently is creating those add-in instance's proxies at start up
| > time(right after they've been created in cross domain) and store these
| > proxy references in a gobal collection (ApplicationState or Application
| > Cache...). Thus, all the later requests can access them in events
code....
| >
| > Anyway, though this is possible, I really feel a bit nervous on it
since
| > creating multiple sub appdomain in ASP.NET process may make it a bit
| > unstable and cross domain communication will hurt the ASP.NET runtime
| > performance .....
| >
| > Thanks,
| >
| > Steven Cheng
| > Microsoft Online Support
| >
| > Get Secure! www.microsoft.com/security
| > (This posting is provided "AS IS", with no warranties, and confers no
| > rights.)
| >
| >
| > --------------------
| > | Date: Wed, 23 Nov 2005 19:07:04 +0100
| > | From: Mats Lycken <[email protected]>
| > | User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| > | X-Accept-Language: en-us, en
| > | MIME-Version: 1.0
| > | Subject: Re: Creating a plug-in based WebApp
| > | References: <[email protected]>
| > <[email protected]>
| > | In-Reply-To: <[email protected]>
| > | Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| > | Content-Transfer-Encoding: 7bit
| > | Message-ID: <[email protected]>
| > | Newsgroups: microsoft.public.dotnet.framework.aspnet
| > | NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| > | Lines: 1
| > | Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!tk2msftngp13.phx.gbl
| > | Xref: TK2MSFTNGXA02.phx.gbl
| > microsoft.public.dotnet.framework.aspnet:360511
| > | X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
| > |
| > | Thanks for the fast reply!
| > |
| > | I've already done this but it doesn't work for me... the thing is
that I
| > | want to add my control to a placeholders control collection, then I
need
| > | a direct reference to the plugin so that I can add it.
| > |
| > | My plugin uses .ascx files to display the data and I can't create an
| > | instance of it without having access to the WebForms context (as I
| > | understand it), so I need to add the plugin the usual way,
| > | Controls.Add(plugin);
| > |
| > | (e-mail address removed) wrote:
| > | > You can pass the object by reference instead, but as you are already
| > | > inheriting from CompositeControl you can't do this directly,
| > | >
| > | > You will need to use the delegate pattern here,
| > | >
| > | > Create an interface that covers all the methods on your plugin, make
| > | > the plugin implement it
| > | >
| > | > Create another class that inherits from MarshalByRefObject, make
this
| > | > object also implement your interface.
| > | >
| > | > The class (that implements marshalbyrefobject) should have a
property
| > | > of your plugin type,
| > | >
| > | > then for the methods that you need to implement (interface methods)
| > | > simply route these to the plugin (via the property)
| > | >
| > | > a bit long winded but as we can't do multiple inheritence this is
one
| > | > way of getting around this,
| > | >
| > |
| > |
| >
|
 
S

Steven Cheng[MSFT]

Thanks for your followup Mats,

So far I also haven't any good idea which can both avoid mutiple appdomain
and also make add-in components load/unload flexibly. How frequently will
those add-in components be changed in your asp.net application? If not very
frequently, you can consider restarting the application when there needs to
change add-in components... But as for manually restarting application
through those tricks I mentioend before( change web.config or private bin
dir's content...), there may exists some delay thing the runtime won't end
the old applicaiton and restart new one right after we make any changes
that will cause restart, it may need some further time to do resource
disposing or finalizing.....

In addition, as for
=============
If I add <probing privatePath="AnotherBin"/> to my .config file and
touch a file there, will the application restart itself then too?
=============

this is not possible, because the ASP.NET's runtime is a particular
customized CLR host, it is forced to use the "bin" as the only private
probing path (no matter what we set in the web.config....) .

Thanks,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)





--------------------
| Date: Mon, 28 Nov 2005 22:40:03 +0100
| From: Mats Lycken <[email protected]>
| User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| X-Accept-Language: en-us, en
| MIME-Version: 1.0
| Subject: Re: Creating a plug-in based WebApp
| References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<q$vTtW#[email protected]>
| In-Reply-To: <q$vTtW#[email protected]>
| Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| Content-Transfer-Encoding: 7bit
| Message-ID: <#[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| Lines: 1
| Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!tk2msftngp13.phx.gbl
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:361348
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Hi, and thanks again for your response, it's really appreciated to get
| help from you.
|
| If I load a plugin assembly which holds the plugin type I have to load
| it into a separate AppDomain to be able to unload it, right?
| The thing is that since I want to inherit CompositeControl so that I can
| simply add it to a PlaceHolders control collection I can't have it in
| another AppDomain since it won't serialize.
| Is there some other way to solve it?
|
| On restarting the webapp I guess I could have a file in my bin-directory
| that I simply "touch" when I want to restart the app.
| Then I can control it from the app itself, although it might be a bad
| idea to let the app have write access to the bin-dir, writing to the
| .config file sounds like a no-no too..
| If I add <probing privatePath="AnotherBin"/> to my .config file and
| touch a file there, will the application restart itself then too?
|
| I was planning on adding caching to solve the overhead involved with
| loading the plugins. Either a "whole-page" cache or just cache the
| output of the plugin based on the parameters that are sent to control
| its output.
|
| Thanks again for your reply, it feels great to be able to discuss this
| with a professional.
|
| Best regards,
| Mats
|
|
| Steven Cheng[MSFT] wrote:
| > Thanks for your response Mats,
| >
| > Regarding on your further quesitons:
| >
| > But I'm not that convinced that it is the best way to do it. Will my
app
| > suffer a lot perfomance wise by this architecture?
| > ================================================
| > Of course, dynamically adding webcontrols will add overhead to the
asp.net
| > runtime at serverside processing. Also, since you add many additional
layer
| > to abstract the "Add-in" /WebControls relationship.... that'll make the
| > application's performance more pressed. I suggest you turn on the Trace
to
| > see how much time a typical page which use your current control/add-in
| > model will consume at serverside processing (normal loading and
postback
| > processing).... Also, I think such application architecture suits
| > intranet application where network bandwith won't be the problem and
the
| > concurrent requests number won't be two high...
| >
| >
| > Btw, which is the best way to restart a webapplication to make it
reload
| > my addins. I would like to initiate the restart myself so that I can
| > minimize the downtime, ie. putting all the files in the correct place
| > and just click "Restart" and the webapp is up and running within a
second.
| > ================================================
| >
| > I'm afraid there is no explicit or standard interfaces for us to
manually
| > restart an asp.net application(appdomain). Restaring is controled by
| > runtime itself whenever there occur some certain incidents or meet some
| > certain points. e.g. when we change the components in private "bin" dir
or
| > modify some critical setting in web.config.....
| >
| > Why not just create and hold those add-in class instances in some
| > application cache , and when you need to update them , just remove them
and
| > create new instances and update the caches ?
| >
| > Thanks,
| >
| > Steven Cheng
| > Microsoft Online Support
| >
| > Get Secure! www.microsoft.com/security
| > (This posting is provided "AS IS", with no warranties, and confers no
| > rights.)
| >
| >
| >
| > --------------------
| > | Date: Fri, 25 Nov 2005 11:33:36 +0100
| > | From: Mats Lycken <[email protected]>
| > | User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| > | X-Accept-Language: en-us, en
| > | MIME-Version: 1.0
| > | Subject: Re: Creating a plug-in based WebApp
| > | References: <[email protected]>
| > <[email protected]>
| > <[email protected]>
| > <[email protected]>
| > | In-Reply-To: <[email protected]>
| > | Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| > | Content-Transfer-Encoding: 7bit
| > | Message-ID: <[email protected]>
| > | Newsgroups: microsoft.public.dotnet.framework.aspnet
| > | NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| > | Lines: 1
| > | Path: TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP12.phx.gbl
| > | Xref: TK2MSFTNGXA02.phx.gbl
| > microsoft.public.dotnet.framework.aspnet:360872
| > | X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
| > |
| > | Hi Steven,
| > | I rewrote my code some and abandoned the idea of having a separate
| > | AppDomain for the add-ins. What I did instead was to create an object
| > | factory that sits in my primary appdomain and creates instances of my
| > | add-ins for each request. The add-ins are quite lightweight, just
| > | parsing some parameters and loading the correct UserControl.
| > |
| > | The add-in inherits CompositeControl so I can simply do a:
| > | Control userControl =
| > | this.Page.LoadControl(RequestedControlPath);
| > | this.Controls.Add(userControl);
| > | in my add-in to load the userControl. I then do a
| > | Controls.Add(addInObj); on a placeholder object in my page.
| > | Everything is dandy and postback works like a charm.
| > |
| > | But I'm not that convinced that it is the best way to do it. Will my
app
| > | suffer a lot perfomance wise by this architecture?
| > |
| > | Btw, which is the best way to restart a webapplication to make it
reload
| > | my addins. I would like to initiate the restart myself so that I can
| > | minimize the downtime, ie. putting all the files in the correct place
| > | and just click "Restart" and the webapp is up and running within a
second.
| > |
| > | Steven Cheng[MSFT] wrote:
| > | > Hi Mats,
| > | >
| > | > The Mutiple subdomain Add-in architecture is ususally used in many
| > destop
| > | > application, seems not quite common for asp.net scenario. Anyway,
based
| > on
| > | > my understanding, we'll meet the following problem here:
| > | >
| > | > 1. For ASP.NET's page processing, it is request/response based. So
each
| > | > time a request is processed in a server worker thread( page class
and
| > other
| > | > control instances are contructed during this server pipeline....) ,
| > after
| > | > that , all the pages and control instances are destroyed and page
| > content
| > | > being flush to clientside.... (later a new post back to server
cause a
| > new
| > | > worker thread and page structure to be constructed.....). So I
think
| > we
| > | > should not implement those add-ins as control, if so, we'll need to
| > create
| > | > them in each request, and also I don't think ASP.NET page model
will
| > | > support cross appdomain control communication.... So we need to
| > | > implement add-in as separate compent classes which will be loaded
into
| > | > ASP.NET worker process (in separate appdomain ) at startup time .
| > | >
| > | > 2. Then, since we create those Add-in appdomains in asp.net woker
| > process
| > | > (at startup time), what we need to do later is communicating with
those
| > | > addins in the appdomain, this is another hard problem. What I can
get
| > | > currently is creating those add-in instance's proxies at start up
| > | > time(right after they've been created in cross domain) and store
these
| > | > proxy references in a gobal collection (ApplicationState or
Application
| > | > Cache...). Thus, all the later requests can access them in events
| > code....
| > | >
| > | > Anyway, though this is possible, I really feel a bit nervous on it
| > since
| > | > creating multiple sub appdomain in ASP.NET process may make it a
bit
| > | > unstable and cross domain communication will hurt the ASP.NET
runtime
| > | > performance .....
| > | >
| > | > Thanks,
| > | >
| > | > Steven Cheng
| > | > Microsoft Online Support
| > | >
| > | > Get Secure! www.microsoft.com/security
| > | > (This posting is provided "AS IS", with no warranties, and confers
no
| > | > rights.)
| > | >
| > | >
| > | > --------------------
| > | > | Date: Wed, 23 Nov 2005 19:07:04 +0100
| > | > | From: Mats Lycken <[email protected]>
| > | > | User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
| > | > | X-Accept-Language: en-us, en
| > | > | MIME-Version: 1.0
| > | > | Subject: Re: Creating a plug-in based WebApp
| > | > | References: <[email protected]>
| > | > <[email protected]>
| > | > | In-Reply-To:
<[email protected]>
| > | > | Content-Type: text/plain; charset=ISO-8859-1; format=flowed
| > | > | Content-Transfer-Encoding: 7bit
| > | > | Message-ID: <[email protected]>
| > | > | Newsgroups: microsoft.public.dotnet.framework.aspnet
| > | > | NNTP-Posting-Host: 1-1-3-42a.vs.vs.bostream.se 82.182.18.143
| > | > | Lines: 1
| > | > | Path:
TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!tk2msftngp13.phx.gbl
| > | > | Xref: TK2MSFTNGXA02.phx.gbl
| > | > microsoft.public.dotnet.framework.aspnet:360511
| > | > | X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
| > | > |
| > | > | Thanks for the fast reply!
| > | > |
| > | > | I've already done this but it doesn't work for me... the thing is
| > that I
| > | > | want to add my control to a placeholders control collection, then
I
| > need
| > | > | a direct reference to the plugin so that I can add it.
| > | > |
| > | > | My plugin uses .ascx files to display the data and I can't create
an
| > | > | instance of it without having access to the WebForms context (as
I
| > | > | understand it), so I need to add the plugin the usual way,
| > | > | Controls.Add(plugin);
| > | > |
| > | > | (e-mail address removed) wrote:
| > | > | > You can pass the object by reference instead, but as you are
already
| > | > | > inheriting from CompositeControl you can't do this directly,
| > | > | >
| > | > | > You will need to use the delegate pattern here,
| > | > | >
| > | > | > Create an interface that covers all the methods on your plugin,
make
| > | > | > the plugin implement it
| > | > | >
| > | > | > Create another class that inherits from MarshalByRefObject,
make
| > this
| > | > | > object also implement your interface.
| > | > | >
| > | > | > The class (that implements marshalbyrefobject) should have a
| > property
| > | > | > of your plugin type,
| > | > | >
| > | > | > then for the methods that you need to implement (interface
methods)
| > | > | > simply route these to the plugin (via the property)
| > | > | >
| > | > | > a bit long winded but as we can't do multiple inheritence this
is
| > one
| > | > | > way of getting around this,
| > | > | >
| > | > |
| > | > |
| > | >
| > |
| >
|
 
J

Joseph Ferris

Steven,

I've been following this thread, as I have been working on a similar
application to what Mats is describing. I have a CMS with a dynamic
plugin architecture that hasn't gotten much beyond the proof of concept
stage.

But, what I have a question about is:
In addition, as for
=============
If I add <probing privatePath="AnotherBin"/> to my .config file and
touch a file there, will the application restart itself then too?
=============

this is not possible, because the ASP.NET's runtime is a particular
customized CLR host, it is forced to use the "bin" as the only private
probing path (no matter what we set in the web.config....) .

I have been able to get this to work, though. The catch is that you
can not just add the values to the privatePath attribute, but you also
must add an <%@ Assembly %> and <%@ Import %> directive on the ASPX
page.

There is a brief article about this at:
http://www.hanselman.com/blog/PermaLink.aspx?guid=4d0ef4fb-f8ae-4355-a658-3c0432c98dbe

This did not work for me, as that defeated the purpose of dynamically
included ASCXs. Touching the ASPX pages to include all possible
controls (which are analyzed and have creation information stored in
the database) would become make for a page that is too large and prone
to error. This technique is more for a team of developers working on a
single solution that is broken into multiple projects that might change
at varying frequencies.

What I ended up doing was (I am working off the top of my head, since I
don't have access to my home development machine from the office), I
created a base control class that inherited from UserControl, where I
extended it with some creation and data loading code. I also created
an Interface that all controls which inherit from my base must also
implement, so that I ensure that the system can talk to them.

To create them, I have implemented an Abstract Factory pattern and
created an object which creates any control that implements my
interface and also is a type of my object, based upon the information
stored in the database and the type of content the page should be
displaying. So far, it is working well - although I will be the first
to admit that I have a long way to go until it does something useful
(like return data to the screen!). ;-)

Like you, Mats, I have been struggling with a way to organize my bin,
as well as allow the worker process to be able to see my changes.
Right now, my test app is able to load a control from a subdirectory of
bin by using LoadControl. To be honest with you, I have no clue how I
was able to get it to work. I had struggled with it for a better part
of the weekend. ;-)

The way that my solution is set up is that I have a "Library" project
that contains my framework. I also have a main solution that is the
web site itself. It is really small and lightweight, since most of the
functionality is in the Library. My plugin that I have been playing
with is stored in two places. The ASCX is in a subdirectory of the web
site, in this particular case, it is in ./Template/Default. (My
plugins can either be widgets, or templates, or a couple of other types
of specific objects.) The DLL from the Plugin's project is in the bin
folder of the web site at the moment.

While it works, I was hoping to get a more granular structure, as well.
I am not sure for your reasoning, but I am guessing that it is similar
to mine. I am looking for plugin segragation. Since I might not be
the one developing a plugin, I don't have control over things such as
naming, etc. If I could "sandbox" them, I could have a little more
piece of mind. Of primary concern is the use of third party controls
in relation to a third party control from the app. Isn't that a
confusing way to put it? ;-) What I meant to say is if PluginA uses
CompanyZ's WonderWidget, as does PluginB, I now have to implement some
sort of reference counting to be able to determine when I can remove
the WonderWidget unless I can come up with a sound and secure way of
organizing the plugin "installs".

Anyhow, I have rambled on enough for you, I am sure. When I get to
looking at my code again, I'll see if there is anything that I didn't
mention. Unfortunately, taking the commute to work into account, I
don't have much time for my project until the weekends.

Thanks for reading!

Joseph
 
S

Steven Cheng[MSFT]

Thanks for your informative inputs Joseph,

Really appreciate the article you provided about setting additional probing
path, I did haven't noticed that before...

Mats,

Do you have further idea based on Joseph's experience sharing...

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
--------------------
| From: "Joseph Ferris" <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| Subject: Re: Creating a plug-in based WebApp
| Date: 29 Nov 2005 07:38:43 -0800
| Organization: http://groups.google.com
| Lines: 89
| Message-ID: <[email protected]>
| References: <[email protected]>
| <[email protected]>
| <[email protected]>
| <[email protected]>
| <[email protected]>
| <q$vTtW#[email protected]>
| <#[email protected]>
| <[email protected]>
| NNTP-Posting-Host: 63.144.130.226
| Mime-Version: 1.0
| Content-Type: text/plain; charset="iso-8859-1"
| X-Trace: posting.google.com 1133278728 11694 127.0.0.1 (29 Nov 2005
15:38:48 GMT)
| X-Complaints-To: (e-mail address removed)
| NNTP-Posting-Date: Tue, 29 Nov 2005 15:38:48 +0000 (UTC)
| In-Reply-To: <[email protected]>
| User-Agent: G2/0.2
| X-HTTP-UserAgent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;
..NET CLR 1.1.4322; .NET CLR 1.0.3705),gzip(gfe),gzip(gfe)
| Complaints-To: (e-mail address removed)
| Injection-Info: g43g2000cwa.googlegroups.com; posting-host=63.144.130.226;
| posting-account=Vd0Hbg0AAAC6U1lJ_giny8wVIgM0jjCa
| Path:
TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!newsfeed00.sul.t-online.de!t-onli
ne.de!border2.nntp.dca.giganews.com!border1.nntp.dca.giganews.com!nntp.gigan
ews.com!postnews.google.com!g43g2000cwa.googlegroups.com!not-for-mail
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:361488
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Steven,
|
| I've been following this thread, as I have been working on a similar
| application to what Mats is describing. I have a CMS with a dynamic
| plugin architecture that hasn't gotten much beyond the proof of concept
| stage.
|
| But, what I have a question about is:
|
| > In addition, as for
| > =============
| > If I add <probing privatePath="AnotherBin"/> to my .config file and
| > touch a file there, will the application restart itself then too?
| > =============
| >
| > this is not possible, because the ASP.NET's runtime is a particular
| > customized CLR host, it is forced to use the "bin" as the only private
| > probing path (no matter what we set in the web.config....) .
|
| I have been able to get this to work, though. The catch is that you
| can not just add the values to the privatePath attribute, but you also
| must add an <%@ Assembly %> and <%@ Import %> directive on the ASPX
| page.
|
| There is a brief article about this at:
|
http://www.hanselman.com/blog/PermaLink.aspx?guid=4d0ef4fb-f8ae-4355-a658-3c
0432c98dbe
|
| This did not work for me, as that defeated the purpose of dynamically
| included ASCXs. Touching the ASPX pages to include all possible
| controls (which are analyzed and have creation information stored in
| the database) would become make for a page that is too large and prone
| to error. This technique is more for a team of developers working on a
| single solution that is broken into multiple projects that might change
| at varying frequencies.
|
| What I ended up doing was (I am working off the top of my head, since I
| don't have access to my home development machine from the office), I
| created a base control class that inherited from UserControl, where I
| extended it with some creation and data loading code. I also created
| an Interface that all controls which inherit from my base must also
| implement, so that I ensure that the system can talk to them.
|
| To create them, I have implemented an Abstract Factory pattern and
| created an object which creates any control that implements my
| interface and also is a type of my object, based upon the information
| stored in the database and the type of content the page should be
| displaying. So far, it is working well - although I will be the first
| to admit that I have a long way to go until it does something useful
| (like return data to the screen!). ;-)
|
| Like you, Mats, I have been struggling with a way to organize my bin,
| as well as allow the worker process to be able to see my changes.
| Right now, my test app is able to load a control from a subdirectory of
| bin by using LoadControl. To be honest with you, I have no clue how I
| was able to get it to work. I had struggled with it for a better part
| of the weekend. ;-)
|
| The way that my solution is set up is that I have a "Library" project
| that contains my framework. I also have a main solution that is the
| web site itself. It is really small and lightweight, since most of the
| functionality is in the Library. My plugin that I have been playing
| with is stored in two places. The ASCX is in a subdirectory of the web
| site, in this particular case, it is in ./Template/Default. (My
| plugins can either be widgets, or templates, or a couple of other types
| of specific objects.) The DLL from the Plugin's project is in the bin
| folder of the web site at the moment.
|
| While it works, I was hoping to get a more granular structure, as well.
| I am not sure for your reasoning, but I am guessing that it is similar
| to mine. I am looking for plugin segragation. Since I might not be
| the one developing a plugin, I don't have control over things such as
| naming, etc. If I could "sandbox" them, I could have a little more
| piece of mind. Of primary concern is the use of third party controls
| in relation to a third party control from the app. Isn't that a
| confusing way to put it? ;-) What I meant to say is if PluginA uses
| CompanyZ's WonderWidget, as does PluginB, I now have to implement some
| sort of reference counting to be able to determine when I can remove
| the WonderWidget unless I can come up with a sound and secure way of
| organizing the plugin "installs".
|
| Anyhow, I have rambled on enough for you, I am sure. When I get to
| looking at my code again, I'll see if there is anything that I didn't
| mention. Unfortunately, taking the commute to work into account, I
| don't have much time for my project until the weekends.
|
| Thanks for reading!
|
| Joseph
|
|
 
M

Mats Lycken

Hi,
I'll try to explain the solution I did that works for me.
I guess it's something similar to what Joseph did.

I use the factory pattern to create instances of my addins for each
request. Each instance inherits CompositeControl so that I easily can
add the addin to the control structure of the page.

I use masterpages to load my addins and I wrote a special Loader
webcontrol that takes the name of the addin to load as a parameter (it
also takes parameters to pass to the addin).

On each masterpage I have at least one Loader whos addin name is set to
_content. That loader looks at the querystring to determine which addin
to load.

The addins in their turn look at the parameters they got and adds the
correct .ascx file (depending on the parameters) to its control collection.

This way I can have as many instances of each addin on each page as I
want, and they can all display different data but still have full use of
view state and post back etc.

It's a pretty neat solution that works great for me. :)

Addin reloading won't be a problem since we will only update the addins
once every couple of months or so, probably even more seldom.
To restart the web application I'll probably resort to using an external
program that installs the correct addins and then touches a file in the
bin dir.

Best regards,
Mats Lycken
 
J

Joseph Ferris

Mats,

Our approaches do, indeed, sound similar. I think that the primary
difference comes in the way that we are looking at installing controls.
I am assuming the worst (shared hosting environment with limited
access) and hoping for a web based installation solution. Good luck on
your project! I hope that you are having as much fun with it as I am.

Joseph
 
S

Steven Cheng[MSFT]

Cool~ Mats,

That sounds much better.. Anyway, IMO such design is only suitable for
intranet application deployed in internal envionement rather than internet
shared hosting environment...
Also, you're welcome share more things here when you've got a complete
prototype on this...

Thanks & Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
--------------------
| From: "Joseph Ferris" <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| Subject: Re: Creating a plug-in based WebApp
| Date: 30 Nov 2005 09:54:26 -0800
| Organization: http://groups.google.com
| Lines: 10
| Message-ID: <[email protected]>
| References: <[email protected]>
| <[email protected]>
| <[email protected]>
| <[email protected]>
| NNTP-Posting-Host: 63.144.130.226
| Mime-Version: 1.0
| Content-Type: text/plain; charset="iso-8859-1"
| X-Trace: posting.google.com 1133373271 971 127.0.0.1 (30 Nov 2005
17:54:31 GMT)
| X-Complaints-To: (e-mail address removed)
| NNTP-Posting-Date: Wed, 30 Nov 2005 17:54:31 +0000 (UTC)
| In-Reply-To: <[email protected]>
| User-Agent: G2/0.2
| X-HTTP-UserAgent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;
..NET CLR 1.1.4322; .NET CLR 1.0.3705),gzip(gfe),gzip(gfe)
| Complaints-To: (e-mail address removed)
| Injection-Info: o13g2000cwo.googlegroups.com; posting-host=63.144.130.226;
| posting-account=Vd0Hbg0AAAC6U1lJ_giny8wVIgM0jjCa
| Path:
TK2MSFTNGXA02.phx.gbl!TK2MSFTNGP08.phx.gbl!newsfeed00.sul.t-online.de!t-onli
ne.de!border2.nntp.dca.giganews.com!border1.nntp.dca.giganews.com!nntp.gigan
ews.com!postnews.google.com!o13g2000cwo.googlegroups.com!not-for-mail
| Xref: TK2MSFTNGXA02.phx.gbl
microsoft.public.dotnet.framework.aspnet:361828
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Mats,
|
| Our approaches do, indeed, sound similar. I think that the primary
| difference comes in the way that we are looking at installing controls.
| I am assuming the worst (shared hosting environment with limited
| access) and hoping for a web based installation solution. Good luck on
| your project! I hope that you are having as much fun with it as I am.
|
| Joseph
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top