473,395 Members | 1,677 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

More powerful version of Type.GetType(string)?

Sky
I have been looking for a more powerful version of GetType(string) that will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one solution
fits all', but instead there are several parts that have to be put together
to check.

What I have so far is, and would like as much feedback as possible to ensure
I've done the best job possible is:

Step 1: Find a Type in the calling Assembly, or fallback to mscorlib:
GetType() looks for a class by that name in the calling Assembly, and then
falls back to search in mscorlib.
As you can imagine, this doesn't get us far.

Step 2: Looking in other Assemblies already loaded:
If not in either of these two, you have to fall back to using
AppDomain.GetAssemblies(), and then loop through each individually to test
each one with assembly.GetType(string).

Step 3: Looking in Assemblies not already loaded:
But these only refer to assemblies already loaded -- and will fail if the
assembly has not loaded yet, so you then have to Assembly.Load(pathName) for
each assembly in the bin dir that ends with ".dll" and ".exe".

Step 4: Looking in the GAC:
The above solutions almost get us through everything, except there stilll is
missing one place to look, the GAC. How can I get a list of assemblies in the
GAC, to search through them as well?
Questions:
a) The Assembly.LoadFile() worries me a lot: how does it work, exactly? I
assume it does exactly as implied, and loads it up in memory -- so calling it
at the beginning of a program could mean that *all* assemblies are loaded in
memory right from the start, making for a slower startup... Calling and
loading all files in the GAC to search through them would end up with a lot
of memory for assemblies that have nothing to do with the application, right?

b) This all seems to be a very complex route, that even with caching for
later, could be a massive drain on system resources -- is there any simpler
way?

c) GetAssemblies() is not available on CE...Is there *any* other way to get
a list of assemblies loaded in memory other than AppDomain.GetAssemblies?

Thank you for any and all feedback, and pointers,
Sky

BTW: For anybody that is interested, the code for the above looks a bit like:

private static Type LoadType(string typeName) {
System.Reflection.Assembly assembly;
return LoadType(typeName, out assembly);
}

private static Type LoadType(string typeName, out
System.Reflection.Assembly assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

#if (!PocketPC) && (!pocketPC) && (!WindowsCE)
foreach (System.Reflection.Assembly tmpAasembly in
System.AppDomain.CurrentDomain.GetAssemblies()) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
}
#endif

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetCallingAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
assembly = System.Reflection.Assembly.LoadFrom(fileName);

type = assembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}

Jul 25 '06 #1
7 7787
Sky,

There is no way around it, you are going to have to provide the assembly
name, and not just the type name. A type's identity is not simply the name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
>I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:

Step 1: Find a Type in the calling Assembly, or fallback to mscorlib:
GetType() looks for a class by that name in the calling Assembly, and then
falls back to search in mscorlib.
As you can imagine, this doesn't get us far.

Step 2: Looking in other Assemblies already loaded:
If not in either of these two, you have to fall back to using
AppDomain.GetAssemblies(), and then loop through each individually to test
each one with assembly.GetType(string).

Step 3: Looking in Assemblies not already loaded:
But these only refer to assemblies already loaded -- and will fail if the
assembly has not loaded yet, so you then have to Assembly.Load(pathName)
for
each assembly in the bin dir that ends with ".dll" and ".exe".

Step 4: Looking in the GAC:
The above solutions almost get us through everything, except there stilll
is
missing one place to look, the GAC. How can I get a list of assemblies in
the
GAC, to search through them as well?
Questions:
a) The Assembly.LoadFile() worries me a lot: how does it work, exactly? I
assume it does exactly as implied, and loads it up in memory -- so calling
it
at the beginning of a program could mean that *all* assemblies are loaded
in
memory right from the start, making for a slower startup... Calling and
loading all files in the GAC to search through them would end up with a
lot
of memory for assemblies that have nothing to do with the application,
right?

b) This all seems to be a very complex route, that even with caching for
later, could be a massive drain on system resources -- is there any
simpler
way?

c) GetAssemblies() is not available on CE...Is there *any* other way to
get
a list of assemblies loaded in memory other than AppDomain.GetAssemblies?

Thank you for any and all feedback, and pointers,
Sky

BTW: For anybody that is interested, the code for the above looks a bit
like:

private static Type LoadType(string typeName) {
System.Reflection.Assembly assembly;
return LoadType(typeName, out assembly);
}

private static Type LoadType(string typeName, out
System.Reflection.Assembly assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

#if (!PocketPC) && (!pocketPC) && (!WindowsCE)
foreach (System.Reflection.Assembly tmpAasembly in
System.AppDomain.CurrentDomain.GetAssemblies()) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
}
#endif

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetCallingAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
assembly = System.Reflection.Assembly.LoadFrom(fileName);

type = assembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}

Jul 25 '06 #2
Sky
Hi Nicholas:

Very good question, actually.

Actually it probably comes from my having had really frustrating experiences
with app.configs/ConnectionSettings/Providers in general when I first started
out. Seemed I could never get up and running without a lot of poking around
due to very vague error messages, combined with one little spelling mistake
in an app.Config.

The whole thing set me off right from the start distrusting pointing to
assemblies with version and culture numbers: it seems to be way too specific,
and causes me nothing but frustration.

It also just seems to me that the current assemby full names are *way* too
specific, whereas they should be in *most* cases 'loose', only resorting to
specific culture/version to handle specific clashes.

In addition, I'm not sure that I even agree that a config file is the best
location for some of this identity inforation: I suspect that Culture should
be handled via code choices of satellite resource assemblies,

But probably what worries me the most is the issue of version numbers --
hard to update a growing app (ie more assemblies) over the web without having
to update the config file as well. And that is made very complicated when the
app has
a) user settings in it,
b) is a modular type of software where other vendors may need to also have
settings in the app.config for their assemblies.

Talking about that last piece a little bit more: it seems that the
app.config model is more suited for installation packages, and/or ClickOnce
packages. But if I am correct, code is going to be more and more like
services...ie thin+ clients that start off with some modules, and as needed
(or paid for...) or released, more modules are downloaded and installed, that
are updatable much more fluidly (webservice+serializationofdlls+throw out and
restart appdomain)...where the webconfig stuff will need to be updated for
every new module downloaded, and every version shift in the downloaded
modules.... Seems like this is very hard to do with current thinking... I'm
REALLY looking for pointers/thoughts/articles on this type of thinking...

