Adding @Assembly references programmatically

P

Praveen Ramesh

Hi,

Is there any way to add the @Assembly reference to the aspx files
programmatically from inside a custom control (when it gets dropped on to
the page from the toolbox)?

I have a custom control - MyControl that implements an interface in another
custom assembly - InterfaceAssembly. When MyControl gets dropped on to the
page and run, it results in a "InterfaceAssembly not found" exception. I am
aware that this can be fixed by manually adding a @Assembly directive
refering to the InterfaceAssembly in the GAC (or add a reference to it in
the web.config/machine.config, etc) - but that is not good enough. The
MyControl is a control that will be distributed to a whole lot of people and
we do not want them to do this manual step every time they drag and drop
this control to a page - not very elegant.

I see that Steven Cheng from MS has responded to some related issues in the
newsgroups. Hope to hear from him or someone else from MS.

Thanks in advance,
Praveen
 
P

Praveen

Brock,

Thanks for the reply. But, like I mentioned I do not want to add the
reference manually, I want my custom control to INSERT this AUTOMATICALLY
into the aspx file in which it was added, if possible.

Thanks
-Praveen
 
S

Steven Cheng[MSFT]

Thanks for Brock's inputs.

Hi Praveen,

From the description of your problem, it is a VS.NET's design-time issue
which I've met in some former issues. And is the following issue the one
you found on the web search ?

#Adding namespaces to code behind automatically (C#)
http://groups.google.com.sg/groups?hl=en&lr=&selm=qzudX38aEHA.2752@cpmsftn
gxa06.phx.gbl&rnum=2

I think that's exactly the same problem as yours. When we developing a
custom control and use VS.NET's ToolBox to drag it onto our page or
winform. The VS.NET ide will automatcally add assembly reference of the
control's Main Assembly(dll). However, if the control still have other
assembly dependecy, VS.NET won't add them into references automatically.
Then, if we didn't manually add them (in our project) or in our control's
design-time code, there will occur assembly not found exception at runtime.
That's just what you 've encountered, yes?

Also, have you tried the sample code in the above thread?

====================
protected override IComponent[] CreateComponentsCore(IDesignerHost host)
{

ITypeResolutionService service1;
Assembly assembly1,assembly2;

IComponent component1;
IComponent[] componentArray1;

IContainer container1 = host.Container;
service1 = ((ITypeResolutionService)
host.GetService(typeof(ITypeResolutionService)));

assembly1 = typeof(ClassLib.UserName).Module.Assembly;
assembly2 = typeof(ComponentLib.SimpleComponent).Module.Assembly;
service1.ReferenceAssembly(assembly1.GetName());
service1.ReferenceAssembly(assembly2.GetName());

component1 = new ComponentLib.SimpleComponent();
container1.Add(component1);
componentArray1 = new IComponent[]{component1};

return componentArray1;

}
==================

We can override the CreateComponents method of the ToolboxItem and manually
add the necessary assembly dependecy in it. The following two statements
are just the adding reference code:

service1.ReferenceAssembly(assembly1.GetName());
service1.ReferenceAssembly(assembly2.GetName());

Please have a look to see whether it helps. 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.)
 
S

Steven Cheng[MSFT]

Hi Praveen,

After some further checking , I'm thinking the problem is likely
environment specific or project specific. Based on my local test, (a
control with another dependency), I didn't get the assembly not load error.
I've tested using strong-named or not strong-named control assembly. As I
also mentioned in another thread, if possible, you can generate a
simplified version of your problem control and let me do some tests on my
local side.

Looking forward to your response. 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.)
 
P

Praveen

Steven,

Glad to hear from you!

Yes, the thread you posted in the other message is what I had referred to.
The other message I posted is also, as you might have figured, related to
resolving this issue.

Before I generate a sample for you, could you please test the following. My
custom control implements an interface defined in this other assembly -
which is what is causing the runtime dll not found error. Does your test
case do something similar (implementing an interface)? If not, please try
that quickly.

Now, if you can reproduce the above issue, then does providing a custom
ToolBoxItem resolve the issue (by forcing a @assembly reference into the
aspx page)?

I will send a sample if you cannot reproduce the above.

Thanks
Praveen
 
B

Brock Allen

Oh, I see what you're saying. VS.NET adds the incorrect version in the directive?
Well, that's unfortunate. I rarely use the designer in VS.NET. Given these
sorts of quirks from VS.NET, it's good to know how to do these things manually.


-Brock
DevelopMentor
http://staff.develop.com/ballen
 
S

Steven Cheng[MSFT]

Thanks for your response Praveen,

From your further description, there seems still something difference from
your test and mine. AS you mentioned, you put the interfaceLib into GAC and
the control's assembly not in GAC yes? Also, at compile time , there is no
error and the control's assembly is correctly copied into the application's
private bin folder, yes? And is the interfacelib also copied into private
bin folder?

And at runtime, you got the error in your message, yes?

I'll assume the above steps and perform some tests on my side. If there is
anything incorrect, please feel free to let me know. 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.)
 
P

Praveen

Steven,

Yes, to all your questions. Except, no, the InterfaceLib is not copied to
the bin folder - copy local false - as discussed. I wonder what our
differences might be!

I also, tested this on 2 other systems - 1 with just 1.0 and one with just
1.1. Same problem there!

Hope you can reproduce.

Regards,
Praveen
 
S

Steven Cheng[MSFT]

Hi Praveen,

