Storing assembly Version readonly - c#

this is a follow on from this question I asked a while ago:
Assembly.GetExecutingAssembly() performance
this solution seemed perfect. Now I've just gottent around to implementing it and it doesn't work. I get a System.TypeInitializationException thrown, the inner exception is the good old, Object reference not set to an instance of an object. Now I'm not sure why it's not working. My guess is that the static readonly property is instanticating before the Assembly class or something?
Can anybody shed any light on why this is happening, any fixes, other than not use a readonly as this is obvious, would also be welcome though not necessarily expected!
Here's the code:
public class VersionHelper
{
private static readonly Version _applicationVersion = Assembly.GetEntryAssembly().GetName().Version;
public static string GetVersionText()
{
return string.Format("Version: {0}-{1}", _applicationVersion, Environment.MachineName.Substring(5));
}
}
Called:
protected void Page_Load(object sender, EventArgs e)
{
lblVersion.Text = VersionHelper.GetVersionText();
}
Just to explain if I do it this way it works:
public class VersionHelper
{
public static string GetVersionText()
{
Assembly web = Assembly.GetExecutingAssembly();
AssemblyName webName = web.GetName();
return string.Format("Version: {0}-{1}", webName.Version, Environment.MachineName.Substring(5));
}
}

The exception doesn't have anything to do with the fact that the property is readonly or not. The problem is that you are calling Assembly.GetEntryAssembly() in a ASP.NET context, and apparently that doesn't work well together.
The other option that you have also does not use this method, it uses Assembly.GetExecutingAssembly. If you change your first sample so it uses Assembly.GetExecutingAssembly, than you will see that it runs fine.
I do not have any real references, but you can check this question, and in particular the comments beneath the question.
It also has a solution on how to get an entry assembly in a ASP.NET context.

Assembly.GetEntryAssembly is not reliable, specifically it will return NULLif the application started in an unmanaged context instead of a managed context. The result must be null checked..
For example, if an unmanaged application creates an instance of a COM component written in C#, a call to the GetEntryAssembly method from the C# component returns NULL, because the entry point for the process was unmanaged code rather than a managed assembly.
whereas GetExecutingAssembly just gets the assembly that contains the code that is currently executing.
while To get the assembly that contains the method that called the currently executing code, you should use GetCallingAssembly.

Related

MethodAccessException on Task.CompletedTask property

I am working on a small wpf application and one of the users is getting the following exception:
System.MethodAccessException:
Attempt by method "xxx.HttpConfirmation.Invoke()" to access method "System.Threading.Tasks.Task.get_CompletedTask()" failed.
at xxx.HttpConfirmation.Invoke()
at xxx.RequestPipeline.<ProcessQueuedRequests>d__11.MoveNext()
According to MSDN documentation, such exception is thrown in the following situations:
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.
Task.get_CompletedTask() is public since its introduction and I am also not using reflection to access the property.
I also don't think that there is a problem with code security/transparency since only one user is having this issue.
The exception is thrown at the Task.CompletedTask line:
public class HttpConfirmation
{
public static Task Invoke()
{
using (var client = new WebClient())
{
try
{
// Send the request and don't wait for the response.
client.UploadStringTaskAsync("http://sampleUrl.com", string.Empty);
}
catch
{
// ignore
}
}
return Task.CompletedTask;
}
}
Any ideas on what may cause the exception?
The problem was that the customer had .NET 4.5.2 installed and the program targeted .NET 4.6.
Though I still have no clue as to why exactly System.MethodAccessException was thrown as none of the 3 documented situations for throwing this exception did happen.

Conditionally call a private method based on caller's debug configuration

My current code situation is that I have in assembly A the following code:
public class Foo
{
public Foo()
{
CreateDebugMessage();
}
[Conditional("DEBUG")]
[DebuggerStepThrough]
private void CreateDebugMessage()
{
AddMessageType(MessageType.Debug, "Debug",
"/Company.App.Class;component/Images/image.png", Brushes.Green, false);
}
}
Some extra information is that I am using MEF and this method is called from the constructor. I have an assembly B (where I am importing assembly A) which depending on whether I am on DEBUG or RELEASE mode I want the Debug message to be created when I instantiate the class:
var foo = new Foo();
If I am on Debug mode I want the debug message to be created.
If I am on Release mode I DO NOT want the debug message to be created.
I thought the Conditional attribute would be better than the #iF DEBUG statement. This question showed me how WRONG I was! Since on runtime the method is never reached.
At this point I understand that the "#iF Debug" and "[Conditional("DEBUG")]" statements won't cut it for what I want to achieve.
Therefore my question is, how to make this scenario work?
The attribute works as it should, see Conditional Compilation in Referenced Assemblies. The attribute depends on the compilation symbols of the calling assembly. I tested and confirmed this: a method in an assembly with [Conditional("DEBUG")], compiled on Release, will only get called if the calling assembly is compiled in Debug. If this isn't the case for you, your code does not match your description.
The relevant part in your question is of course "This method is called from the constructor.". The attribute works for the direct caller, which in your case is the constructor of the containing class, which is Release.
You'll have to make it public and explicitly call the method:
public class Foo
{
public Foo()
{
}
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void CreateDebugMessage()
{
AddMessageType(MessageType.Debug, "Debug",
"/Company.App.Class;component/Images/image.png", Brushes.Green, false);
}
}
var foo = new Foo();
foo.CreateDebugMessage();