Then again, this point of view of mne all might be caused from to a
completly wrong understanding of how the whole thing fits together, whereas a
fresh look/undestanding of how to use it all would sort it all out! :-) For
example, I'm one of the people who just doesn't get User Settings in an
app.config. Oh, sure I get the simplicity of typed access to properties...but
saving user settings in an app.config seems to be exactly the same as keeping
stuff intended for c:\Documents and Settings\Users\YourSettings under
c:\Programs Files\Your app.... Sounds like a very messed up way of doing
things, no?

Hence, my struggling around to find a good solution: currently this leads me
to believe that references to assemblies being 'loose', with short names, and
not always the assembly it belongs in.

Which when I think about it...doesn't answer your question... Hum.

As for why I can't put the assembly name... That was your question. Is the
answer simply because I'm lazy? I know the type, but I don't always know what
assembly it is in? Especially because I sometimes move things around from one
assembly to another as I progress through coding and get clearer as to where
it should go(eg: I start with a simple 1 assembly exe, and later make it into
an multiple assembly application (UIL, BLL, DAL) and have to move code that
was originally placed in UIL to BLL...
Which is not a good reason to not put in the assembly name as well. It just
seems to indicate that I am lazy. Hum. I'll have to think about that.

Sky
BTW: Solution to my question in the last post, about not using up all
resources:
....the solution is to use a secondary AppDomain to load the Assemblies into,
that can then be dumped. I was stunned to find that one can get a Type out of
an Assembly in a secondary domain, and then dump the secondary domain, and
use the Type in the first domain, without it bugging out due to the Type
pointing to a null address...I would have thought (limited experience with
AppDomains...) that it would somehow cause a type of memory exception
pointing into mem that is no longer available...even after a GC.Collect().
So there. It works. On desktop/full.... But not on CE because CE's AppDomain
is stunted and doesn't have a Load(string) feature to do the same trick.
Anybody have an idea?

PPS: I am still looking for answers to find out what is in the GAC? And the
equivalent to LoadAssembly(string) and GetAssemblies(string) on Compact
NET...anyone?
public static Type LoadType(string typeName, out System.Reflection.Assembly
assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
//Create a second domain:
System.AppDomain currentAppDomain = System.AppDomain.CurrentDomain;
System.Security.Policy.Evidence evidence =
System.AppDomain.CurrentDomain.Evidence;
System.AppDomain secondDomain =
System.AppDomain.CreateDomain("typeLoader", evidence);
System.AppDomain tmpDomain = secondDomain;//currentAppDomain;
int tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;
//zero?

//Get assemblies in tmp domain:
//suprisingly, this turned out to have same results
//as currentDomain -- I would have thought it would report back
//less assemblies. Nice.
System.Reflection.Assembly[] assemblies = tmpDomain.GetAssemblies();
int foundCount = assemblies.Length;

foreach (System.Reflection.Assembly tmpAasembly in assemblies) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
//Load assembly into tmp domain rather than
//directly into current domain:
//assembly = System.Reflection.Assembly.LoadFrom(fileName);
string assemblyShortName =
System.IO.Path.GetFileNameWithoutExtension(fileNam e);
assembly = tmpDomain.Load(assemblyShortName);

type = assembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}






"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

There is no way around it, you are going to have to provide the assembly
name, and not just the type name. A type's identity is not simply the name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:

Step 1: Find a Type in the calling Assembly, or fallback to mscorlib:
GetType() looks for a class by that name in the calling Assembly, and then
falls back to search in mscorlib.
As you can imagine, this doesn't get us far.

Step 2: Looking in other Assemblies already loaded:
If not in either of these two, you have to fall back to using
AppDomain.GetAssemblies(), and then loop through each individually to test
each one with assembly.GetType(string).

Step 3: Looking in Assemblies not already loaded:
But these only refer to assemblies already loaded -- and will fail if the
assembly has not loaded yet, so you then have to Assembly.Load(pathName)
for
each assembly in the bin dir that ends with ".dll" and ".exe".

Step 4: Looking in the GAC:
The above solutions almost get us through everything, except there stilll
is
missing one place to look, the GAC. How can I get a list of assemblies in
the
GAC, to search through them as well?
Questions:
a) The Assembly.LoadFile() worries me a lot: how does it work, exactly? I
assume it does exactly as implied, and loads it up in memory -- so calling
it
at the beginning of a program could mean that *all* assemblies are loaded
in
memory right from the start, making for a slower startup... Calling and
loading all files in the GAC to search through them would end up with a
lot
of memory for assemblies that have nothing to do with the application,
right?

b) This all seems to be a very complex route, that even with caching for
later, could be a massive drain on system resources -- is there any
simpler
way?

c) GetAssemblies() is not available on CE...Is there *any* other way to
get
a list of assemblies loaded in memory other than AppDomain.GetAssemblies?

Thank you for any and all feedback, and pointers,
Sky

BTW: For anybody that is interested, the code for the above looks a bit
like:

private static Type LoadType(string typeName) {
System.Reflection.Assembly assembly;
return LoadType(typeName, out assembly);
}

private static Type LoadType(string typeName, out
System.Reflection.Assembly assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

#if (!PocketPC) && (!pocketPC) && (!WindowsCE)
foreach (System.Reflection.Assembly tmpAasembly in
System.AppDomain.CurrentDomain.GetAssemblies()) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
}
#endif

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetCallingAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
assembly = System.Reflection.Assembly.LoadFrom(fileName);

type = assembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}


Jul 25 '06 #3
Sky,

See inline.
Actually it probably comes from my having had really frustrating
experiences
with app.configs/ConnectionSettings/Providers in general when I first
started
out. Seemed I could never get up and running without a lot of poking
around
due to very vague error messages, combined with one little spelling
mistake
in an app.Config.
Well, yes, but in the end, that's understandable. Computers can't
understand intent.
The whole thing set me off right from the start distrusting pointing to
assemblies with version and culture numbers: it seems to be way too
specific,
and causes me nothing but frustration.

It also just seems to me that the current assemby full names are *way* too
specific, whereas they should be in *most* cases 'loose', only resorting
to
specific culture/version to handle specific clashes.