After some further testing, I think I've found the problem you encountered.
Yes, when making the interfaceLib strong-named and put in GAC, at runtime
(have draged the control onto page and compiled the project), we'll get
assembly not found. Also, if we put the interfacelib assembly in the
application's private bin directory(copy local), that issue not occur. (And
copy local is bydefault when we not strong-named the interfacelib that's
why I didn't repro it in former test). The cause of this seems like below:

the aspx is dynamic compiled at runtime, and when he found that there is a
DsControlLib dll referenced in page, it 'll try to find its dependent
assemly (interfacelib). However, it will treat the interfacelib as a
private assembly(not strong-named) , so it didn't lookup the GAC and
direclty search the private bin folder, if not found , the exception
thrown. That's why if we manually add the "@Assembly" reference which
specify the Full Assembly name of the interfacelib will make it work.

However, I'm not sure why the dynamic compiled page class will referencing
the strong-named assembly as private one, I'll consult some further experts
on this to see whether they have any further ideas. Anyway, I think this
problem is different from the one in my orginal post(use toolboxiitem to
manually add reference).

I'll update you if I got any new info. 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.)
 
P

Praveen

Steven,

Glad you could reproduce this now!

Actually, my reasoning is a bit different. When the runtime compiler
compiles the dynamically generated code, it encounters the "new
MathsControl();" line and figures that it needs access to the dscontrollib
where it's defined AND the interfacelib where the "ICalculate" is defined.
The dscontrollib is referenced through the @register tag but there is no
reference to the interfacelib assembly (it doesn't look up the
dscontrollib's manifest to determine where to find the interfacelib) - so it
chokes.

Like I mentioned before, this can be worked around by inserting assembly
referencing entries in the web.config or other config files, or by asking
the user to insert @assembly directives manually in the aspx files, but I
would like to avoid it. If I could insert "@assembly" directives
automatically from my control code, that would be awesome!

-Praveen
 
S

Steven Cheng[MSFT]

Hi Praveen,

Well, I think you're right. For those dynamically compiled components
(aspx, ascx ....), the referenced assembly are specified by the @Register
@Assembly directives in template or the predefined references in
web.config(or machine.config)'s <assembies> configuration element. And by
default the machine.conifig's <assemblies> settting contains the

<assemblies>
....
<add assembly="*" />
</assemblies>

So all the assemblies in the private bin path will be automatically
refereced. That's why if using copylocal, that'll work.

Currently I think we have the following options when developing our custom
control which may meet such problem:
1. Programmatically add the <@assembly > directive into aspx page. Though
we can get the path of the editing
aspx page in VS.NET at design-time , but I didn't suggest this approach
since VS.NET didn't provide buidlin DOM structure or interface to let us
programly editing it.

2. Since we can specify the assembly reference in
web.config/machine.config's <compilation><assemblies>.. like below:

<compilation
defaultLanguage="c#"
debug="true"<assemblies>
<add
assembly="InterfaceLib,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=2bfe02
78943847bf"/>
</assemblies>
</compilation>

We can consider adding the reference of our assembly into web.config at
design-time. Since web.config is a xml file we can using the buildin DOM
api to manipulate it. That'll be much more convenient.

How do you think of this?

Steven Cheng
Microsoft Online Support

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

Praveen

Steven,

Option 1 is the preferrable option, but if that cannot be implemented, I
will make do with option 2. Come to think of it, isn't the aspx file an xml
file as well? Shouldn't we be able to parse it then just as the web.config
file?

Do you have any code samples that will help me get started on this?

Thanks
Praveen
 
P

Praveen

I actually got this working through some hacks, after going through the
designer source using Reflector. Here are the steps:

In the custom control's custom designer's Initialize override, do something
like this:
public override void Initialize(IComponent component)
{

base.Initialize (component);

IDesignerHost host = component.Site.Container as IDesignerHost;
IDesigner designer = host.GetDesigner(host.RootComponent);

// Calling GetHTMLFromWebControlTool with the following custom toolboxitem
will insert the
// Register directives for the type associated with that .
MethodInfo mi = designer.GetType.GetMethod("GetHTMLFromWebControlTool",
BindingFlags.NonPublic | BindingFlags.Instance);
if(mi != null)
{
// DependantType is a custom type defined in DependantAssembly.dll
mi.Invoke(designer, new object[]{new
WebControlToolboxItem(typeof(SomeNamespace.DependantType))});
}
}

Then when the user drags and drops the item from the toolbox, besides the
default @ register entry it makes, it will also make an entry like this:
<%@ Register TagPrefix="cc1" Namespace="SomeNamespace"
Assembly="DependantAssembly, Version=2.0.0.1, Culture=neutral,
PublicKeyToken=3d6dfsd1fdsd44c89" %>

The assembly will not be strong named in the above tag if it's not in the
GAC.

Thanks a lot for your help.

-Praveen
 
S

Steven Cheng[MSFT]

Great Work Praveen!

I must admit that your professional and passion really impressed me. In
fact, I've never noticed the

IDesigner designer = host.GetDesigner(host.RootComponent);

MethodInfo mi = designer.GetType.GetMethod("GetHTMLFromWebControlTool",

before though I also use reflecter to lookup some designer's code
sometimes. I was going to provide some former thread on reference the
web.cofig file and modify it at design-time in control before reading your
last message. But now I think they're unnecessary since you've found such a
good solution.

Anyway, I shall thank you for the persistent work and sharing your great
effort with us. I'm sure that'll be much valuable to many other community
members who're struggling with such problem.

Also, if there are any problems in the future, please always feel free to
discuss here.

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.)
 

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