By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,640 Members | 1,598 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,640 IT Pros & Developers. It's quick & easy.

Instantiate/Load UserControl from DLL

P: n/a
Hi there,

I searched carefully through the web before finally deciding to post
this message, because I could not find a solution for my problem.
Hopefully someone will have a hint or explanation for me! I apologize
for the length of this posting, but I wanted to make sure that I get an
answer other than "Hey man, just use LoadControl!", because this is not
what I want.

The Task: Isolate a collection of web forms which are created as
UserControls from the web application framework so that they can be
easily changed, exchanged, removed, and added, without having to
restart or recompile the web application.
My Approach: Store UserControls in separate project and dynamically
load assembly. Example code in C#:

[... Code Snippet Begin ...]
ObjectHandle PackageManagerHandle;
IPackageManager packageManager;

// Load Assembly
PackageManagerHandle = Activator.CreateInstanceFrom("Packages.dll",
"Packages.PackageManager");

// Unwrap type
packageManager = (IPackageManager) PackageManagerHandle.Unwrap();
UserControl control = packageManager.GetControl(ctrlName);
control.InitializeAsUserControl(this.Page);
[... Code Snippet End ...]

This is pretty much the same code that can be found in MSDN when
looking at Assembly.LoadFrom or Activator.CreateInstance. The
interesting part are the last two lines, where the actual UserControl
instance is created. The very last line came from the very informative
article at http://aspalliance.com/399 about LoadControl and
LoadTemplate, but actually does not change much for me.

The Result: When I execute the above code, it works fine and I get an
instance of my UserControl, but all the controls inside of the
UserControl are not initialized, therefore it shows up on the page as
an empty control. This seems to make sense, though, because the
instantiation only creates an instance of the UserControl class, but it
does not execute/interpret the actual ascx file that has the HTML code
in it.

Why not use Page.LoadControl? Here is why: First of all, LoadControl
expects a virtual path to the ascx file of the UserControl. This means
the ascx file has to be inside of the web root of that web application,
and I cannot compile it into my single DLL, which would be much nicer
to deploy and maintain.

While trying different things out, I found two solutions, which I
briefly want to present here:

Solution 1: Go back to using Page.LoadControl, but still call it from
my PackageManager class which is in another project (or solution, for
that matter) than my web application.
Advantage: It works!
Disadvantage: I need to have my user control files somewhere in the web
root of the application, otherwise LoadControl cannot find them. Also,
the type the UserControl inherits from needs to be known to the
assembly, otherwise I get an ugly Cannot Load Type error. As I said, it
works, but I was hoping for a more elegant solution.

Solution 2: While trying to overcome the fact that simply instantiating
the UserControl does not evaluate the ascx file I thought about using
ParseControl, which I usually don't like very much since it does not
compile or interpret any code. However, in this case this is exactly
what I want, because I already have my UserControl instance and all I
need are the controls inside of my UserControl instantiated with the
parameters specified in the HTML tags in the ascx file.
Here is how it works: First I create the UserControl instance, then I
use ParseControl to parse the ascx file into a control. Next I add this
parsed control to my user control. Here comes the tricky part:
Unfortunately I don't know what exactly is going on behind the scenes
if you instantiate a UserControl just by dropping it on to a page in
Visual Studio, but the key part is that ASP.NET connects the controls
in the ascx file with the protected member variables in the code
behind. This connection is somehow lost in the way I do it, so that
trying to access a server control from the code behind causes a Object
Not Set To An Instance exception.
I found a solution for this as well: By using Reflection I iterated
over the Fields collection of the UserControl and then used FindControl
to find the respective server controls in the Controls collection. This
way I could reconnect the code behind with the "code in front".
This is a short code snippet which illustrates this solution:

[... Code Snippet Begin ...]
StreamReader sr = new StreamReader(fileName);
Control parseControl = Container.Page.ParseControl(sr.ReadToEnd());
sr.Close();

userControl.Controls.Add(parseControl);
Type type = userControl.GetType();
System.Reflection.FieldInfo[] fields =
type.GetFields(System.Reflection.BindingFlags.Inst ance |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.DeclaredOnly);
foreach ( System.Reflection.FieldInfo field in fields )
{
Control ctrl = FindControlQ(userControl, field.Name);
field.SetValue(userControl, ctrl);
}
[... Code Snippet End ...]