In addition, I'm not sure that I even agree that a config file is the best
location for some of this identity inforation: I suspect that Culture
should
be handled via code choices of satellite resource assemblies,
How satellite resource assemblies are referenced is clearly laid out in
the framework documentation. This shouldn't be such a big issue. The
static CurrentCulture property on the Thread class is used to make a
decision from which assembly to load resources from.
But probably what worries me the most is the issue of version numbers --
hard to update a growing app (ie more assemblies) over the web without
having
to update the config file as well. And that is made very complicated when
the
app has
a) user settings in it,
b) is a modular type of software where other vendors may need to also have
settings in the app.config for their assemblies.
That's part of your problem there. You shouldn't be storing ^user^
configuration information in a file that is meant for ^application^
configuration. You should be handling user preferences in a separate file.

As for updating the config file, if your user settings aren't in there,
it shouldn't be such a big deal. Have you looked at ClickOnce for your
deployment scenario? It should help with this situation greatly.
Talking about that last piece a little bit more: it seems that the
app.config model is more suited for installation packages, and/or
ClickOnce
packages. But if I am correct, code is going to be more and more like
services...ie thin+ clients that start off with some modules, and as
needed
(or paid for...) or released, more modules are downloaded and installed,
that
are updatable much more fluidly (webservice+serializationofdlls+throw out
and
restart appdomain)...where the webconfig stuff will need to be updated for
every new module downloaded, and every version shift in the downloaded
modules.... Seems like this is very hard to do with current thinking...
I'm
REALLY looking for pointers/thoughts/articles on this type of thinking...
I don't think that your perspective on app.config is correct. It simply
is a way of specifying configuration details for your application, details
which could change over the course of the installation. It's a way of
providing a uniform interface to those configuration details.

ClickOnce has a separate manifest altogether.

The web.config file is for your service side only. If you roll out new
features on that end, then yes, you will have to update it (assuming there
is information in there that you need to access).
>
Then again, this point of view of mne all might be caused from to a
completly wrong understanding of how the whole thing fits together,
whereas a
fresh look/undestanding of how to use it all would sort it all out! :-)
For
example, I'm one of the people who just doesn't get User Settings in an
app.config. Oh, sure I get the simplicity of typed access to
properties...but
saving user settings in an app.config seems to be exactly the same as
keeping
stuff intended for c:\Documents and Settings\Users\YourSettings under
c:\Programs Files\Your app.... Sounds like a very messed up way of doing
things, no?
I agree with you completely on this. The app.config file is not a place
that user settings should be set. Also, the idea of an app changing the
app.config file while it is running is not something I agree with either.
Hence, my struggling around to find a good solution: currently this leads
me
to believe that references to assemblies being 'loose', with short names,
and
not always the assembly it belongs in.

Which when I think about it...doesn't answer your question... Hum.

As for why I can't put the assembly name... That was your question. Is the
answer simply because I'm lazy? I know the type, but I don't always know
what
assembly it is in? Especially because I sometimes move things around from
one
assembly to another as I progress through coding and get clearer as to
where
it should go(eg: I start with a simple 1 assembly exe, and later make it
into
an multiple assembly application (UIL, BLL, DAL) and have to move code
that
was originally placed in UIL to BLL...
Which is not a good reason to not put in the assembly name as well. It
just
seems to indicate that I am lazy. Hum. I'll have to think about that.
Without it seeming like I am being chastising, you do need to rethink
that approach. A type is not only defined by its code, but by it's
location, which means the assembly name. You say you know the type, but if
you don't always know what assembly it is in, then you CAN'T know the type.

Also, here is a hint. If you use the static Load method on the Assembly
class, you don't have to always specify the complete name. You can specify
the assembly name without the public key, the culture, and the version, and
it will get the best match.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

>
Sky
BTW: Solution to my question in the last post, about not using up all
resources:
...the solution is to use a secondary AppDomain to load the Assemblies
into,
that can then be dumped. I was stunned to find that one can get a Type out
of
an Assembly in a secondary domain, and then dump the secondary domain, and
use the Type in the first domain, without it bugging out due to the Type
pointing to a null address...I would have thought (limited experience with
AppDomains...) that it would somehow cause a type of memory exception
pointing into mem that is no longer available...even after a GC.Collect().
So there. It works. On desktop/full.... But not on CE because CE's
AppDomain
is stunted and doesn't have a Load(string) feature to do the same trick.
Anybody have an idea?

PPS: I am still looking for answers to find out what is in the GAC? And
the
equivalent to LoadAssembly(string) and GetAssemblies(string) on Compact
NET...anyone?
public static Type LoadType(string typeName, out
System.Reflection.Assembly
assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
//Create a second domain:
System.AppDomain currentAppDomain = System.AppDomain.CurrentDomain;
System.Security.Policy.Evidence evidence =
System.AppDomain.CurrentDomain.Evidence;
System.AppDomain secondDomain =
System.AppDomain.CreateDomain("typeLoader", evidence);
System.AppDomain tmpDomain = secondDomain;//currentAppDomain;
int tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;
//zero?

//Get assemblies in tmp domain:
//suprisingly, this turned out to have same results
//as currentDomain -- I would have thought it would report back
//less assemblies. Nice.
System.Reflection.Assembly[] assemblies = tmpDomain.GetAssemblies();
int foundCount = assemblies.Length;

foreach (System.Reflection.Assembly tmpAasembly in assemblies) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
//Load assembly into tmp domain rather than
//directly into current domain:
//assembly = System.Reflection.Assembly.LoadFrom(fileName);
string assemblyShortName =
System.IO.Path.GetFileNameWithoutExtension(fileNam e);
assembly = tmpDomain.Load(assemblyShortName);

type = assembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}






"Nicholas Paldino [.NET/C# MVP]" wrote:
>Sky,

There is no way around it, you are going to have to provide the
assembly
name, and not just the type name. A type's identity is not simply the
name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies
and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microso ft.com...
>I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one
solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:

Step 1: Find a Type in the calling Assembly, or fallback to mscorlib:
GetType() looks for a class by that name in the calling Assembly, and
then
falls back to search in mscorlib.
As you can imagine, this doesn't get us far.

Step 2: Looking in other Assemblies already loaded:
If not in either of these two, you have to fall back to using
AppDomain.GetAssemblies(), and then loop through each individually to
test
each one with assembly.GetType(string).

Step 3: Looking in Assemblies not already loaded:
But these only refer to assemblies already loaded -- and will fail if
the
assembly has not loaded yet, so you then have to
Assembly.Load(pathName)
for
each assembly in the bin dir that ends with ".dll" and ".exe".

Step 4: Looking in the GAC:
The above solutions almost get us through everything, except there
stilll
is
missing one place to look, the GAC. How can I get a list of assemblies
in
the
GAC, to search through them as well?
Questions:
a) The Assembly.LoadFile() worries me a lot: how does it work, exactly?
I
assume it does exactly as implied, and loads it up in memory -- so
calling
it
at the beginning of a program could mean that *all* assemblies are
loaded
in
memory right from the start, making for a slower startup... Calling and
loading all files in the GAC to search through them would end up with a
lot
of memory for assemblies that have nothing to do with the application,
right?

