Programmatically determine if .NET 3.0 is installed

G

Guest

I am writing a web app to be widely distributed where I do not know the
installed .NET Framework version. I want to take advantage of some .NET 3.0
classes if they are installed, but gracefully degrade if not available.
(Specifically, I want to use System.Windows.Media.Imaging.BitmapMetadata to
extract metadata from JPEG files when 3.0 is available, but will resort to
System.Drawing.Image if .NET 3.0 is not installed.)

What is the recommended best practice for determining whether .NET 3.0 is
installed? The solution must work in a Medium Trust environment. I am not
sure if there is a framework class for querying this info or if I should just
try accessing the class and let the exception tell me it is not available.

I have found that System.Environment.Version.ToString() gives 2.0.50727.1378
on my PC, so that doesn't help. (Unless the "1378" indicates that 3.0 is
installed, but I doubt it.)

Thanks!
Roger Martin
 
J

Juan T. Llibre

<HTML>
<HEAD>
<TITLE>Test for the .NET Framework 3.0</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />
<script language="JavaScript" type="text/javascript">
var a = navigator.userAgent.match(/\.NET CLR [0-9.]+/g);
if (a == null)
document.write( "Microsoft .NET is not installed on your PC" )
else
{
document.write( "The following versions of Microsoft .NET are installed on your PC:<br/>" )
for (i = 0; i < a.length; ++i)
{
document.write( a )
document.write( "<br/>" )
}
}
</script>

</HEAD>

<BODY>

</BODY>
</HTML>
============

As you can see, the critical part is :

navigator.userAgent.match(/\.NET CLR [0-9.]+/g);

You may need to parse the results to accomodate your needs.
 
G

Guest

I am sorry, but I need to determine the version running on the web server,
not on the client browser. The normal way would be to have code-behind refer
to System.Environment.Version.ToString(), but as I mentioned this returns
2.0.50727.1378, even when I have 3.0 installed.
 
J

Juan T. Llibre

W

Walter Wang [MSFT]

Hi Roger,

Do you mean that you want to build your program against .NET Framework 2.0
but want to dynamically detect and load an assembly from .NET Framework
3.0? How will you use the System.Drawing.Image? Using reflection?

You can use registry to determine if .NET Framework 3.0 is installed or not:

http://msdn2.microsoft.com/en-US/library/aa480173.aspx#deploywinfx_topic11

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I am under the impression one cannot access the registry under Medium Trust,
but correct me if I am wrong.

I am building my web app and supporting class libraries against .NET 2.0,
but one of my class libraries has a reference to WindowsBase.dll and
PresentationCore.dll from .NET 3.0. When running this on a PC with .NET 2.0
*only*, the app runs fine and throws an exception only when directly invoking
the .NET 3.0 classes (i.e. System.Windows.Media.Imaging.BitmapMetadata).

That is why I would like to add some conditional logic to execute the 3.0
code only when .NET 3.0 is present, and avoid it when it is not. As I said
before, the solution must work under Medium Trust.

I think I can implement a solution by running the .NET 3.0 code in a try{}
block, but I started this thread to find out if there is a better, officially
recommended route. The solutions offered thus far do not work in Medium
Trust, and catching an exception is not very efficient, so I am hoping there
is a better way.

To answer your question about System.Drawing.Image, I access it directly and
not through reflection.

Roger Martin
 
G

Guest

but one of my class libraries has a reference to WindowsBase.dll and
PresentationCore.dll from .NET 3.0.

Hi Roger

the .NET 3 adds into context at least two new assemblies for WCF, and
this can be checked using AppDomain.GetAssemblies() method. If you
found one of these assemblies - .NET 3 is installed

Example:

System.Reflection.Assembly[] assemblies =
AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly assembly in assemblies)
{
if (assembly.ManifestModule.Name.ToLower() ==
"system.runtime.serialization.dll")
..... // .net 3 is installed
}

In principle, in the same way you can test if PresentationCore or
other assembly has been loaded

System.Reflection.Assembly[] assemblies =
AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly assembly in assemblies)
{
if (assembly.ManifestModule.Name.ToLower() == "presentationcore.dll")
.... // loaded
}

Hope it helps
 
W

Walter Wang [MSFT]

Based on my understanding, what Roger is trying to do here is to have a
separate assembly that has references to .NET 3.0 framework, and he need to
detect if .NET 3.0 is installed or not before using/loading this assembly.
Therefore I don't think your method will work since the main assembly isn't
referencing .NET 3.0 framework and current AppDomain certainly has not
loaded any 3.0 assemblies.

Roger, you're right registry access is not allowed in medium trust. I
somehow overlooked this in your first message, sorry.

