I have developed a Library for internal email reporting. When I am using that Library from another project (By Adding Reference).
It gives NullReferenceException on the following line.
System.Reflection.Assembly.GetEntryAssembly().GetName().Name
Any idea, why Assembly is null?
This is expected especially in the Windows Services where they are loaded by an unmanaged runtime.
Use:
Process.GetCurrentProcess().MainModule.FileName
To get unmanaged entry point file.
Update
It seems you are looking for this:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
problem is solved guys,
I am using
Assembly.GetAssembly(ex.TargetSite.DeclaringType.UnderlyingSystemType).GetName().Name
to get the EntryAssemblyName.
In this case I already has parameter which is taking Exception 'ex', so I solved it by using that.
Many Thanks Guys, specially #Aliostad
Cheers
Answering both the OP's and #Neeraj 's questions: sometimes it can also be useful to get the root of your assembly with Assembly.GetExecutingAssembly().Location (e.g. when the Resharper test runner is making your life hard when using GetEntryAssembly())
string rootDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string someFile = Path.Combine(
rootDir ?? throw new InvalidOperationException(),
"Foo",
"Bar.txt");
Related
I'm trying to extract the version number from a AssemblyInfo.cs file!
And I'm trying to use System.Reflection.Assembly.LoadFile(path); But while doing this I get a BadImageFormatException; "The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)". So now I wounder, is that not a possible way to go about it? And should I use RegEx instead?
I have read many examples with GetExecutingAssembly() but I do want to get the version from an other project.
Clarification: I want to read the version info from the AssemblyInfo.cs file! And not from a compiled file. I'm trying to make a tool to update my version numbers before I make a new release.
You can get Assembly version without loading it as:
using System.Reflection;
using System.IO;
...
// Get assembly
AssemblyName currentAssembly = AssemblyName.GetAssemblyName(path);
Version assemblyVersion = currentAssembly.Version;
Edit:
If you want to read file then you can do it like this:
string path = #"d:\AssemblyInfo.cs";
if (File.Exists(path))
{
// Open the file to read from.
string[] readText = File.ReadAllLines(path);
var versionInfoLines = readText.Where(t => t.Contains("[assembly: AssemblyVersion"));
foreach (string item in versionInfoLines)
{
string version = item.Substring(item.IndexOf('(') + 2, item.LastIndexOf(')') - item.IndexOf('(') - 3);
//Console.WriteLine(Regex.Replace(version, #"\P{S}", string.Empty));
Console.WriteLine(version);
}
}
//Output
1.0.*
1.0.0.0
Hope this help...
You can specify the target assembly path in AssemblyName.GetAssemblyName
AssemblyName.GetAssemblyName("ProjectB.exe").Version
AssemblyInfo.cs file gets compiled to IL assembly.
If you load that assembly you can read the version with all the examples that you have already seen. Which is reading an embedded version information from a compiled assembly file, and it may be overwritten by compilation process to a value different from what is in AssemblyInfo.cs
However it sounds like what you want instead is to read a version number from AssemblyInfo.cs text file, without compiling it down.
If this is the case you really just have to use regex with a format appropriate for your project, or even come up with a convention that will keep it simple.
This could be as simple as
var versionMatch = Regex.Match(File.ReadAllText(filename), #"AssemblyVersion\s*\(\s*""([0-9\.\*]*?)""\s*\)");
if (versionMatch.Success)
{
Console.WriteLine(versionMatch.Groups[1].Value);
}
You would have to consider convention around what goes there, since 1.0.* is a valid version string that translates to timestamp values of form 1.0.nnn.mmm at compile time, and nnn and mmm part closely guessable but not precisely guessable.
It sounds like you're trying to load an assembly compiled for x86 in an x64 environment or vice-versa.
Ensure the assembly this code resides in is built for the same environment as the target and you can get it with the examples it sounds like you've read.
You can proceed with Assembly.GetName().Version where your assembly could be the type of your class
public class Test
{
public static void Main()
{
Console.WriteLine("Current assembly : " + typeof(Test).Assembly.GetName().Version);
}
}
For the test application I have working on, shows me below details using above code:
One of my classes, to execute some instructions needs to know its location (as an absolute path). I was using a naive Directory.GetCurrentDirectory(), until I noticed that things get messed up when the user is actually not executing from the directory where the class is sitting.
How can I get that ? So far my googling is unfructuous... :(
PS : I intend to release this class as a DLL, no COM or anything fancy, just a basic DLL. Will that change any rule?
You can use:
string path = GetType().Assembly.GetModules(false)[0].FullyQualifiedName;
(Assuming you only have one module, which is likely.)
string path = typeof(YourClass).Assembly.Location;
string directory = Path.GetDirectoryName(path);
Should do it.
You can use:
System.Reflection.Assembly.GetExecutingAssembly().Location
Get it from Assembly
Assembly.GetExecutingAssembly().Location
I am using System.Web.Helpers.Json to deserialize some JSON into dynamic in NET 4. The following line fails with this error: TypeInitializationException: Attempt by method 'System.Web.Helpers.Json..cctor()' to access method 'System.Web.Helpers.Json.CreateSerializer()' failed.
var json = Json.Decode(response);
The response is lengthy but valid JSON. What could be the matter here? I have tried LINQPad with a short handcrafted JSON and it worked. Is this a configuration issue of some sort?
[EDIT]
Here is the actual sample JSON. It appears the content is pretty much irrelevant. When this is run in a brand new Console application or LINQPad, it works as expected. But if you try to run the same code from a brand new Windows Forms application, it barfs with the above error.
var json = Json.Decode("{\"r\":{\"0\":{\"id\":\"2\"},\"1\":{\"id\":\"33\"}}}");
[EDIT2]
Actually, it turns out this has nothing to do with project types. The exception is thrown if the project is being debugged. If it is simply run, the exception does not occur. Strange, eh?
I forgot about this question and I found my answer in the meantime. I think it was somewhere on Microsoft's Connect site but I am not sure. So let's share it now.
Basically, in order to workaround this problem you need to make sure "Enable the Visual Studio hosting process" is unchecked in your project's settings under Debug. I am not sure why it's happening but this is definitely a way to "fix" it. I stopped searching for answers once I found out about this. It was good enough for me.
This can also happen if you are running in a partial trust.
Check the exception description here for possible reasons.
I don't know if this will apply to you, since you are not running in a web context, but this is what that link describes:
This exception is thrown in situations such as the following:
A private, protected, or internal method that would not be accessible from normal compiled code is accessed from partially
trusted code by using reflection.
A security-critical method is accessed from transparent code.
The access level of a method in a class library has changed, and one or more assemblies that reference the library have not been
recompiled.
There is problem in the inbuilt json class.
If you want to achieve this in alternate way, please use the below code:
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new DynamicJavaScriptConverter[] { new DynamicJavaScriptConverter() });
var result = WrapObject(serializer.DeserializeObject(value)); // here you will have result.
private object WrapObject(object value)
{
IDictionary<string, object> values = value as IDictionary<string, object>;
if (values != null)
{
return new DynamicJsonObject(values);
}
object[] arrayValues = value as object[];
if (arrayValues != null)
{
return new DynamicJsonArray(arrayValues);
}
return value;
}
Further to Roland's answer: some assembly mismatches listed can be fixed in the AssemblyInfo.cs file.
The offending line in my AssemblyInfo was this:
[assembly: AllowPartiallyTrustedCallers]
Removing this allowed me to access the public property (on a public class) that I was trying to set from another assembly that had dynamically loaded this assembly.
I have to create an application to read the name of all DLLs (assemblies) in my application path along with its version. And also to read the same of all the dll in the sub folders.
How to do this in C#. Can any one help me with sample code?
EDIT : how to read details of Legacy dlls( External dlls- not created in .NET)
Thanks in advance.
You should search through your given root directory by calling Directory.GetFiles(). You can run through the result and load every assembly by calling Assembly.ReflectionOnlyLoadFrom() (cause if you load it that way it won't be added to the AppDomain, thous no unload is needed).
With these Assembly classes you can access the GetName() function and take a look into the Version property to get the version information.
Other properties, that are not easily to get, can be reached through the GetCustomAttribute() function like this:
((AssemblyCopyrightAttribute)assembly.GetCustomAttribute(typeof(AssemblyCopyrightAttribute), true).Copyright
With these informations you should be able to built up the list you like.
Update:
And here's the obligatory linq code sample:
var rootPath = #"C:\MyRoot\Folder";
var query = Directory.GetFiles(rootPath, "*.dll", SearchOption.AllDirectories)
.Select(fileName =>
{
try
{
return Assembly.ReflectionOnlyLoadFrom(fileName);
}
catch
{
return null;
}
})
.Where(assembly => assembly != null)
.Select(assembly => new
{
Version = assembly.GetName().Version.ToString(),
Name = assembly.GetName().Name
});
foreach (var infos in query)
{
Console.WriteLine(infos.Name + " " + infos.Version);
}
Update 2:
So to get it from normal DLLs you should take a look into this question.
I'm a bit confused on what you actually want, but check the Assembly class: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.aspx
Use Assembly.Load. There is one problem, you can't unload it, so if you do it too much times your memory will be filled by garbage.
If you call AssemblyName.GetAssemblyName, the assembly doesn't get loaded into your appdomain.
To include subfolders, you'll likely need to write a recursive function. Directory.GetDirectories or DirectoryInfo.GetDirectories can be used to retrieve all subfolders.
Use Assembly.GetName() to get an object, where you can extract the assembly version, as one part of an assemblies name is its version.
As already mentioned above, an assembly loaded with Assembly.Load cannot be unloaded and therefore remains in memory. You can however create a separate AppDomain, which you can unload again. Data transfer between AppDomains is possible by passing serializable objects, which is no problem for you because you just want to pass a string.
If you actually want to load the assemblies in the context of an extendable application, have a look at MEF.
Best Regards,
Oliver Hanappi
Use Assembly.ReflectionOnlyLoadFrom if you don't need to execute any code from that assembly and you want only gather some info about members contained inside.
Is there a way to find out the assembly name at design-time (i.e. not using reflection or runtime APIs such as System.Reflection.Assembly.GetEntryAssembly) from within Visual Studio?
The scenario requires a tool to get the assembly name that a Visual Studio project will eventually compile into.
This is like parsing the AssemblyName property of the .csproj - I am wondering if there are any APIs that can give this information reliably.
Please do not respond back with runtime APIs that use reflection - there is no assembly file present at the time I need the assembly name - just the metadata of the assembly in the csproj file.
if you are calling the tool via a post/pre-build event, this data is very easy to access.
Just go to the "project properties->Build Events" tab, then select either "edit pre-build" or "edit post-build", depending on when you want the tool to run. This should bring up an edit window with the ever helpful "Macros >>" button. Press this and you will be given a heap of macros to use and should be pretty much everything you need.
The "API" you could use is LINQ to XML after all the .csproj file is just xml. (and you can get the location of the .csproj file if you need from the solution file which for some reason is not XML but can be easily parsed)
You can use "TargetName" available in Macros for Post-build events. It will give you the assembly name for your project.
After a quick run through MSDN I found this article which might be a good start for some further research:
Accessing Project Type Specific Project, Project Item, and Configuration Properties
I think you will need to write some regular expression that will give you the value of "AssemblyTitle" attribute in AssemblyInfo.cs file.
Something like this:
public class Assembly
{
public static string GetTitle (string fileFullName) {
var contents = File.ReadAllText (fileFullName); //may raise exception if file doesn't exist
//regex string is: AssemblyTitle\x20*\(\x20*"(?<Title>.*)"\x20*\)
//loading from settings because it is annoying to type it in editor
var reg = new Regex (Settings.Default.Expression);
var match = reg.Match (contents);
var titleGroup = match.Groups["Title"];
return (match.Success && titleGroup.Success) ? titleGroup.Value : String.Empty;
}
}