b) This all seems to be a very complex route, that even with caching
for
later, could be a massive drain on system resources -- is there any
simpler
way?

c) GetAssemblies() is not available on CE...Is there *any* other way to
get
a list of assemblies loaded in memory other than
AppDomain.GetAssemblies?

Thank you for any and all feedback, and pointers,
Sky

BTW: For anybody that is interested, the code for the above looks a bit
like:

private static Type LoadType(string typeName) {
System.Reflection.Assembly assembly;
return LoadType(typeName, out assembly);
}

private static Type LoadType(string typeName, out
System.Reflection.Assembly assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

#if (!PocketPC) && (!pocketPC) && (!WindowsCE)
foreach (System.Reflection.Assembly tmpAasembly in
System.AppDomain.CurrentDomain.GetAssemblies()) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
}
#endif

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetCallingAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
assembly = System.Reflection.Assembly.LoadFrom(fileName);

type = assembly.GetType(typeName);
if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}



Jul 25 '06 #4
Sky
Hi Nicholas:

First:
<<Without it seeming like I am being chastising, you do need to rethink
that approach...>>
True. :-) I think i just needed to beat it out in public to see the error of
my ways :-) I am seeing more and more that the problem that I was looking for
a solution to is actually a problem that I was causing myself, due to the way
I was coding... Hum. Got it. Give TypeName + AssemblyName. (But don't need
Version or culture...)

Second:
WebConfig. Sorry...that was a typo. I meant App.Config: I clearly understand
that if one rolls out more modules, that the app.config has to be updated on
the clientside, and web.config is another kettle to be sorted out
independantly.

What I don't see clearly is the following way to handle scenarios such as
this one:
Imagine an app for PocketPC/Desktop that has a common plugin arch. You first
ship it with 5 modules. Turns out later than one set of clients pays for the
Extras and downloads 5 more modules, and another group even goes for Platinum
and downloads 5 more modules. Finally, we release 5 more that nobody seems
interested in. So now we have some clients with 5, some with 10, some with 15
assemblies/modules....which means some only need 5 Sections in app.config,
some 10, some 15. What do we do? Update all with the same config with info
about all modules they could be getting (5+5+5+10) or only what they each got
(5, 10, 15)?

It's just that updating the app.config on the fly, adding module
sectionhandlers and sections as being downloaded...freaks me out. What if
there is a write error half way through? I could blow out whole swaths of
users due one stupid update error...On the PocketPC, it would be a nightmare
to ask them to use pocket Notes to look at their app.config to see what
modules are defined...

Third:
You mentioned ClickOnce manifest as a possible way to go: I'm not too up to
speed on ClickOnce (I tried back in beta and it felt good for an app that
needed to be updated in one block, sending all modules in same package), but
not perfect for a download-as-you-need modular approach. Or did I miss
something that I could use here?

Fourth:
User Settings. Not in app.config. Very bad you say, which is very good :-).
So why does MS push it? Plus, I'm getting a bit confused as to which one I am
suppossed to use! There was originally app.config in 1.1, now there are
*.settings files, that produce two sections (user/application).
App.settings are read only, and the other two are read/write -- I think.
Are we supposed to still use both? Or is app.settings depracated, and we
should concentrate on the later two?
Am I right that all three point to app.settings, not another file...
You mentioned using external files to save user settings....how with these
files? Or should we be rolling our own storage system?

Fifth:
Better ask before taking this for granted: you say user settings should be
in secondary file...what about application settings? In app.config, or an
exterior one too, and just use app.config for wiring stuff
(sectionhandlers->Providers).
Thanks!
Sky

"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

See inline.
Actually it probably comes from my having had really frustrating
experiences
with app.configs/ConnectionSettings/Providers in general when I first
started
out. Seemed I could never get up and running without a lot of poking
around
due to very vague error messages, combined with one little spelling
mistake
in an app.Config.

Well, yes, but in the end, that's understandable. Computers can't
understand intent.
The whole thing set me off right from the start distrusting pointing to
assemblies with version and culture numbers: it seems to be way too
specific,
and causes me nothing but frustration.

It also just seems to me that the current assemby full names are *way* too
specific, whereas they should be in *most* cases 'loose', only resorting
to
specific culture/version to handle specific clashes.

In addition, I'm not sure that I even agree that a config file is the best
location for some of this identity inforation: I suspect that Culture
should
be handled via code choices of satellite resource assemblies,

How satellite resource assemblies are referenced is clearly laid out in
the framework documentation. This shouldn't be such a big issue. The
static CurrentCulture property on the Thread class is used to make a
decision from which assembly to load resources from.
But probably what worries me the most is the issue of version numbers --
hard to update a growing app (ie more assemblies) over the web without
having
to update the config file as well. And that is made very complicated when
the
app has
a) user settings in it,
b) is a modular type of software where other vendors may need to also have
settings in the app.config for their assemblies.

That's part of your problem there. You shouldn't be storing ^user^
configuration information in a file that is meant for ^application^
configuration. You should be handling user preferences in a separate file.

As for updating the config file, if your user settings aren't in there,
it shouldn't be such a big deal. Have you looked at ClickOnce for your
deployment scenario? It should help with this situation greatly.
Talking about that last piece a little bit more: it seems that the
app.config model is more suited for installation packages, and/or
ClickOnce
packages. But if I am correct, code is going to be more and more like
services...ie thin+ clients that start off with some modules, and as
needed
(or paid for...) or released, more modules are downloaded and installed,
that
are updatable much more fluidly (webservice+serializationofdlls+throw out
and
restart appdomain)...where the webconfig stuff will need to be updated for
every new module downloaded, and every version shift in the downloaded
modules.... Seems like this is very hard to do with current thinking...
I'm
REALLY looking for pointers/thoughts/articles on this type of thinking...

I don't think that your perspective on app.config is correct. It simply
is a way of specifying configuration details for your application, details
which could change over the course of the installation. It's a way of
providing a uniform interface to those configuration details.