So far I'm not aware of any official way to achieve this, I'll need some
time to do some researching and consulting for you. I'll keep you posted.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thanks for looking into this, Walter. I look forward to your response.

Interestingly, I thought Alexey may have given me the solution I needed by
using AppDomain.CurrentDomain.GetAssemblies() to discover if
presentationcore.dll was loaded. This actually works when the app is running
under Full Trust. My project has a static reference to presentationcore.dll,
and .NET seems to load it when it is present and not load it when not
present. If I place Alexey's code just before I reference .NET 3.0 specific
classes, I can avoid calling the classes when .NET 3.0 is not there. Works
great!

Alas, the technique fails under Medium Trust. During app startup I get the
following exception:

System.Security.Policy.PolicyException: Required permissions cannot be
acquired.

[HttpException (0x80004005): Could not load file or assembly
'PresentationCore, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' or one of its dependencies. Failed to grant
minimum permission requests. (Exception from HRESULT: 0x80131417)]

So it seems my web app should not have a reference to presentationcore.dll
and instead I must dynamically load the dll only when .NET 3.0 is installed.
This is what Walter was suggesting in his last post, and it makes sense. I
hope we can figure out how to do this.

Cheers,
Roger Martin
 
W

Walter Wang [MSFT]

Hi Roger,

Thanks for the update.

I've been consulting and researching on this issue recently. Here's the
summary so far:

Since ASP.NET in Medium trust by default doesn't have access to registry,
file system outside the virtual directory, and reflection: we will no
longer be able to detect .NET 3.0's presence using the normal way (that is
checking registry). Therefore I'm afraid the only option left is to use
try-catch to determine if your assembly that's using .NET 3.0 is ok to use
or not. I understand that you have some concerns on the performance issue
of this approach, my suggestion is that you can use a static class and
variable to do this once and shared by your entire web application:

public static class Class1
{

public static readonly bool IsMyAssemblyUsingNet3Avaiable;

static Class1()
{
try
{
MyClassUseNet3 c3 = new MyClassUseNet3();
IsMyAssemblyUsingNet3Avaiable = true;
}
catch (Exception)
{
IsMyAssemblyUsingNet3Avaiable = false;
}
}
}

A static variable in ASP.NET web application will live with the ASP.NET
worker process.

You need to remove those 3.0 assemblies references in web.config if they're
added by IDE when you reference the assembly that is referencing 3.0
framework.

I've tested this on my side with two systems (one with 3.0, one without)
and it seems it's working fine. The checking is only made once, later you
can directly use the Class1.IsMyAssemblyUsingNet3Available variable to
determine which class to use.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

You got me on the right path and I think I have it solved.

You said to remove the references to the .NET 3.0 assemblies, but of course
doing so meant my project no longer compiled. So I refactored the .NET 3.0
code into a new class library that *does* have references to the required
..NET 3.0 assemblies.

Back in my main library, I wrote code that runs at app startup that uses
Reflection to invoke my new class library. A flag is set based on it passing
or throwing an exception that I can use later in my app's lifetime.

Here is the function that runs at app startup. Note that I don't need the
invoked method to actually do anything useful. In fact, it returns
immediately when it sees the empty/null parameters. I only care that it *can*
be invoked.

/// <summary>
/// Return a value indicating whether the .NET Framework 3.0 is installed on
the current system. This is determined
/// by invoking a method in the GalleryServerPro.Business.Wpf assembly. This
assembly has a reference to
/// PresentationCore.dll and WindowsBase.dll, both .NET 3.0 assemblies. If
the method throws a TargetInvocationException,
/// we'll assume the framework is not installed.
/// </summary>
/// <returns>Returns true if .NET Framework 3.0 is installed; otherwise
returns false.</returns>
/// <remarks>The technique used here is fairly fragile. Any exception thrown
by the invoked method is received as a
/// TargetInvocationException, even if .NET 3.0 is installed. However, this
was perceived to be the best available
/// technique.
/// </remarks>
private bool DetermineIfDotNet3IsInstalled()
{
bool isDotNet3Installed = false;

System.Reflection.Assembly assembly =
System.Reflection.Assembly.Load("GalleryServerPro.Business.Wpf");

// Get reference to static WpfMetadataExtractor.AddWpfBitmapMetadata()
method.
Type[] parmTypes = new Type[2];
parmTypes[0] = typeof(string);
parmTypes[1] =
typeof(GalleryServerPro.Business.Interfaces.IGalleryObjectMetadataItemCollection);
Type metadataExtractor =
assembly.GetType("TIS.GSP.Business.Wpf.WpfMetadataExtractor");
System.Reflection.MethodInfo addMetadataMethod =
metadataExtractor.GetMethod("AddWpfBitmapMetadata", parmTypes);

// Prepare parameters to pass to
WpfMetadataExtractor.AddWpfBitmapMetadata() method.
object[] parameters = new object[2];
parameters[0] = String.Empty;
parameters[1] = null;

try
{
addMetadataMethod.Invoke(null, parameters);
isDotNet3Installed = true;
}
catch (System.Reflection.TargetInvocationException ex)
{
GalleryServerPro.ErrorHandler.AppErrorHandler.RecordErrorInfo(ex,
System.Diagnostics.EventLogEntryType.Information);
}

return isDotNet3Installed;
}