The first three lines read the ascx file through a stream reader. This
has the HUGE advantage of being able to put the UserControl files
anywhere, not necessarily inside of the web root of the web
application.
Note that I am using FindControlQ which is a recursive version of
FindControl, so that controls nested in other NamingContainers are
found as well.
Despite the fact that I have actually two working solutions now, I am
left with two questions:
1. Is there an easier way to do this? The first code snippet at the
beginning of this posting seems to do *almost* what I want, so maybe I
am just missing a simple call which would save me all the ParseControl
and Reflection work? All I am doing is more or less mimicing the
behavior of LoadControl, so if there was a different way to execute
LoadControl on a file outside of the web root, that would work fine for
me.
2. Are there any reasons why going down that ParseControl/Reflection
path might cause serious problems later? I tested my solution with a
couple of UserControls, and it seems that ViewState, Validators etc.
are still working correctly, and my events in the code behind are
firing as I expect it.
Thanks for reading through all this, I'd be happy about feedback, and
if someone out there happens to find a solution for his or her problem
in this posting, feel free to ask any questions, I can also post more
code if necessary!

Thanks,
Sascha

Nov 19 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a

Would you mind giving out the code for FindControlQ?

Sascha wrote:
*Hi there,

I searched carefully through the web before finally deciding to post
this message, because I could not find a solution for my problem.
Hopefully someone will have a hint or explanation for me! I
apologize
for the length of this posting, but I wanted to make sure that I get
an
answer other than "Hey man, just use LoadControl!", because this is
not
what I want.

The Task: Isolate a collection of web forms which are created as
UserControls from the web application framework so that they can be
easily changed, exchanged, removed, and added, without having to
restart or recompile the web application.
My Approach: Store UserControls in separate project and dynamically
load assembly. Example code in C#:

[... Code Snippet Begin ...]
ObjectHandle PackageManagerHandle;
IPackageManager packageManager;

// Load Assembly
PackageManagerHandle = Activator.CreateInstanceFrom("Packages.dll",
"Packages.PackageManager");

// Unwrap type
packageManager = (IPackageManager) PackageManagerHandle.Unwrap();
UserControl control = packageManager.GetControl(ctrlName);
control.InitializeAsUserControl(this.Page);
[... Code Snippet End ...]

This is pretty much the same code that can be found in MSDN when
looking at Assembly.LoadFrom or Activator.CreateInstance. The
interesting part are the last two lines, where the actual
UserControl
instance is created. The very last line came from the very
informative
article at http://aspalliance.com/399 about LoadControl
and
LoadTemplate, but actually does not change much for me.

The Result: When I execute the above code, it works fine and I get
an
instance of my UserControl, but all the controls inside of the
UserControl are not initialized, therefore it shows up on the page
as
an empty control. This seems to make sense, though, because the
instantiation only creates an instance of the UserControl class, but
it
does not execute/interpret the actual ascx file that has the HTML
code
in it.

Why not use Page.LoadControl? Here is why: First of all, LoadControl
expects a virtual path to the ascx file of the UserControl. This
means
the ascx file has to be inside of the web root of that web
application,
and I cannot compile it into my single DLL, which would be much
nicer
to deploy and maintain.

While trying different things out, I found two solutions, which I
briefly want to present here:

Solution 1: Go back to using Page.LoadControl, but still call it
from
my PackageManager class which is in another project (or solution,
for
that matter) than my web application.
Advantage: It works!
Disadvantage: I need to have my user control files somewhere in the
web
root of the application, otherwise LoadControl cannot find them.
Also,
the type the UserControl inherits from needs to be known to the
assembly, otherwise I get an ugly Cannot Load Type error. As I said,
it
works, but I was hoping for a more elegant solution.