ClickOnce has a separate manifest altogether.

The web.config file is for your service side only. If you roll out new
features on that end, then yes, you will have to update it (assuming there
is information in there that you need to access).

Then again, this point of view of mne all might be caused from to a
completly wrong understanding of how the whole thing fits together,
whereas a
fresh look/undestanding of how to use it all would sort it all out! :-)
For
example, I'm one of the people who just doesn't get User Settings in an
app.config. Oh, sure I get the simplicity of typed access to
properties...but
saving user settings in an app.config seems to be exactly the same as
keeping
stuff intended for c:\Documents and Settings\Users\YourSettings under
c:\Programs Files\Your app.... Sounds like a very messed up way of doing
things, no?

I agree with you completely on this. The app.config file is not a place
that user settings should be set. Also, the idea of an app changing the
app.config file while it is running is not something I agree with either.
Hence, my struggling around to find a good solution: currently this leads
me
to believe that references to assemblies being 'loose', with short names,
and
not always the assembly it belongs in.

Which when I think about it...doesn't answer your question... Hum.

As for why I can't put the assembly name... That was your question. Is the
answer simply because I'm lazy? I know the type, but I don't always know
what
assembly it is in? Especially because I sometimes move things around from
one
assembly to another as I progress through coding and get clearer as to
where
it should go(eg: I start with a simple 1 assembly exe, and later make it
into
an multiple assembly application (UIL, BLL, DAL) and have to move code
that
was originally placed in UIL to BLL...
Which is not a good reason to not put in the assembly name as well. It
just
seems to indicate that I am lazy. Hum. I'll have to think about that.

Without it seeming like I am being chastising, you do need to rethink
that approach. A type is not only defined by its code, but by it's
location, which means the assembly name. You say you know the type, but if
you don't always know what assembly it is in, then you CAN'T know the type.

Also, here is a hint. If you use the static Load method on the Assembly
class, you don't have to always specify the complete name. You can specify
the assembly name without the public key, the culture, and the version, and
it will get the best match.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com


Sky
BTW: Solution to my question in the last post, about not using up all
resources:
...the solution is to use a secondary AppDomain to load the Assemblies
into,
that can then be dumped. I was stunned to find that one can get a Type out
of
an Assembly in a secondary domain, and then dump the secondary domain, and
use the Type in the first domain, without it bugging out due to the Type
pointing to a null address...I would have thought (limited experience with
AppDomains...) that it would somehow cause a type of memory exception
pointing into mem that is no longer available...even after a GC.Collect().
So there. It works. On desktop/full.... But not on CE because CE's
AppDomain
is stunted and doesn't have a Load(string) feature to do the same trick.
Anybody have an idea?

PPS: I am still looking for answers to find out what is in the GAC? And
the
equivalent to LoadAssembly(string) and GetAssemblies(string) on Compact
NET...anyone?
public static Type LoadType(string typeName, out
System.Reflection.Assembly
assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
//Create a second domain:
System.AppDomain currentAppDomain = System.AppDomain.CurrentDomain;
System.Security.Policy.Evidence evidence =
System.AppDomain.CurrentDomain.Evidence;
System.AppDomain secondDomain =
System.AppDomain.CreateDomain("typeLoader", evidence);
System.AppDomain tmpDomain = secondDomain;//currentAppDomain;
int tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;
//zero?

//Get assemblies in tmp domain:
//suprisingly, this turned out to have same results
//as currentDomain -- I would have thought it would report back
//less assemblies. Nice.
System.Reflection.Assembly[] assemblies = tmpDomain.GetAssemblies();
int foundCount = assemblies.Length;

foreach (System.Reflection.Assembly tmpAasembly in assemblies) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
//Load assembly into tmp domain rather than
//directly into current domain:
//assembly = System.Reflection.Assembly.LoadFrom(fileName);
string assemblyShortName =
System.IO.Path.GetFileNameWithoutExtension(fileNam e);
assembly = tmpDomain.Load(assemblyShortName);

type = assembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}






"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

There is no way around it, you are going to have to provide the
assembly
name, and not just the type name. A type's identity is not simply the
name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies
and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one
solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:
Jul 25 '06 #5
Sky
While I'm searching for answers to the questions I posted in last post,
concerning
app.settings, user and application settings, where to save them, how to
access them, etc, I came across the following blog which seems to cover the
most terrain:

http://geekswithblogs.net/akraus1/articles/64871.aspx

I'm still digesting it, trying to see how best to put it to use, but in the
mean-time I'm posting it anycase it is of use to anybody else as well who is
looking for info on settings....
"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

See inline.
Actually it probably comes from my having had really frustrating
experiences
with app.configs/ConnectionSettings/Providers in general when I first
started
out. Seemed I could never get up and running without a lot of poking
around
due to very vague error messages, combined with one little spelling
mistake
in an app.Config.

Well, yes, but in the end, that's understandable. Computers can't
understand intent.
The whole thing set me off right from the start distrusting pointing to
assemblies with version and culture numbers: it seems to be way too
specific,
and causes me nothing but frustration.

It also just seems to me that the current assemby full names are *way* too
specific, whereas they should be in *most* cases 'loose', only resorting
to
specific culture/version to handle specific clashes.

In addition, I'm not sure that I even agree that a config file is the best
location for some of this identity inforation: I suspect that Culture
should
be handled via code choices of satellite resource assemblies,

How satellite resource assemblies are referenced is clearly laid out in
the framework documentation. This shouldn't be such a big issue. The
static CurrentCulture property on the Thread class is used to make a
decision from which assembly to load resources from.
But probably what worries me the most is the issue of version numbers --
hard to update a growing app (ie more assemblies) over the web without
having
to update the config file as well. And that is made very complicated when
the
app has
a) user settings in it,
b) is a modular type of software where other vendors may need to also have
settings in the app.config for their assemblies.

That's part of your problem there. You shouldn't be storing ^user^
configuration information in a file that is meant for ^application^
configuration. You should be handling user preferences in a separate file.