How do I add support for typed calls to a remote COM+ application

I am in the process of replacing a COM+ hosted application with a .Net variant.
The steps I took are roughly:
Generate an Interop assembly of the old dll
Create a new class in C# .Net that derives from ServicedComponent and implements the IMyClass interface from the interop.
I have annotated the class with a [Guid("...")] and a [ProgId("...")] attribute to match the class in the old dll
The end result looks like this:
[ProgId("MyComponent")]
[Guid("...")]
public class MyClass : ServicedComponent, IMyClass
{
public MyClass()
{
}
public object Open(string arg1, string arg2)
{
/* trace arguments*/
}
public object Run()
{
/* implementation here */
}
public void Close()
{
return;
}
}
This assembly is installed on a remote machine using regsvcs.exe
Now most clients use code similar to this unittest code:
Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
dynamic comInstance = Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();
This works perfectly, the .Net tracing on the remote machine tells me everything is working as it should. Other clients use code similar to this:
Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
MyClass comInstance = (MyClass)Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();
The first line is the same and seems to work fine, the rest acts weird. The VS debugger shows the lines are being executed. The remoteMachine shows that no methods are being executed.
The last call to Close(), which actually just returns, throws an exception:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Result StackTrace:
at Interop.MyComponent.IMyClass.Close()
at UnitTestProject1.UnitTest1.temp()
What have I missed in my implementation to support this last (typed) scenario?
This sounds like mismatched metadata, e.g. marshaling is different between the one that happens with the original type library and the one that happens with your server registered .NET assembly.
My guess is that the untyped case runs well because it depends solely on IDispatch, which .NET implements quite well, but the typed test fails (and I'm surprised it doesn't fail earlier) because of this mismatch.

Weird Access Violation Exception

I'm puzzled with an occurance of AccessViolationException. It's quite impossible (see answer) to have a clean reproduction but here goes the general idea:
class MyClass
{
public List<SomeType> MyMethod(List<string> arg)
{
// BREAKPOINT here
// Simple stuff here, nothing fancy, no external libs used
}
}
delegate List<SomeType> MyDelegate(List<string> arg);
...
var myObject = new MyClass();
Func<List<string>, List<SomeType>> myFunc = myObject.MyMethod;
MyDelegate myDelegate = myObject.MyMethod;
myFunc(null) // works fine
myDelegate(null) // works fine
myObject.MyMethod(null) // throws AccessViolationException
The weird part is I'm not using any unsafe code. I don't have any dependencies on external libraries anywhere close (and anywhere in the whole program execution AFAIK).
The weirdest part is this is 100% reproducable and even after refactoring the code slightly, moving the method invocation elsewhere, putting extra code before it etc. - in all cases AccessViolationException is still thrown on that particular method invocation. The method is never entered when invoked directly (breakpoint is not hit). Invoking it through delegate or Func<> works fine.
Any clues as to what could cause it or how to debug it?
UPDATE
Following antiduh's question: There is no call to a virtual method from a constructor anywhere close. The actual stack trace when this happens is very simple, just two static methods and a simple instance one.
The only clue seems to be threading. There is Parallel.ForEach() and Thread.Sleep() invoked before this in program execution (not in call stack). Any clues as to how mishandled threading (with regular, managed classes) could cause AVE?
UPDATE
Narrowed it down to a VS bug, see my answer.
This seems to be a VS bug. Have a look at this full solution. Code is simple:
using System;
using System.Collections.Generic;
namespace Foo
{
public class MyClass
{
public virtual object Foo(object o1, object o2, object o3, object o4)
{
return new object();
}
}
public sealed class Program
{
public static void Main(string[] args)
{
var myClass = new MyClass();
object x = new object();
myClass.Foo(null, null, null, new object()); // put a breakpoint here and once it stops, step over (F10) - AccessViolationException should be thrown in VS
}
}
}
The important fact I have missed before is that the code actually works fine when ran normally. Only when that particular line is being stepped over in VS (F10), the Access Violation occurs and it actually occurs in VS hosting process (even though the final stack frame is my code). It's possible to continue execution fine.
The issue happens for me on VS 2013, version 12.0.21005.1 REL. It also happens on 3 other machines I tested this on.
UPDATE
Installing .NET Framework 4.5.2 solves this.