Solution 2: While trying to overcome the fact that simply
instantiating
the UserControl does not evaluate the ascx file I thought about
using
ParseControl, which I usually don't like very much since it does not
compile or interpret any code. However, in this case this is exactly
what I want, because I already have my UserControl instance and all
I
need are the controls inside of my UserControl instantiated with the
parameters specified in the HTML tags in the ascx file.
Here is how it works: First I create the UserControl instance, then
I
use ParseControl to parse the ascx file into a control. Next I add
this
parsed control to my user control. Here comes the tricky part:
Unfortunately I don't know what exactly is going on behind the
scenes
if you instantiate a UserControl just by dropping it on to a page in
Visual Studio, but the key part is that ASP.NET connects the
controls
in the ascx file with the protected member variables in the code
behind. This connection is somehow lost in the way I do it, so that
trying to access a server control from the code behind causes a
Object
Not Set To An Instance exception.
I found a solution for this as well: By using Reflection I iterated
over the Fields collection of the UserControl and then used
FindControl
to find the respective server controls in the Controls collection.
This
way I could reconnect the code behind with the "code in front".
This is a short code snippet which illustrates this solution:

[... Code Snippet Begin ...]
StreamReader sr = new StreamReader(fileName);
Control parseControl = Container.Page.ParseControl(sr.ReadToEnd());
sr.Close();

userControl.Controls.Add(parseControl);
Type type = userControl.GetType();
System.Reflection.FieldInfo[] fields =
type.GetFields(System.Reflection.BindingFlags.Inst ance |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.DeclaredOnly);
foreach ( System.Reflection.FieldInfo field in fields )
{
Control ctrl = FindControlQ(userControl, field.Name);
field.SetValue(userControl, ctrl);
}
[... Code Snippet End ...]

The first three lines read the ascx file through a stream reader.
This
has the HUGE advantage of being able to put the UserControl files
anywhere, not necessarily inside of the web root of the web
application.
Note that I am using FindControlQ which is a recursive version of
FindControl, so that controls nested in other NamingContainers are
found as well.
Despite the fact that I have actually two working solutions now, I
am
left with two questions:
1. Is there an easier way to do this? The first code snippet at the
beginning of this posting seems to do *almost* what I want, so maybe
I
am just missing a simple call which would save me all the
ParseControl
and Reflection work? All I am doing is more or less mimicing the
behavior of LoadControl, so if there was a different way to execute
LoadControl on a file outside of the web root, that would work fine
for
me.
2. Are there any reasons why going down that ParseControl/Reflection
path might cause serious problems later? I tested my solution with a
couple of UserControls, and it seems that ViewState, Validators etc.
are still working correctly, and my events in the code behind are
firing as I expect it.
Thanks for reading through all this, I'd be happy about feedback,
and
if someone out there happens to find a solution for his or her
problem
in this posting, feel free to ask any questions, I can also post
more
code if necessary!

Thanks,
Sascha *
Would you mind giving out the code for FindControlQ?


--
msteller
------------------------------------------------------------------------
Posted via http://www.codecomments.com
------------------------------------------------------------------------

Apr 15 '06 #2

P: n/a

Did you manage to find out a solution?
I got exactly the same problem

Best Regards
Franz Thomsen

Sascha wrote:
*Hi there,

I searched carefully through the web before finally deciding to post
this message, because I could not find a solution for my problem.
Hopefully someone will have a hint or explanation for me! I
apologize
for the length of this posting, but I wanted to make sure that I get
an
answer other than "Hey man, just use LoadControl!", because this is
not
what I want.

The Task: Isolate a collection of web forms which are created as
UserControls from the web application framework so that they can be
easily changed, exchanged, removed, and added, without having to
restart or recompile the web application.
My Approach: Store UserControls in separate project and dynamically
load assembly. Example code in C#:

[... Code Snippet Begin ...]
ObjectHandle PackageManagerHandle;
IPackageManager packageManager;

// Load Assembly
PackageManagerHandle = Activator.CreateInstanceFrom("Packages.dll",
"Packages.PackageManager");

// Unwrap type
packageManager = (IPackageManager) PackageManagerHandle.Unwrap();
UserControl control = packageManager.GetControl(ctrlName);
control.InitializeAsUserControl(this.Page);
[... Code Snippet End ...]

This is pretty much the same code that can be found in MSDN when
looking at Assembly.LoadFrom or Activator.CreateInstance. The
interesting part are the last two lines, where the actual
UserControl
instance is created. The very last line came from the very
informative
article at http://aspalliance.com/399 about LoadControl
and
LoadTemplate, but actually does not change much for me.