As for updating the config file, if your user settings aren't in there,
it shouldn't be such a big deal. Have you looked at ClickOnce for your
deployment scenario? It should help with this situation greatly.
Talking about that last piece a little bit more: it seems that the
app.config model is more suited for installation packages, and/or
ClickOnce
packages. But if I am correct, code is going to be more and more like
services...ie thin+ clients that start off with some modules, and as
needed
(or paid for...) or released, more modules are downloaded and installed,
that
are updatable much more fluidly (webservice+serializationofdlls+throw out
and
restart appdomain)...where the webconfig stuff will need to be updated for
every new module downloaded, and every version shift in the downloaded
modules.... Seems like this is very hard to do with current thinking...
I'm
REALLY looking for pointers/thoughts/articles on this type of thinking...

I don't think that your perspective on app.config is correct. It simply
is a way of specifying configuration details for your application, details
which could change over the course of the installation. It's a way of
providing a uniform interface to those configuration details.

ClickOnce has a separate manifest altogether.

The web.config file is for your service side only. If you roll out new
features on that end, then yes, you will have to update it (assuming there
is information in there that you need to access).

Then again, this point of view of mne all might be caused from to a
completly wrong understanding of how the whole thing fits together,
whereas a
fresh look/undestanding of how to use it all would sort it all out! :-)
For
example, I'm one of the people who just doesn't get User Settings in an
app.config. Oh, sure I get the simplicity of typed access to
properties...but
saving user settings in an app.config seems to be exactly the same as
keeping
stuff intended for c:\Documents and Settings\Users\YourSettings under
c:\Programs Files\Your app.... Sounds like a very messed up way of doing
things, no?

I agree with you completely on this. The app.config file is not a place
that user settings should be set. Also, the idea of an app changing the
app.config file while it is running is not something I agree with either.
Hence, my struggling around to find a good solution: currently this leads
me
to believe that references to assemblies being 'loose', with short names,
and
not always the assembly it belongs in.

Which when I think about it...doesn't answer your question... Hum.

As for why I can't put the assembly name... That was your question. Is the
answer simply because I'm lazy? I know the type, but I don't always know
what
assembly it is in? Especially because I sometimes move things around from
one
assembly to another as I progress through coding and get clearer as to
where
it should go(eg: I start with a simple 1 assembly exe, and later make it
into
an multiple assembly application (UIL, BLL, DAL) and have to move code
that
was originally placed in UIL to BLL...
Which is not a good reason to not put in the assembly name as well. It
just
seems to indicate that I am lazy. Hum. I'll have to think about that.

Without it seeming like I am being chastising, you do need to rethink
that approach. A type is not only defined by its code, but by it's
location, which means the assembly name. You say you know the type, but if
you don't always know what assembly it is in, then you CAN'T know the type.

Also, here is a hint. If you use the static Load method on the Assembly
class, you don't have to always specify the complete name. You can specify
the assembly name without the public key, the culture, and the version, and
it will get the best match.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com


Sky
BTW: Solution to my question in the last post, about not using up all
resources:
...the solution is to use a secondary AppDomain to load the Assemblies
into,
that can then be dumped. I was stunned to find that one can get a Type out
of
an Assembly in a secondary domain, and then dump the secondary domain, and
use the Type in the first domain, without it bugging out due to the Type
pointing to a null address...I would have thought (limited experience with
AppDomains...) that it would somehow cause a type of memory exception
pointing into mem that is no longer available...even after a GC.Collect().
So there. It works. On desktop/full.... But not on CE because CE's
AppDomain
is stunted and doesn't have a Load(string) feature to do the same trick.
Anybody have an idea?

PPS: I am still looking for answers to find out what is in the GAC? And
the
equivalent to LoadAssembly(string) and GetAssemblies(string) on Compact
NET...anyone?
public static Type LoadType(string typeName, out
System.Reflection.Assembly
assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
//Create a second domain:
System.AppDomain currentAppDomain = System.AppDomain.CurrentDomain;
System.Security.Policy.Evidence evidence =
System.AppDomain.CurrentDomain.Evidence;
System.AppDomain secondDomain =
System.AppDomain.CreateDomain("typeLoader", evidence);
System.AppDomain tmpDomain = secondDomain;//currentAppDomain;
int tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;
//zero?

//Get assemblies in tmp domain:
//suprisingly, this turned out to have same results
//as currentDomain -- I would have thought it would report back
//less assemblies. Nice.
System.Reflection.Assembly[] assemblies = tmpDomain.GetAssemblies();
int foundCount = assemblies.Length;

foreach (System.Reflection.Assembly tmpAasembly in assemblies) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
//Load assembly into tmp domain rather than
//directly into current domain:
//assembly = System.Reflection.Assembly.LoadFrom(fileName);
string assemblyShortName =
System.IO.Path.GetFileNameWithoutExtension(fileNam e);
assembly = tmpDomain.Load(assemblyShortName);

type = assembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}






"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

There is no way around it, you are going to have to provide the
assembly
name, and not just the type name. A type's identity is not simply the
name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies
and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one
solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:
Jul 25 '06 #6
Sky
Another quick post about good info I've found while trying to clear this all
up:

An essential blog entry to make things clear about how appSettings,
userSettings, and applicationSettings work in NET 2.0

http://blogs.msdn.com/rprabhu/articles/433979.aspx


"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

See inline.
Actually it probably comes from my having had really frustrating
experiences
with app.configs/ConnectionSettings/Providers in general when I first
started
out. Seemed I could never get up and running without a lot of poking
around
due to very vague error messages, combined with one little spelling
mistake
in an app.Config.

Well, yes, but in the end, that's understandable. Computers can't
understand intent.
The whole thing set me off right from the start distrusting pointing to
assemblies with version and culture numbers: it seems to be way too
specific,
and causes me nothing but frustration.

It also just seems to me that the current assemby full names are *way* too
specific, whereas they should be in *most* cases 'loose', only resorting
to
specific culture/version to handle specific clashes.

In addition, I'm not sure that I even agree that a config file is the best
location for some of this identity inforation: I suspect that Culture
should
be handled via code choices of satellite resource assemblies,

How satellite resource assemblies are referenced is clearly laid out in
the framework documentation. This shouldn't be such a big issue. The
static CurrentCulture property on the Thread class is used to make a
decision from which assembly to load resources from.
But probably what worries me the most is the issue of version numbers --
hard to update a growing app (ie more assemblies) over the web without
having
to update the config file as well. And that is made very complicated when
the
app has
a) user settings in it,
b) is a modular type of software where other vendors may need to also have
settings in the app.config for their assemblies.

That's part of your problem there. You shouldn't be storing ^user^
configuration information in a file that is meant for ^application^
configuration. You should be handling user preferences in a separate file.