I tested this and it works as expected, including in Medium Trust. If you
think this solution is more complicated than needed, let me know. I'm not
thrilled about having to add a new project. I could have invoked ALL my logic
through reflection and not needed a new project, but this was a lot faster.

Cheers, and thanks, Walter!
Roger Martin
Tech Info Systems / www.techinfosystems.com
Gallery Server Pro / www.galleryserverpro.com
 
W

Walter Wang [MSFT]

Hi Roger,

Previously my assumption is to move the code that're using 3.0 to a
separate assembly and the main web application doesn't need to reference
3.0 but it references the assembly directly. (Though when you add the
reference or compile the web application, it seems Visual Studio will try
to add those 3.0 assemblies' references into web.config, but removing them
are fine for the compiling). Sorry I didn't describe this more clearly.

I think your approach will work fine, as long as the CAS policy for the
"Medium" level grants the code to use reflection. Remember this policy can
be customized by administrator to include or remove certain permission set;
though the policy may still named as "Medium", it might not have the exact
required permissions by your application.

Based on my test, the default "Medium" policy will allow my code to use
Assembly.Load, but not assembly.GetType and other reflection operations.
Therefore, you may need to check with your web hosting environment to see
if they're using the required permissions in the CAS policy.

For more information, please refer to following MSDN library:

#How To: Use Medium Trust in ASP.NET 2.0
http://msdn2.microsoft.com/en-us/library/ms998341.aspx


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I tried your suggestion to add a reference to my new assembly instead of
using reflection. It works, but there is a big annoyance in VS 2008 beta 2.
Every time I compile I get the following popup:

"You are attempting to add a reference to a project which is targeting .NET
Framework 3.0. The current target framework for your project is .NET
Framework 2.0. For this reference to work correctly, you may need to update
the target framework version to .NET Framework 3.0 using the property page
for your project. Do you want to add this project reference?"

Of course I answer No. I can't stand to deal with this every time I build,
so I'd like to revert to my reflection approach, but your statement that
GetType() is not available in medium trust alarmed me.

However, in my case I am successfully using assembly.GetType where
web.config has:

<trust level="Medium"/>

Based on my research it seems that GetType() will fail if accessing a
non-public type, but that it should work for public types. Since that is what
I am doing, I think I am safe.

If you have information to the contrary, please let me know.

Cheers,
Roger
 
W

Walter Wang [MSFT]

Hi Roger,

Based on my test, if you call GetType on an assembly that is strong named,
it will succeed even in Medium trust leve. This is what you've observed
that "work for public types". Previously my test code hasn't signed that
assembly (which is using .NET 3.0).

For the VS2008 Beta 2 issue, I've also performed a test locally: based on
my findings, VS will only issue the warning when you add the reference, not
at every time when you build the project. In my test, I have a class
library that targets 3.0, a console application targets 2.0; then the
console app references the class library.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Walter Wang [MSFT]

Hi Roger,

I'm writing to check the status of this post and also summarize it since
it's rather long.

First, I must say such requirement is not common, therefore we don't have
some "official" or documented way to do this. However, since .NET 3.0 is
actually a very special version of .NET Framework (it's built upon .NET 2.0
instead of a brand new runtime, if it were a new runtime, you will not be
able to load some core assemblies from different runtime versions. For
example, you cannot load an assembly built with .NET 2.0 in a .NET 1.1
application).

We usually can use registry to check if .NET 3.0 is installed or not. Since
your requirement is also to make it work in Medium trust level, we also
need to watch out some restrictions such as no registry checking, no
reflection, etc.

To summarize, there're two approaches:

1) Use a separate assembly to use .NET 3.0, you can directly use the class
(which is using .NET 3.0); but this approach will require you manually
remove those .NET 3.0 assemblies' references from web.config since VS IDE
will add them for you whenever you build the web site.

2) Still use a separate assembly to use .NET 3.0 but do not use direct
reference to it, instead, you use reflection on it; this approach will
require your assembly being strong named.


Please let me know if you need further information on this.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

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

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top