I am attempting to setup a custom attribute like the following:
[AttributeUsageAttribute(AttributeTargets.Method)]
public sealed class AuthorizationAttribute : Attribute
{
public AuthorizationAttribute(bool required)
{
Required = required;
}
public bool Required;
}
In my service contract interface, I have a method like such:
[OperationContract]
[Authorization(true)]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "randommethod")]
ReturnObject RandomMethod();
When I do the following I see it in the list, but but the 'is' comparison, fails:
foreach(object attribute in methodInfo.GetCustomAttributes(true)) // Returns all 3 of my attributes.
if (attribute is AuthorizationAttribute) //Does not pass
I have tried to do the following that returns false:
Attribute.IsDefined(methodInfo, typeof(AuthorizationAttribute));
attribute.GetType().IsAssignableFrom(typeof(AuthorizationAttribute));
I have also done the following 2 things that returns null:
AuthorizationAttribute authAttribute = attribute as AuthorizationAttribute;
Attribute attribute = Attribute.GetCustomAttribute(methodInfo, typeof(AuthorizationAttribute));
I am not sure what I am doing wrong here. It seems like it should work, but I am sure I am making a simple mistake somewhere. Any insight?
Thanks for any assistance.
Edit:
I am not sure if it adds any meaning, but the AuthorizationAttribute declaration exists in a different project from my services project. The Service Contract interface exists in the same project as the AuthorizationAttribute.
I tried doing a cast and got the following exception:
[A]Lib.OAuth.AuthorizationAttribute cannot be cast to [B]Lib.OAuth.AuthorizationAttribute.
Type A originates from 'Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the
context 'LoadNeither' at location 'F:\RestServices\bin\Lib.dll'. Type B originates from 'Lib,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\oauth_rest\951069b9
\9f7b77fe\assembly\dl3\54c48906\f928a6ad_01facb01\Lib.dll'.
Any ideas?
The exception contains the answer:
Type A originates...at location 'F:\RestServices\bin\Lib.dll'. Type B originates...at location
'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\oauth_rest\951069b9
\9f7b77fe\assembly\dl3\54c48906\f928a6ad_01facb01\Lib.dll'
The issue is that the Lib.OAuth.AuthorizationAttribute type which attributes your method is found in an assembly that is different than the assembly loaded at runtime when you try to cast.
Is it possible that one of your projects is using an old version of Lib.dll?
Thanks to Wesley's response, I was able to figure this out. It is more of a 'duh' moment than anything.
I was using some example code for reflection to load an assembly via the Assembly.LoadFile(...) method. The problem is that since my assembly was not registered with the GAC, it was reading the local copy on the IIS server and the comparison failed.
For reference, this was my solution:
Assembly.GetExecutingAssembly();
Once I did that, everything worked.
Related
I added the nuget FluentAssertions 6.7.0 in a test project using .NET Framework 4.6.1. I run tests from Rider 2022.1.1.
I'm new to this nuget and I read the intro and searched for issues (none found). I come from the Should family and trying to upgrade.
I cannot build with basic assertions. Here is the initial code:
using FluentAssertions;
using Moq;
using System;
using Xunit;
public class MyTestClass
{
[Fact]
public void GetProvider_ByRemoteName_Works()
{
// input
var desiredRemoteName = "Remote2";
// prepare
var context = Context.New(); // mocks and stubs
// execute
var result = context.SomeService.GetProvider(desiredRemoteName);
// verify
result.Should().NotBeNull(); // error line
result.Should().BeOfType<MyProviderClient>(); // error line
}
The build errors are:
error CS0012: The type 'DataTable' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
error CS0012: The type 'DataColumn' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
...
error CS0012: The type 'DataRow' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
I don't understand why I should reference this "System.Data" assembly. That does not seem legit. If I do reference it:
MyTestClass.cs: [CS0121] The call is ambiguous between the following methods or properties: 'DataRowAssertionExtensions.Should(TDataRow)' and 'DataSetAssertionExtensions.Should(TDataSet)'
Also, removing the error lines and using line provide a valid build and test run.
Also, the IDE editor indicates:
The call is ambiguous between the following methods or properties: 'DataRowAssertionExtensions.Should(TDataRow)' and 'DataSetAssertionExtensions.Should(TDataSet)'
Also, using Xunit's assertions works:
// verify
Assert.NotNull(result);
Assert.IsType<MyProviderClient>(result);
Following up on your comments, let's consider this updated code:
// execute
object result = context.SomeService.GetProvider(desiredRemoteName);
// verify
result.Should().BeAssignableTo<IMyInterface>()
.And.BeOfType<SomeImplementation>()
.Which
.Configuration
.Should() // error line
.NotBeNull();
The same error occurs on the latest .Should() call.
MyTestClass.cs: [CS0121] The call is ambiguous between the following methods or properties: 'DataRowAssertionExtensions.Should(TDataRow)' and 'DataSetAssertionExtensions.Should(TDataSet)'
Is it considered "normal" with FluentAssertions to do .BeOfType<>().Which everywhere? I feel something is wrong on my side or in the way the lib works.
As I recall, there's a weird issue with .NET Framework 4.6.1 where the assembly reference to System.Data wasn't automatically added. For newer framework versions, it happens automatically.
The IDE error you listed suggests that the compiler doesn't know which of the .Should() overloads to call. This isn't unusual for any library that relies on overload resolution.
Since it looks like you're only intending to test the return type in this context, you only "need" the ObjectAssertions overload of .Should(). As such, one way you could avoid the ambiguous invocation like this:
object result = context.SomeService.GetProvider(desiredRemoteName);
result.Should().BeOfType<MyProviderClient>() // Chained FA assertions are now typed as MyProviderClient
.Which.Should().BeEquivalentTo(new { Foo = "bar" });
Observe:
Remember that the value null does not have a runtime type, so asserting that an object has some specific runtime type implicitly asserts that it is not null. FA's .BeOfType<T>() assertion will fail with a specific message if a null reference is asserted on.
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.
I have an application where I load plugins by reading their DLL file and then loading the bytes using AppDomain.CurrentDomain.Load(bytes). Note that the application and the plugin are loaded in the same AppDomain. The plugin contains several classes which register themselves in a service locator system using a static constructor.
Later, my main application tries to find and instantiate one of these service classes using the service locator, but it cannot find the class. Upon manual inspection, I can see that the registry entry is present in the locator, so it was registered, but for some unknown reason the types aren't equal.
I then put a breakpoint at the place where the type is registered and discovered the following weirdness:
How can typeof(IViewFor<CompactDashboardViewModel>) not be equal to itself?
I then tested a few more things:
t == t
true
typeof(IViewFor<CompactDashboardViewModel>) == typeof(IViewFor<CompactDashboardViewModel>)
true
t.AssemblyQualifiedName == typeof(IViewFor<CompactDashboardViewModel>).AssemblyQualifiedName
true
In fact, everything about these 2 Type objects seems to be equal, except the m_handle and m_cache fields.
typeof(IViewFor<CompactDashboardViewModel>).TypeHandle
{System.RuntimeTypeHandle}
Value: 0x08690784
m_type: {Name = "IViewFor`1" FullName = "ReactiveUI.IViewFor`1[[PluginMTSICS.ViewModel.CompactDashboardViewModel, PluginMTSICS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
t.TypeHandle
{System.RuntimeTypeHandle}
Value: 0x0f8cf5a8
m_type: {Name = "IViewFor`1" FullName = "ReactiveUI.IViewFor`1[[PluginMTSICS.ViewModel.CompactDashboardViewModel, PluginMTSICS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
Does anybody know what is happening here? I am using .NET 4.7.1.
I am trying to create an MCVE, but unsuccessfully so far.
Maybe this works:
Type t = typeof(IViewFor<CompactDashboardViewModel>);
//this should evaluate to true:
bool result = t.Equals(typeof(IViewFor<CompactDashboardViewModel>));
Type.Equals docs:
https://msdn.microsoft.com/en-us/library/3ahwab82(v=vs.110).aspx
EDIT:
After reading this post Type Checking: typeof, GetType, or is? i would expect this to work:
Type t = typeof(IViewFor<CompactDashboardViewModel>);
//this should evaluate to true:
bool result = t is IViewFor<CompactDashboardViewModel>;
OK, so I fixed the issue. Here is what I did:
My main application had a reference to a library project, which in turn referenced the plugin project. This probably caused the assembly to be loaded twice, in different load contexts (see links below for more info). I removed the reference. The problem was not fixed, and now weird stuff was happening such as typeof(CompactDashboardViewModel) == null.
My plugin loading code originally used appdomain.Load(bytes). I replaced this with Assembly.LoadFrom. typeof() now worked correctly, and works as expected. However, Type.GetType() still returns null sometimes.
I replaced Assembly.LoadFrom with Assembly.Load and added my plugin directory to the probing path using the <probing> tag in app.config. Everything works correctly now, however I can't load the plugins by filepath, as Assembly.Load requires the assembly name. Not ideal, but I can live with that.
Useful sources:
Best practices for assembly loading
<probing> element
Type.GetType() docs
LoadFrom isolation
Choosing a binding context
I have a project named "Test.LiveModel" (Test.LiveModel.dll) and its version is 8.0.7.0 in my solution which contains 25 projects. I can see the information of Test.LiveModel in AssemblyInfo.cs. I have two category of objects named 'base class category' and 'user-defined class category' which are displaying in my application UI. I am displaying this through a property which is of class Type
Now I am considering one base class category object named "Server" and one user-defined class category object RoundedTree. When I set value as "Server" in Property in Grid after saving it when I restart my application I can see the saved value, but for "RoundedTree" which is not happening due to type becomes null. So I did a thorough analysis and came to know that issue is in ToType() method shown below
This is ToType() metho
For base class Server xmlSerializableType.Name, I am getting as Test.LiveModel.Server and AssemblyName I am getting as Test.LiveModel, Version=8.0.7.0, Culture=neutral, PublicKeyToken=23bd062a94e26d58 and type I am getting by using Type.GetType as type = {Name = "Server" FullName = "Test.LiveModel.Server"}
But for user defined class xmlSerializableType.Name I am getting as _Rounded_Tree. 'type' I am getting as null by using Type.GetType. AssemblyName I am getting as _Rounded_TreeTest-Machine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, but even assembly.GetType I am getting as null. What is the reason behind it? Why am I getting assembly version 0.0.0.0? I mean full assembly _Rounded_TreeTest-Machine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null.
This is the method CreateType() which will create assembly and type as myTypeBuilder for userdefined class:
public Type CreateType()
{
// Create the assembly name by appending the machine name to the typename.
myAsmName.Name = this.TypeName + Environment.MachineName;
// Define assembly that can be executed but not saved
this.UserClassAssemblyBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
// Create dynamic module with symbol information
this.UserClassModuleBuilder = this.UserClassAssemblyBuilder.DefineDynamicModule("userdefinedmodule", true);
So here is my question: if real Dll has some version number, and user defined class assembly has version 0.0.0.0, is that the reason why I am getting type as null after using Type.GetType and assembly.GetType method?
Here are some suggestions which may solve the problems.
Define a assembly version
new AssemblyName(this.TypeName + Environment.MachineName)
{
Version = new Version("1.0.0.0")
};
Use full qualified names for the serialization
myObject.GetType().FullName
my situation is the next: I'm working with Visual C# 2010 express developing a Windows Forms Application. When the user logins, dinamically build a menustrip with options loaded from a database table. In that table i save id, option name and Form Name.
So, suppose that in my project i have a Form named Contabilidad, it has Contabilidad.cs that is the main class , so if i wanna create a new form and show it i do this:
Contabilidad frmConta = new Contabilidad();
frmConta.Show();
But in this case, because the menu options are stored in database, in database i only have the string "Contabilidad". So, i want to use C# reflection to create a instance of Contabilidad or any other form only with class name in string format.
First i tried this:
Form frmConta= (Form)Activator.CreateInstance(null, "Contabilidad").Unwrap();
Because i read in a StackOverflow question that if i use null i'm referring to current assembly (my forms are all in the same project), but i get this message:
Could not load type 'Contabilidad' from assembly 'AccountingSA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
The class definition is the next:
namespace AccountingSA {
public partial class Contabilidad : Form
{
public Contabilidad()
{
InitializeComponent();
} ...
Also i tried this:
Assembly assembly = Assembly.Load("AccountingSA");
Type t = assembly.GetType("Contabilidad");
Form frmConta = (Form)Activator.CreateInstance(t);
But i get ArgumentNullException with this message:
Value cannot be null. Parameter name: type
Because t variable is null.
What i'm do wrong? Thanks in advance.
Use the fully-qualified name of the type:
Type t = assembly.GetType("AccountingSA.Contabilidad");
From the documentation for Assembly.GetType(string):
name Type: System.String
The full name of the type.
[...] The name parameter includes the namespace but not the assembly.
You're trying to use the name of the class without specifying the namespace. This should be fine:
Assembly assembly = Assembly.Load("AccountingSA");
Type t = assembly.GetType("AccountingSA.Contabilidad");
Form frmConta = (Form)Activator.CreateInstance(t);
Every version of GetType requires the fully-qualified type name; the benefit of using Assembly.GetType is that at least you don't need to also include the assembly name, but as documented you still need the namespace:
The name parameter includes the namespace but not the assembly.
Note that to diagnose something similar in the future, it would have been worth looking at the value of t after the second line - it will be null, which is why the third line threw an exception.
You should add the namespace:
assembly.GetType("AccountingSA.Contabilidad");
Try this
Form frmConta= (Form)Activator.CreateInstance(null, "AccountingSA.Contabilidad").Unwrap();
Try specifying your class this way:
ContabilidadNamespace.Contabilidad, ContabilidadAssembly
Its too late in the thread to answer, but the earlier answer, in current .NET framework (4.7), not working (The line Assembly assembly = Assembly.Load("AccountingSA"); always throws FileIOException). Currently, working code is (Use Type directly)
Type t = Type.GetType("AccountingSA.Contabilidad");
Form frmConta = (Form)Activator.CreateInstance(t);
or other way using Assembly is
Assembly assembly = typeof(Form).Assembly;
Type t = assembly.GetType("AccountingSA.Contabilidad");
Form frmConta = (Form)Activator.CreateInstance(t);