I have encountered a strange error that is unexplainable to me.
I have a .NET 6 class library project (A) that has the function:
public async Task ImportDeliveries()
{
try
{
var csvFileProcessor = new CsvFileProcessor();
await csvFileProcessor.ProcessAllAsync(_DeliveryImporter.ImportAsync).ConfigureAwait(true);
}
catch (Exception ex)
{
_TelemetryClient.TrackException(ex);
}
}
It works fine. However, as soon as I add the project reference of another .NET 6 class library (B) to the project, without changing anything else, the function
await csvFileProcessor.ProcessAllAsync(_DeliveryImporter.ImportAsync).ConfigureAwait(true);
fails and throws the following exception:
System.MissingMethodException: 'Method not found: 'System.Threading.Tasks.Task BlobStorageHelper.BlobStorageFolder.MoveAsync(Microsoft.Azure.Storage.Blob.CloudBlockBlob, BlobStorageHelper.BlobStorageFolder)'.'
Can this be caused because (B) contains certain nuget packages?
This behavior is very counterintuitive to me, and I'm not sure where to start looking.
This is probably caused by:
Your project, A, referencing a class library C, in which CsvFileProcessor and BlobStorageHelper.BlobStorageFolder are defined (the latter could also be in a transitive dependency, D).
Project B also references class library C (and/or D), but a different version.
Someone modified, added or removed System.Threading.Tasks.Task BlobStorageHelper.BlobStorageFolder.MoveAsync(Microsoft.Azure.Storage.Blob.CloudBlockBlob, BlobStorageHelper.BlobStorageFolder) in some version of C or D.
You're not properly implementing Semantic Versioning within C or D, so MSBuild is restoring a version of C or D that doesn't contain the required method.
Hence the error.
Takeaway: changing a signature or return type is breaking the ABI (application binary interface), requiring a major version update.
To fix this, you could revert the signature or return type change, and add an overload instead.
Related
I am trying to refactor a code base. This requires moving types to different assemblies to fix some dependency issues. I want to avoid requiring my customers to recompile as a result of these changes. I've noticed that interfaces that are explicitly implemented and declare events do not forward correctly. For example:
Foo.dll defines:
public interface IFooInterface
{
void Foo();
event EventHandler FooEvent;
}
My customer's FooProgram.exe depends on Foo.dll and defines:
public class Foo : IFooInterface
{
event EventHandler IFooInterface.FooEvent
{
add { }
remove { }
}
void IFooInterface.Foo() { }
}
Now I move the type. I create a new assembly NewFoo.dll. I move IFooInterface from the old assembly to the new assembly and put it under the same namespace. Foo.csproj takes a project reference to NewFoo.csproj and I add the forwarding attribute:
[assembly: TypeForwardedTo(typeof(IFooInterface))]
I place Foo.dll and NewFoo.dll in the bin directory for Foo.exe and Foo.exe errors with:
Unhandled Exception: System.TypeLoadException: Method 'add_FooEvent' in type 'FooProgram.Foo' from assembly 'FooProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
at FooProgram.Program.Main(String[] args)
Why does this happen? If I implicitly implement the interface on Foo it works, but that doesn't do me any good as it means anyone who wrote vb.net code against my library will break. What other constructs have this problem with Type Fowrarding? Is there a way to get the behavior I want?
It looks like this is a bug in the old version of .NET Framework we're using (4.5). I upgraded to 4.8 and it works as expected. I found this blog post by Rick Strahl that describes how TypeForwardTo is what makes .NET Standard capable of resolving to the correct targets. This made me realize it must work for all types on a more modern version of the framework.
So today I faced interesting problem while trying to build our company solution and I wanted to ask you guys do you know why is this happening. I've been told that it might be from my machine/visual studio because other people did not have same problem.
So we have a method in project A:
private static string RpcRoutingKeyNamingConvention(Type messageType, ITypeNameSerializer typeNameSerializer)
{
string queueName = typeNameSerializer.Serialize(messageType);
return messageType.GetAttribute<GlobalRPCRequest>() != null || AvailabilityZone == null
? queueName
: queueName + "_" + AvailabilityZone;
}
where GetAttribute<GlobalRPCRequest>() is defined in public static class ReflectionHelpers
public static TAttribute GetAttribute<TAttribute>(this Type type) where TAttribute : Attribute;
then we have project B which have method:
public static string GetAttribute(this XElement node, string name)
{
var xa = node.Attribute(name);
return xa != null ? xa.Value : "";
}
I have to point out that we have reference to project B in project A.
Now what happens is that when I try to build I get compile error:
Error 966 The type 'System.Xml.Linq.XElement' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. D:\Repositories\website\website\submodules\core\src\A\Extensions\Extensions.cs 37 13 A
Whats happening is that compiler thinks that I am actually using GetAttribute method from project B(in my opinion!). Why this is happening? Since when I try to navigate to GetAttribute VS leads me to the right method (the one that is in ReflectionHelpers).
Could it be because of the reflection? NOTE: I fixed this issue by calling the method statically or adding reference to System.Xml.Linq in my project A, but I am curious of the strange behavior of VS/syntax-checking feature.
It's a guess, but I think your function:
private static string RpcRoutingKeyNamingConvention(Type messageType, ITypeNameSerializer typeNameSerializer) does not match your helper method signature because you try returning a string:
public static TAttribute GetAttribute<TAttribute>(this Type type) where TAttribute : Attribute; which expects a TAttribute return type.
Maybe, you can try modifiying your function RpcRoutingKeyNamingConvention to return GlobalRPCRequest and check if the compiler continues to go crazy.
Visual Studio gets confused all the times! I tried to reproduce the scenario in my VS 2015 (.NET 4.6) and it compiles just fine. I didn't have to add reference to System.Xml.Linq in my Project A.
My guess is that it might be a cache issue. You might want to try this:
Remove reference to Project B
Clean then rebuild both solutions
Add the reference back
Rebuild and voila!! Well.. hopefully
Hope it helps, let me know :)
I guess that's going on:
- B has reference to System.Xml.Linq
- B is built without a problem.
- You are referencing B in A
- A hasn't got a reference to System.Xml.Linq
- A seem to consume the function defined in B
- When you try to build project A, it produces that error
Am I right?
If that's the case, it is totally normal. Because a project which consumes a reference (A) must have a reference to what is referenced (System.Xml.Linq) by what it references (B).
Think like this: When you try to add a nuget package to your project if it has a dependency, nuget will install it too. Why? Because of this situation.
This is completely normal if I understand your answer correctly.
Recently in my WinForm project, I installed MiniProfiler.Windows and write following decorator for my QueryHandlers(I'm using CQRS):
public class MiniProfilerQueryHandlerDecorator<TQuery,TResult>:IQueryHandler<TQuery,TResult> where TQuery : IQueryParameter<TResult>
{
private readonly IQueryHandler<TQuery, TResult> _decoratee;
public MiniProfilerQueryHandlerDecorator(IQueryHandler<TQuery, TResult> decoratee)
{
_decoratee = decoratee;
}
public TResult Handle(TQuery request)
{
TResult result;
using (StackExchange.Profiling.MiniProfiler.Current.Step("Call QueryHandler"))
{
result =_decoratee.Handle(request); //call some Linq to entity queries
}
var friendlyString = ConsoleProfiling.StopAndGetConsoleFriendlyOutputStringWithSqlTimings();
Debug.WriteLine(friendlyString);
return result;
}
}
I get following error at var friendlyString=ConsoleProfiling.StopAndGetConsoleFriendlyOutputStringWithSqlTimings()
line.
An unhandled exception of type 'System.MissingMethodException' occurred in IASCo.Application.Core.dll
Additional information: Method not found: 'Boolean StackExchange.Profiling.MiniProfiler.get_HasSqlTimings()'.
Does anyone know where is the problem?
MissingMethodException = an attempt is made to dynamically access a deleted or renamed method of an assembly that is not referenced by its strong name (msdn).
Or as this answer puts it:
This is a problem which can occur when there is an old version of a DLL still lingering somewhere around
I notice that the MiniProfiler.Windows library is using a very old (over 2 years) version of MiniProfiler. That version of the code did indeed have a MiniProfiler.HasSqlTimings property. However, the current version (3.0.11) no longer has this property.
I am guessing that you are using the code from the MiniProfiler.Windows library that you linked above, but instead of using the v2 MiniProfiler dll that they have saved in /packages, you are using a v3 MiniProfiler dll (maybe downloaded from nuget). This would explain the exception that you are getting.
If this is indeed the case, then you can solve this by either downloading the version 2.0.2 nuget (Install-Package MiniProfiler -Version 2.0.2) or by upgrading the code in ConsoleProfiling to be compatible with MiniProfiler v3.
My issue goes like this:
There is a project called myframework. It has some extension methods defined in it as follows:
namespace myframework
{
public static class Helpers
{
public static bool ContainsAll(this string obj, string[])
{
return true;
}
}
}
It also has some other stuff like interfaces, etc, etc.
There is a second class I generate via System.CodeDom classes. The generated output is somewhat like this:
using myframework;
public class A: IMyFrameworkInterface
{
public void foo()
{
string s ="HELLO";
if(s.ContainsAll(some_arr))
return;
}
//More methods defined...
}
The compiler options I pass which is created prior to the actual compile call references the correct assemblies
var cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("myframework.dll");
The code compilation modules are written in a different project. The particular class responsible for this also nicely gives us access to a list of CompilerError object via which we can learn the result of compilation.
Issue1: When I tried this in an asp.net project the compiler threw error saying it could not find metadata file myframework.dll (despite it being referenced in the project).
Issue2: When I tried it with a windows forms project. It gave a different error. This time saying that string does not contain definition for ContainsAll()
How to solve these two specific problems?
Found out the answer to this after a bit digging up. I was using .net framework 3.5. The codedom compiler apis targets v2.0 of the framework by default. Hence, you have to manually specify the correct framework:
var cp = new CompilerParameters(
new Dictionary<string,string>() { {"CompilerVersion", "v3.5"} });
For the compilation to work within an asp.net environment you'd have to actually point the references to the correct location. Hence you'd have to do something like follows:
cp.ReferencedAssemblies.Add(
HttpContext.Current.Server.MapPath(
"bin\\myframework.dll"));
My references:
http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
.Net 3.5 CodeDom Compiler generating odd errors
And comments in the question's post. :)
I've used a tutorial (http://support.microsoft.com/kb/837908, method 1) to generate two projects. Project a has a reference to project b.
project a:
new System.EnterpriseServices.Internal.Publish().GacRemove(string.Format(#"C:\Users\[me]\Documents\Visual Studio 2010\Projects\MyAssembly1\MyAssembly1\bin\Debug\MyAssembly1.dll"));
new System.EnterpriseServices.Internal.Publish().GacInstall(string.Format(#"C:\Users\[me]\Documents\Visual Studio 2010\Projects\MyAssembly1\MyAssembly1\bin\Debug\MyAssembly1.dll"));
MyAssembly1.Class1 obj1 = new MyAssembly1.Class1();
MessageBox.Show(obj1.HelloWorld());
project b:
public string HelloWorld()
{
return "1";
}
when I perform the following:
change "HelloWorld" method in project b to return "2" (instead of "1").
build project b
build project a and run it
I get message box with "1" as text, and the GAC doesn't always update itself.
What is the simplest way to update project b and see it on project a?
Firstly, changing the GAC is unlikely to help an already running process. In this specific case, note that JIT happens per-method before the method is executed. Which means MyAssembly1 is resolved and loaded before the remove/install step. However, that doesn't change the fact that this is very unlikely to be a good approach.