Ninject ActivationException: Error activating IAlertManagement

I'm getting the following error:
Test method: BootStrapperTest.Can_Create_Alert_Management_Object threw exception: Ninject.ActivationException:
Error activating IAlertManagement No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for IAlertManagement
Suggestions:
1) Ensure that you have defined a binding for IAlertManagement.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Here is the test case that is causing this exception:
[TestInitialize]
public void Initialize()
{
BootStrapper.RegisterTypes();
}
[TestMethod]
public void Can_Create_Alert_Management_Object()
{
IAlertManagement alertManagementService = BootStrapper.Kernel.Get<IAlertManagement>();
Assert.IsNotNull(alertManagementService);
}
//This is the code that gets called in [TestInitialize]
public static void RegisterTypes()
{
if (!initialized)
{
Kernel.Bind(scanner => scanner.FromAssembliesMatching("MyCompany.MyProduct.*")
.SelectAllClasses()
.BindDefaultInterface());
Kernel.Unbind(typeof(IWcfServiceClient<>));
Kernel.Bind(typeof(IWcfServiceClient<>)).ToMethod(ctx =>
(ctx.Kernel.Get(typeof(WcfServiceClientProvider<>).MakeGenericType(ctx.GenericArguments)) as IProvider).Create(ctx));
}
initialized = true;
}
The above error is occurring in one of my unit tests on our build server but not on my development machine. I have 7 other tests almost identical to this one that pass on the build server and on my development machine but this is the only test that fails.
The IAlertManagement interface is coming from a dll called Core and the concrete type is coming from another dll called AlertManagement. I have both the Core dll and the AlertManagement dll included in my unit test project as project references. I have 7 or 8 other tests identical to this situation but this is the only one failing.
Any ideas would be appreciative.
The error occur because IAlertManagement is not binded with any concrete class.
Try to manually bind IAlertManagement.
public static void RegisterTypes()
{
if (!initialized)
{
Kernel.Bind(scanner => scanner.FromAssembliesMatching("MyCompany.MyProduct.*")
.SelectAllClasses()
.BindDefaultInterface());
//Try to add following line
Kernel.Bind<IAlertManagement>().To<ConcreteImplementationOfIAlertManagement>();
Kernel.Unbind(typeof(IWcfServiceClient<>));
Kernel.Bind(typeof(IWcfServiceClient<>)).ToMethod(ctx => (ctx.Kernel.Get(typeof(WcfServiceClientProvider<>).MakeGenericType(ctx.GenericArguments)) as IProvider).Create(ctx));
}
initialized = true;
}
I ended up resolving this by adding concrete references to the resolving types in my unit testing project. Just adding project references is not enough. This is how I'm doing this:
[TestClass]
public class AssemblyInitialize
{
/// <summary>
/// Method which gets executed once per unit test session. The purpose of this method is to reference any loosely coupled
/// assemblies so that they get included in the unit test session. If no code actually references a given assembly, even if its
/// technically a project reference, it will not be copied to the test output folder.
/// </summary>
[AssemblyInitialize]
public static void InitializeReferencedAssemblies(TestContext context)
{
List<Type> looselyCoupledTypes = new List<Type>
{
typeof(AlertManagement),
typeof(Naming),
};
looselyCoupledTypes.ForEach(x => Console.WriteLine("Including loosely coupled assembly: {0}",
x.Assembly.FullName));
}
}
The first thing that I would check is to ensure that the DLL that contains the implementation of IAlertManagement is getting copied to the proper directory on the build server so that the tests see it.
Another thing to try would be to move the kernel loading code to a ClassInitialize function instead of a TestInitialize, just to see if there is some sort of race condition or other related thing. I've seen random errors on build servers due to objects being disposed in a different order or sooner than would normally happen (involved Rx, TPL, and unobserved exceptions in my case). It may be that more tests are run in parallel on the build server than on the desktop.
Or it could be due partially to the fact that the server may be using Server GC. I don't know if forcing it to use Workstation GC would help or not but it might be worth a try.

Categories