The Result: When I execute the above code, it works fine and I get
an
instance of my UserControl, but all the controls inside of the
UserControl are not initialized, therefore it shows up on the page
as
an empty control. This seems to make sense, though, because the
instantiation only creates an instance of the UserControl class, but
it
does not execute/interpret the actual ascx file that has the HTML
code
in it.

Why not use Page.LoadControl? Here is why: First of all, LoadControl
expects a virtual path to the ascx file of the UserControl. This
means
the ascx file has to be inside of the web root of that web
application,
and I cannot compile it into my single DLL, which would be much
nicer
to deploy and maintain.

While trying different things out, I found two solutions, which I
briefly want to present here:

Solution 1: Go back to using Page.LoadControl, but still call it
from
my PackageManager class which is in another project (or solution,
for
that matter) than my web application.
Advantage: It works!
Disadvantage: I need to have my user control files somewhere in the
web
root of the application, otherwise LoadControl cannot find them.
Also,
the type the UserControl inherits from needs to be known to the
assembly, otherwise I get an ugly Cannot Load Type error. As I said,
it
works, but I was hoping for a more elegant solution.

Solution 2: While trying to overcome the fact that simply
instantiating
the UserControl does not evaluate the ascx file I thought about
using
ParseControl, which I usually don't like very much since it does not
compile or interpret any code. However, in this case this is exactly
what I want, because I already have my UserControl instance and all
I
need are the controls inside of my UserControl instantiated with the
parameters specified in the HTML tags in the ascx file.
Here is how it works: First I create the UserControl instance, then
I
use ParseControl to parse the ascx file into a control. Next I add
this
parsed control to my user control. Here comes the tricky part:
Unfortunately I don't know what exactly is going on behind the
scenes
if you instantiate a UserControl just by dropping it on to a page in
Visual Studio, but the key part is that ASP.NET connects the
controls
in the ascx file with the protected member variables in the code
behind. This connection is somehow lost in the way I do it, so that
trying to access a server control from the code behind causes a
Object
Not Set To An Instance exception.
I found a solution for this as well: By using Reflection I iterated
over the Fields collection of the UserControl and then used
FindControl
to find the respective server controls in the Controls collection.
This
way I could reconnect the code behind with the "code in front".
This is a short code snippet which illustrates this solution:

[... Code Snippet Begin ...]
StreamReader sr = new StreamReader(fileName);
Control parseControl = Container.Page.ParseControl(sr.ReadToEnd());
sr.Close();

userControl.Controls.Add(parseControl);
Type type = userControl.GetType();
System.Reflection.FieldInfo[] fields =
type.GetFields(System.Reflection.BindingFlags.Inst ance |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.DeclaredOnly);
foreach ( System.Reflection.FieldInfo field in fields )
{
Control ctrl = FindControlQ(userControl, field.Name);
field.SetValue(userControl, ctrl);
}
[... Code Snippet End ...]

The first three lines read the ascx file through a stream reader.
This
has the HUGE advantage of being able to put the UserControl files
anywhere, not necessarily inside of the web root of the web
application.
Note that I am using FindControlQ which is a recursive version of
FindControl, so that controls nested in other NamingContainers are
found as well.
Despite the fact that I have actually two working solutions now, I
am
left with two questions:
1. Is there an easier way to do this? The first code snippet at the
beginning of this posting seems to do *almost* what I want, so maybe
I
am just missing a simple call which would save me all the
ParseControl
and Reflection work? All I am doing is more or less mimicing the
behavior of LoadControl, so if there was a different way to execute
LoadControl on a file outside of the web root, that would work fine
for
me.
2. Are there any reasons why going down that ParseControl/Reflection
path might cause serious problems later? I tested my solution with a
couple of UserControls, and it seems that ViewState, Validators etc.
are still working correctly, and my events in the code behind are
firing as I expect it.
Thanks for reading through all this, I'd be happy about feedback,
and
if someone out there happens to find a solution for his or her
problem
in this posting, feel free to ask any questions, I can also post
more
code if necessary!

Thanks,
Sascha *


--
Franz Thomsen
------------------------------------------------------------------------
Posted via http://www.codecomments.com
------------------------------------------------------------------------

May 11 '06 #3

This discussion thread is closed

Replies have been disabled for this discussion.