As for updating the config file, if your user settings aren't in there,
it shouldn't be such a big deal. Have you looked at ClickOnce for your
deployment scenario? It should help with this situation greatly.
Talking about that last piece a little bit more: it seems that the
app.config model is more suited for installation packages, and/or
ClickOnce
packages. But if I am correct, code is going to be more and more like
services...ie thin+ clients that start off with some modules, and as
needed
(or paid for...) or released, more modules are downloaded and installed,
that
are updatable much more fluidly (webservice+serializationofdlls+throw out
and
restart appdomain)...where the webconfig stuff will need to be updated for
every new module downloaded, and every version shift in the downloaded
modules.... Seems like this is very hard to do with current thinking...
I'm
REALLY looking for pointers/thoughts/articles on this type of thinking...

I don't think that your perspective on app.config is correct. It simply
is a way of specifying configuration details for your application, details
which could change over the course of the installation. It's a way of
providing a uniform interface to those configuration details.

ClickOnce has a separate manifest altogether.

The web.config file is for your service side only. If you roll out new
features on that end, then yes, you will have to update it (assuming there
is information in there that you need to access).

Then again, this point of view of mne all might be caused from to a
completly wrong understanding of how the whole thing fits together,
whereas a
fresh look/undestanding of how to use it all would sort it all out! :-)
For
example, I'm one of the people who just doesn't get User Settings in an
app.config. Oh, sure I get the simplicity of typed access to
properties...but
saving user settings in an app.config seems to be exactly the same as
keeping
stuff intended for c:\Documents and Settings\Users\YourSettings under
c:\Programs Files\Your app.... Sounds like a very messed up way of doing
things, no?

I agree with you completely on this. The app.config file is not a place
that user settings should be set. Also, the idea of an app changing the
app.config file while it is running is not something I agree with either.
Hence, my struggling around to find a good solution: currently this leads
me
to believe that references to assemblies being 'loose', with short names,
and
not always the assembly it belongs in.

Which when I think about it...doesn't answer your question... Hum.

As for why I can't put the assembly name... That was your question. Is the
answer simply because I'm lazy? I know the type, but I don't always know
what
assembly it is in? Especially because I sometimes move things around from
one
assembly to another as I progress through coding and get clearer as to
where
it should go(eg: I start with a simple 1 assembly exe, and later make it
into
an multiple assembly application (UIL, BLL, DAL) and have to move code
that
was originally placed in UIL to BLL...
Which is not a good reason to not put in the assembly name as well. It
just
seems to indicate that I am lazy. Hum. I'll have to think about that.

Without it seeming like I am being chastising, you do need to rethink
that approach. A type is not only defined by its code, but by it's
location, which means the assembly name. You say you know the type, but if
you don't always know what assembly it is in, then you CAN'T know the type.

Also, here is a hint. If you use the static Load method on the Assembly
class, you don't have to always specify the complete name. You can specify
the assembly name without the public key, the culture, and the version, and
it will get the best match.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com


Sky
BTW: Solution to my question in the last post, about not using up all
resources:
...the solution is to use a secondary AppDomain to load the Assemblies
into,
that can then be dumped. I was stunned to find that one can get a Type out
of
an Assembly in a secondary domain, and then dump the secondary domain, and
use the Type in the first domain, without it bugging out due to the Type
pointing to a null address...I would have thought (limited experience with
AppDomains...) that it would somehow cause a type of memory exception
pointing into mem that is no longer available...even after a GC.Collect().
So there. It works. On desktop/full.... But not on CE because CE's
AppDomain
is stunted and doesn't have a Load(string) feature to do the same trick.
Anybody have an idea?

PPS: I am still looking for answers to find out what is in the GAC? And
the
equivalent to LoadAssembly(string) and GetAssemblies(string) on Compact
NET...anyone?
public static Type LoadType(string typeName, out
System.Reflection.Assembly
assemblyTypeFoundIn) {
if (string.IsNullOrEmpty(typeName)) {
throw new System.ArgumentNullException("typeName");
}
//Clear results first:
assemblyTypeFoundIn = null;
System.Reflection.Assembly assembly = null;
System.Type type = null;

type = System.Type.GetType(typeName, false, true);

if (type != null) {
assemblyTypeFoundIn = type.Assembly;
return type;
}
//Create a second domain:
System.AppDomain currentAppDomain = System.AppDomain.CurrentDomain;
System.Security.Policy.Evidence evidence =
System.AppDomain.CurrentDomain.Evidence;
System.AppDomain secondDomain =
System.AppDomain.CreateDomain("typeLoader", evidence);
System.AppDomain tmpDomain = secondDomain;//currentAppDomain;
int tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;
//zero?

//Get assemblies in tmp domain:
//suprisingly, this turned out to have same results
//as currentDomain -- I would have thought it would report back
//less assemblies. Nice.
System.Reflection.Assembly[] assemblies = tmpDomain.GetAssemblies();
int foundCount = assemblies.Length;

foreach (System.Reflection.Assembly tmpAasembly in assemblies) {
type = tmpAasembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
tmpCount = currentAppDomain.ReflectionOnlyGetAssemblies().Len gth;

//Get Path to Bin folder:
string exePath;
//exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
exePath =
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName);
string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
foreach (string fileName in fileNames) {
try {
//Load assembly into tmp domain rather than
//directly into current domain:
//assembly = System.Reflection.Assembly.LoadFrom(fileName);
string assemblyShortName =
System.IO.Path.GetFileNameWithoutExtension(fileNam e);
assembly = tmpDomain.Load(assemblyShortName);

type = assembly.GetType(typeName);
if (type != null) {
System.AppDomain.Unload(tmpDomain);
System.GC.Collect();
assemblyTypeFoundIn = type.Assembly;
return type;
}

}
catch {
assembly = null;
}
}
return null;
}






"Nicholas Paldino [.NET/C# MVP]" wrote:
Sky,

There is no way around it, you are going to have to provide the
assembly
name, and not just the type name. A type's identity is not simply the
name
that it has, but also the module/assembly that it is located in.

For what reason are you looking for a particular type across ALL
assemblies? If you have a need for a specific type, why not have a well
known location (like a subdirectory) where you can load the assemblies
and
scan for your type?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
I have been looking for a more powerful version of GetType(string) that
will
find the Type no matter what, and will work even if only supplied
"{TypeName}", not the full "{TypeName},{AssemblyName}"

As far as I know yet -- hence this question -- there is no 'one
solution
fits all', but instead there are several parts that have to be put
together
to check.

What I have so far is, and would like as much feedback as possible to
ensure
I've done the best job possible is:
Jul 26 '06 #7
Sky,
PMFJI

|I have been looking for a more powerful version of GetType(string) that
will
| find the Type no matter what, and will work even if only supplied
| "{TypeName}", not the full "{TypeName},{AssemblyName}"

You mean something like the BuildManager.GetType in ASP.NET 2.0?

http://msdn2.microsoft.com/en-us/library/a0z5yws8.aspx
--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net
"Sky" <public.skysigal{*AT*}xact-solutions.comwrote in message
news:2E**********************************@microsof t.com...
|I have been looking for a more powerful version of GetType(string) that
will
| find the Type no matter what, and will work even if only supplied
| "{TypeName}", not the full "{TypeName},{AssemblyName}"
|
| As far as I know yet -- hence this question -- there is no 'one solution
| fits all', but instead there are several parts that have to be put
together
| to check.
|
| What I have so far is, and would like as much feedback as possible to
ensure
| I've done the best job possible is:
|
| Step 1: Find a Type in the calling Assembly, or fallback to mscorlib:
| GetType() looks for a class by that name in the calling Assembly, and then
| falls back to search in mscorlib.
| As you can imagine, this doesn't get us far.
|
| Step 2: Looking in other Assemblies already loaded:
| If not in either of these two, you have to fall back to using
| AppDomain.GetAssemblies(), and then loop through each individually to test
| each one with assembly.GetType(string).
|
| Step 3: Looking in Assemblies not already loaded:
| But these only refer to assemblies already loaded -- and will fail if the
| assembly has not loaded yet, so you then have to Assembly.Load(pathName)
for
| each assembly in the bin dir that ends with ".dll" and ".exe".
|
| Step 4: Looking in the GAC:
| The above solutions almost get us through everything, except there stilll
is
| missing one place to look, the GAC. How can I get a list of assemblies in
the
| GAC, to search through them as well?
|
|
| Questions:
| a) The Assembly.LoadFile() worries me a lot: how does it work, exactly? I
| assume it does exactly as implied, and loads it up in memory -- so calling
it
| at the beginning of a program could mean that *all* assemblies are loaded
in
| memory right from the start, making for a slower startup... Calling and
| loading all files in the GAC to search through them would end up with a
lot
| of memory for assemblies that have nothing to do with the application,
right?
|
| b) This all seems to be a very complex route, that even with caching for
| later, could be a massive drain on system resources -- is there any
simpler
| way?
|
| c) GetAssemblies() is not available on CE...Is there *any* other way to
get
| a list of assemblies loaded in memory other than AppDomain.GetAssemblies?
|
| Thank you for any and all feedback, and pointers,
| Sky
|
| BTW: For anybody that is interested, the code for the above looks a bit
like:
|
| private static Type LoadType(string typeName) {
| System.Reflection.Assembly assembly;
| return LoadType(typeName, out assembly);
| }
|
| private static Type LoadType(string typeName, out
| System.Reflection.Assembly assemblyTypeFoundIn) {
| if (string.IsNullOrEmpty(typeName)) {
| throw new System.ArgumentNullException("typeName");
| }
| //Clear results first:
| assemblyTypeFoundIn = null;
| System.Reflection.Assembly assembly = null;
| System.Type type = null;
|
| type = System.Type.GetType(typeName, false, true);
|
| if (type != null) {
| assemblyTypeFoundIn = type.Assembly;
| return type;
| }
|
| #if (!PocketPC) && (!pocketPC) && (!WindowsCE)
| foreach (System.Reflection.Assembly tmpAasembly in
| System.AppDomain.CurrentDomain.GetAssemblies()) {
| type = tmpAasembly.GetType(typeName);
| if (type != null) {
| assemblyTypeFoundIn = type.Assembly;
| return type;
| }
| }
| #endif
|
| //Get Path to Bin folder:
| string exePath;
| //exePath = System.AppDomain.CurrentDomain.BaseDirectory;
| //exePath =
|
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
| exePath =
|
System.IO.Path.GetDirectoryName(System.Reflection. Assembly.GetCallingAssembly().GetModules()[0].FullyQualifiedName);
| string[] fileNames = System.IO.Directory.GetFiles(exePath, "*.dll");
| foreach (string fileName in fileNames) {
| try {
| assembly = System.Reflection.Assembly.LoadFrom(fileName);
|
| type = assembly.GetType(typeName);
| if (type != null) {
| assemblyTypeFoundIn = type.Assembly;
| return type;
| }
|
| }
| catch {
| assembly = null;
| }
|
|
| }
| return null;
| }
|
Jul 27 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Kendall Gifford | last post by:
Greetings. While trying to get a simple app working, I've been forced to delve into embedded and/or linked resources a bit. I read all the reference for the System.Resources namespace as well as...
2
by: Sean | last post by:
Hello, I have a function in C# that accepts a stored proc name and an array of parameters, and then returns a dataset, which works just fine. I have converted the function to VB: Public Shared...
6
by: tshad | last post by:
The error I am getting is: ******************************************************************* Exception Details: System.InvalidCastException: Cast from type 'DBNull' to type 'String' is not...
4
by: Sparky Arbuckle | last post by:
I am looping through a listbox collection to build a SQL string that will be used to delete items from a database. I have tried many variances of the code below but have had no luck. The code below...
9
by: Ben | last post by:
Hello, I'm not a developper, so sorry if it's a stupid question... I'm trying to develop an application in vb.net and I have the following problem: I have some information in an array:...
1
by: Jason Chan | last post by:
in asp.net 2.0, Page.RegisterClientScriptBlock is replaced by Client.RegisterClientScriptBlock function signature: Client.RegisterClientScriptBlock(Type, String, String) what should i put...
9
by: Gugale at Lincoln | last post by:
In my code Type.GetType(text) works when text="System.IO.File". However, it doesn't work when text="System.Windows.Forms.Button". In general it works for classes in System.dll assembly. Is there...
3
by: usenet | last post by:
Kindly pardon my ignorance, but what is the way to declare a constant attribute of type string within a class? Thanks, Gus
8
by: Martin Eckart | last post by:
Hi folks, Who can explain me why the following expression does not result in getting the correct type, but null: Type t = Type.GetType("System.Xml.XmlReader"); For "System.String" it works...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.