philiplaureano / linfu Goto Github PK
View Code? Open in Web Editor NEWA framework that adds mixins, inversion of control, DbC, and other language features to the Common Language Runtime.
Home Page: http://www.codeproject.com/KB/cs/LinFuPart1.aspx
A framework that adds mixins, inversion of control, DbC, and other language features to the Common Language Runtime.
Home Page: http://www.codeproject.com/KB/cs/LinFuPart1.aspx
The intercepted method in the sample interception program always returns null (Or, equivalent), no matter what actual value the method returns.
Let's change the Pay() method of Employee class to return an int
public int Pay(int wage)
{
var currentAmount = wage;
//_checkingAccount.Deposit(currentAmount);
Console.WriteLine("Paid {0} units", wage);
return wage;
}
The, Intercept method is already there which invokes the target method and and tries to get the return value from within the intercepted method:
public object Intercept(IInvocationInfo info)
{
var methodName = info.TargetMethod.Name;
Console.WriteLine("method '{0}' called", methodName);
// Replace the input parameter with 42
var result = info.TargetMethod.Invoke(info.Target, new object[]{42});
//Expecting to get the return value correctly from the target method.
return result;
//The return value is always null or equivalent (0 here)
}
Unfortunately, the return value from the target method invocation (info.TargetMethod.Invoke()) is always null or equivalent (0 here). So, when I try to postweave some of my existing dlls in a project, the project fails to run (Cause, the methods calls no longer return any value after post-weaving).
Using a reflector, I took a look at the post weaven Pay() method, after modifying the Pay() as returning an int. There I found the following codes, along with the injected codes
... int amount = wage; this._checkingAccount.Deposit(amount);
Console.WriteLine("Paid {0} units", wage);
int num2 = wage;
....
return (int) obj2;
//I've found that, the obj2 is never assigned with a value in the post weaven codes and hence, the postweaven methods always return null. This may give you some clue.
Please note that, the First version of LinFu.AOP was able to return the correct value from the postweaven intercepted methods (It had other issues though). So, I hope this issue should also be an easy fix.
Thanks
Comments
When you do a "go ioc" or "go aop" the build fails if a debug version of the library has not been built. This is because one of the depends of the script for these two actions is "run-unit-tests" which appear to only run against only the debug version of the library.
Hi Philip,
Long time no speak. I've got a realword use for MixIns in VB.Net and I'm trying to implement DynamicObject with MixIns that refer to MixIns.
I've followed the instructions on CodeProject and implemented the IMixinAware interface, but when I run the code I get an error message: "Method 'set_Hello' not found on type 'System.Object".
Is there any way I can get the small VB.Net project to you to have a squiz at. It's got 2 classes, 2 interfaces (including IMixinAware), and once class inheriting from the other.
I 'MixWith' instances of both classes, and both classes have a property called "Hello" with a 'Set' and 'Get'.
That's what I don't understand, I've created the Set/Get statements on both properties, and I still get the error message.
In essence, I would like to manipulate a base class instance from an instance of its child class mixed with an instance of the base class. That way, I don't have to clone the base class to get access to its members/properties and methods.
Kind regards
Victor
I’m having some trouble with LinFu 2.3’s IoC and I think I’ve found a bug.
I’ve created the following test service:
public interface IService
{
int Int { get; }
string Text { get; }
bool Bool { get; }
}
[Implements(typeof(IService<>), LifecycleType.OncePerRequest)]
public class S : IService
{
public S(int i, string text, bool b)
{
Int = i;
Text = text;
Bool = b;
}
public int Int { get; set; }
public string Text { get; set; }
public bool Bool { get; set; }
}
When I try to instantiate the service by providing the constructor arguments to GetService it fails with a ServiceNotFound exception.
ServiceContainer container = new ServiceContainer();
container.Initialize();
container.LoadFrom(typeof(UnitTest1).Assembly);
var s = container.GetService<IService>(42, "frobozz", false);
If I strip off the generics, changing IService to IService and S to S it works fine. Debugging LinFu it looks like the problem is in FactoryStorage.GetFactory:
public override IFactory GetFactory(IServiceInfo serviceInfo)
{
// Attempt to create the service type using
// the strongly-typed arguments
var factory = base.GetFactory(serviceInfo);
var serviceType = serviceInfo.ServiceType;
var serviceName = serviceInfo.ServiceName;
// Use the default factory for this service type if no other factory exists
var defaultServiceInfo = new ServiceInfo(serviceInfo.ServiceName, serviceInfo.ServiceType);
if (factory == null && base.ContainsFactory(defaultServiceInfo))
factory = base.GetFactory(defaultServiceInfo);
// Attempt to create the service type using
// the generic factories, if possible
if (factory != null || !serviceType.IsGenericType)
return factory;
var definitionType = serviceType.GetGenericTypeDefinition();
var genericServiceInfo = new ServiceInfo(serviceName, definitionType, serviceInfo.ArgumentTypes);
if (base.ContainsFactory(genericServiceInfo))
return base.GetFactory(genericServiceInfo);
With the (working) non-generic case, the _entries dictionary contains a key for IService with 0 arguments. The construction of defaultServiceInfo with no arguments matches that, and the factory matching defaultServiceInfo is returned and all is well.
With the (not working) generic case the _entries dictionary contains a key for IService<> with 0 arguments. The construction of defaultServiceInfo strips the arguments from my request but does not strip the int from my provided type of IService. Thus defaultServiceInfo does not return a factory (as IService<> != IService). The code falls through to the next step which strips the generic parameter out but does not strip the arguments out, so it ends up looking for the service type IService<> but with whatever arguments I provide. This doesn’t match either and the code falls all the way through w/o finding the default factory.
I’m not sure whether the correct fix is to change defaultServiceInfo so it strips the generic arguments out as well as the constructor argumennts, or whether an addition step of looking for something with generic arguments & constructor arguments stripped should be added.
As far as I can tell this makes the functionality totally broken as there is no workaround.
I made the following change to GetFactory() to test my hypothesis and with the change the code works as expected (whether the change breaks other things I do not know):
///
/// Obtains the instance that can instantiate the
/// service described by the object instance.
///
/// The object that describes the service to be created.
/// A instance if the service can be instantiated; otherwise, it will return false.
public override IFactory GetFactory(IServiceInfo serviceInfo)
{
// Attempt to create the service type using
// the strongly-typed arguments
var factory = base.GetFactory(serviceInfo);
var serviceType = serviceInfo.ServiceType;
var serviceName = serviceInfo.ServiceName;
// Use the default factory for this service type if no other factory exists
var defaultServiceInfo = new ServiceInfo(serviceInfo.ServiceName, serviceInfo.ServiceType);
if (factory == null && base.ContainsFactory(defaultServiceInfo))
factory = base.GetFactory(defaultServiceInfo);
// Attempt to create the service type using
// the generic factories, if possible
if (factory != null || !serviceType.IsGenericType)
return factory;
/*********************************************************************************************/
// Begin MJS Hack.
// We've got a generic service request, repeat the defaultServiceInfo query above but this time
// stripping the generic arguments as well as the constructor arguments.
defaultServiceInfo = new ServiceInfo(serviceName, serviceType.GetGenericTypeDefinition());
if (factory == null && base.ContainsFactory(defaultServiceInfo))
{
factory = base.GetFactory(defaultServiceInfo);
if (null != factory) return factory;
}
// End MJS Hack.
/*********************************************************************************************/
var definitionType = serviceType.GetGenericTypeDefinition();
var genericServiceInfo = new ServiceInfo(serviceName, definitionType, serviceInfo.ArgumentTypes);
if (base.ContainsFactory(genericServiceInfo))
return base.GetFactory(genericServiceInfo);
I trying the AOP part of LinFu(BTW great work!) but i think i found a problem with the IOC bootstrap module.
If the output directory contain a native dll the bootstrap process fails with a BadImageFormatException.
In the file AssemblyTargetLoader.cs at line 75 the function CanLoad check only the file extension:
public virtual bool CanLoad(string filename)
{
string extension = Path.GetExtension(filename).ToLower();
return TypeLoaders.Count > 0 &&
(extension == ".dll" || extension == ".exe") &&
File.Exists(filename);
}
I wrapped the code that load the requested assembly file in a try/catch(BadImageFormatException) (in Loader.cs inside the foreach loop) and it seem to work fine, but i am not familiar enough with the code to be sure if this handle all the cases(i dont think so).
public void LoadDirectory(string directory, string filespec)
{
// Determine which files currently exist
IEnumerable<string> files = DirectoryLister.GetFiles(directory, filespec);
foreach (string currentFile in files)
{
// Make sure the file is loaded only once
if (_loadedFiles.Contains(currentFile))
continue;
try
{
// HACK: Manually load any loader plugins
// into the loader
if (_pluginLoader != null && _pluginLoader.CanLoad(currentFile))
{
// Immediately execute any custom loader actions
// embedded in the file itself
IEnumerable<Action<ILoader<TTarget>>> customActions = _pluginLoader.Load(currentFile);
foreach (var customAction in customActions)
{
customAction(this);
}
}
LoadFile(currentFile);
_loadedFiles.Add(currentFile);
}
catch (BadImageFormatException)
{
}
}
}
I am using the latest version of the master branch.
Not sure if this is a but or a feature, but it is a change from how LinFu used to work (I have a unit test that started failing with a trunk pull from yesterday).
With the latest LinFu trunk, services added to a container as unnamed services get returned for service queries for a named service. For example:
var container = new ServiceContainer();
var myService = new MyService();
container.AddService<IMyService>(myService);
Assert.IsNotNull(container.GetService<IMyService>());
Assert.IsNull(container.GetService<IMyService>("frobozz"));
The second Assert used to pass it now asserts as the GetService("frobozz") call is returning the unnamed instance.
I suspect this was introduced by the fix for my earlier problem with factories for generic types (although I haven't debugged LinFu to figure out why this started happening).
EDIT: The second if in FactoryStorage.GetDefaultFactory() is what is doing it. And I was right it's part of the changeset for the fix to my earlier generics bug.
private IFactory GetDefaultFactory(string serviceName, Type serviceType, IFactory factory)
{
var defaultNamedServiceInfo = new ServiceInfo(serviceName, serviceType);
if (factory == null && base.ContainsFactory(defaultNamedServiceInfo))
factory = base.GetFactory(defaultNamedServiceInfo);
var defaultServiceInfo = new ServiceInfo(string.Empty, serviceType);
if (factory == null && base.ContainsFactory(defaultServiceInfo))
factory = base.GetFactory(defaultServiceInfo);
return factory;
}
I am running LinFu.DynamicProxy.dll 1.0.3.18540 on Silverlight 4.0. The following test:
public interface IFoo
{
}
public class DummyClass : IFoo, IInterceptor
{
public DummyClass()
{
var factory = new ProxyFactory();
factory.CreateProxy<IFoo>(this);
}
public object Intercept(InvocationInfo info)
{
return null;
}
}
[TestClass]
public class Tests
{
[TestMethod]
public void CreateProxyShouldNotRaiseException()
{
Assert.IsNotNull(new DummyClass());
}
}
... causes an exception to be thrown:
TargetInvocationException was unhandled
Exception has been thrown by the target of an invocation.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at LinFu.DynamicProxy.ProxyFactory.CreateProxy[T](IInterceptor interceptor, Type[] baseInterfaces)
at LinFuIssue.DummyClass..ctor()
at LinFuIssue.Tests.CreateProxyShouldNotRaiseException()
This test result also contained an inner exception:
System.Security.VerificationException: Operation could destabilize the runtime.
at DummyClassProxy..ctor()
The same code compiled & run on .NET 4.0 using the LinFu.DynamicProxy.dll 1.0.3139.17910 works just fine.
The LinFu.AOP.Tasks Release build outputs to a directory local to the project rather than the build/Release directory. This causes "go aop" to fail.
LinFu.Proxy.ILMerge.MSBuild file is missing from repository.
Build went normally as expected. But when I tried to start website, I got assembly loading error. This is the content of fusion log:
*** Assembly Binder Log Entry (12/7/2011 @ 8:25:41 PM) ***
The operation failed.
Bind result: hr = 0x8013110e. No description available.
Assembly manager loaded from: D:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable D:\Program Files (x86)\IIS Express\iisexpress.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = Mihhail-PC\Mihhail
LOG: DisplayName = MvcApplication1
(Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: MvcApplication1 | Domain ID: 2
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///D:/Users/Mihhail/Documents/Visual Studio 2010/Projects/MvcApplication1/MvcApplication1/
LOG: Initial PrivatePath = D:\Users\Mihhail\Documents\Visual Studio 2010\Projects\MvcApplication1\MvcApplication1\bin
LOG: Dynamic Base = D:\Users\Mihhail\AppData\Local\Temp\Temporary ASP.NET Files\root\f5537734
LOG: Cache Base = D:\Users\Mihhail\AppData\Local\Temp\Temporary ASP.NET Files\root\f5537734
LOG: AppName = fc02e379
Calling assembly : (Unknown).
LOG: This bind starts in default load context.
LOG: Using application configuration file: D:\Users\Mihhail\Documents\Visual Studio 2010\Projects\MvcApplication1\MvcApplication1\web.config
LOG: Using host configuration file: D:\Users\Mihhail\Documents\IISExpress\config\aspnet.config
LOG: Using machine configuration file from D:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///D:/Users/Mihhail/AppData/Local/Temp/Temporary ASP.NET Files/root/f5537734/fc02e379/MvcApplication1.DLL.
LOG: Attempting download of new URL file:///D:/Users/Mihhail/AppData/Local/Temp/Temporary ASP.NET Files/root/f5537734/fc02e379/MvcApplication1/MvcApplication1.DLL.
LOG: Attempting download of new URL file:///D:/Users/Mihhail/Documents/Visual Studio 2010/Projects/MvcApplication1/MvcApplication1/bin/MvcApplication1.DLL.
LOG: Assembly download was successful. Attempting setup of file: D:\Users\Mihhail\Documents\Visual Studio 2010\Projects\MvcApplication1\MvcApplication1\bin\MvcApplication1.dll
LOG: Entering download cache setup phase.
ERR: Error extracting manifest import from file (hr = 0x8013110e).
ERR: Setup failed with hr = 0x8013110e.
ERR: Failed to complete setup of assembly (hr = 0x8013110e). Probing terminated.
LinFu.IoC.ServiceNotFoundException (and possibly other linfu exceptions?) is not serializable. This causes problems when linfu is used by objects exposed through remoting.
The title says more or less all.
A little sample:
[TestClass]
public class LinFuProxyTests
{
[TestMethod]
public void CreateProxyTest()
{
var target = new SampleClass();
var factory = new ProxyFactory();
var interceptor = new SampleInterceptor(target);
var proxy = factory.CreateProxy<SampleClass>(interceptor);
}
}
public class SampleClass : ICloneable
{
object ICloneable.Clone()
{
return new SampleClass();
}
}
public class SampleInterceptor : IInvokeWrapper
{
public SampleInterceptor(object target)
{
this.Target = target;
}
public object Target { get; private set; }
object IInvokeWrapper.DoInvoke(IInvocationInfo info)
{
return null;
}
void IBeforeInvoke.BeforeInvoke(IInvocationInfo info)
{
}
void IAfterInvoke.AfterInvoke(IInvocationInfo info, object returnValue)
{
}
}
Result of the unit test is:
Test method LinFuProxyTests.CreateProxyTest threw exception:
System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at LinFu.Proxy.Interfaces.ProxyFactoryExtensions.CreateProxy(IProxyFactory factory, Type instanceType, IInterceptor interceptor, Type[] baseInterfaces)
at LinFu.Proxy.Interfaces.ProxyFactoryExtensions.CreateProxy(IProxyFactory factory, Type instanceType, IInvokeWrapper wrapper, Type[] baseInterfaces)
at LinFu.Proxy.Interfaces.ProxyFactoryExtensions.CreateProxy(IProxyFactory factory, IInvokeWrapper wrapper, Type[] baseInterfaces)
at LinFuProxyTests.CreateProxyTest() in LinFuProxyTests.cs: line 28
The following simple signature will result in the interceptor to receive null
as the value for the parameter:
void Test2([In, Out]bool[] test);
In
and Out
are from System.Runtime.InteropServices
Complete sample:
public interface IBar
{
void Test1(bool[] test);
void Test2([In, Out]bool[] test);
}
internal class Bar : IBar
{
public void Test1(bool[] test)
{
if (test == null)
throw new ArgumentNullException("test");
}
public void Test2(bool[] test)
{
if (test == null)
throw new ArgumentNullException("test");
}
}
public class Interceptor : IInterceptor
{
private readonly object _target;
public Interceptor(object target)
{
if (target == null)
throw new ArgumentNullException("target");
_target = target;
}
public object Intercept(InvocationInfo info)
{
Console.WriteLine(info.TargetMethod.Name + ": Is parameter value == null? " + (info.Arguments[0] == null));
return info.TargetMethod.Invoke(_target, info.Arguments);
}
}
var barProxy = (IBar)new ProxyFactory().CreateProxy(typeof(IBar), new Interceptor(new Bar()));
barProxy.Test1(new[] { true, false });
barProxy.Test2(new[] { true, false });
Output on my machine with LinFu.DynamicProxy 1.0.5:
Test1: Is parameter value == null? False
Test2: Is parameter value == null? TrueUnhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentNullEx
ception: Value cannot be null.
Parameter name: test
at LinFuTest.Bar.Test2(Boolean[] test) in d:\Projects\Temp\LinFuTest\LinFuTest\InOutBug.cs:line 25
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at LinFuTest.Interceptor.Intercept(InvocationInfo info) in d:\Projects\Temp\LinFuTest\LinFuTest\InOutBug.cs:line 42
at IBarProxy.Test2(Boolean[] )
at LinFuTest.Program.Main(String[] args) in d:\Projects\Temp\LinFuTest\LinFuTest\Program.cs:line 45
Press any key to continue . . .
We have an error with following description when using proxy of our interfaces generated by Linfu.Core 2.3 in website application.
Description from EventLog:
Exception information:
Exception type: IndexOutOfRangeException
Exception message: Index was outside the bounds of the array.
Request information:
Request URL: http://[OUR_SITE]/xxx
Request path: /path
User host address: xx.xx.xx.xx
User: 1586068
Is authenticated: True
Authentication Type: Forms
Thread account name: IIS APPPOOL\App
Thread information:
Thread ID: 50
Thread account name: IIS APPPOOL\App
Is impersonating: False
Stack trace: at System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)
at LinFu.AOP.Cecil.IgnoredInstancesRegistry.AddInstance(Object target)
at LinFu.Proxy.IBlockServiceProxy-05990fd14dbb49659cd0ebe8d8e66327.System.IDisposable.Dispose()
at MyProj.ContactList.ContactListAdapter.GetBlockedUsers(Member owner) in C:!Projects\xxx\ContactListAdapter.cs:line 174
Error appears only with Linfu.Core version 2.3 and only in applications with a great level of concurrent calls.
IBlockServiceProxy is a proxy of our interface. When we generate proxy by ProxyFactory object we mixin additional IDisposable interface like this:
_proxyFactory.CreateProxy(_interceptor, typeof(IDisposable))
And error occures when Dispose is called implicitly in using operator. In interceptor we have some logic for intercepting dispose call.
Hi,
I'm trying to compile a project (Called "Plugin") with LinFu's Postweaver. I've added the following the the project,
<PropertyGroup>
<PostWeaveTaskLocation>C:\Path\To\My\LinFu.Core.dll</PostWeaveTaskLocation>
</PropertyGroup>
<UsingTask TaskName="PostWeaveTask" AssemblyFile="$(PostWeaveTaskLocation)" />
<Target Name="AfterBuild">
<PostWeaveTask TargetFile="$(MSBuildProjectDirectory)\$(OutputPath)$(MSBuildProjectName).dll" InterceptAllExceptions="false" InterceptAllFields="false" InterceptAllNewInstances="false" InterceptAllMethodCalls="false" InterceptAllMethodBodies="true" />
</Target>
I'm using the LinFu.Core.dll included in LinFu's Nuget package.
This all works fine unless any class in my Project contains any form of generic class or method. So for example, if my Plugin project only contains one class,
public class TestClass
{
public void SomeFunction() { }
}
Everything works fine. Compiling works, and I can reference the output in other projects, do AOP etc.
when I modify this class to contain a generic method though,
public class TestClass
{
public void SomeFunction<T>() { }
}
something seems to go wrong. The project still compiles fine without any error messages. But its output dll seems to be broken.
When I'm referencing this project directly in another project, I'm getting an error message "The meta file '.....path........\Plugin.dll' could not be opened - the database file is damaged and can possibly not be used'.
And when, instead of referencing the project, I'm trying to reference its output dll, I'm getting an error message "Could not add reference to '.....path....\Plugin.dll'. Make sure that it's possible to access this file, and that the file is a valid assembly or COM component.".
(Just a heads up, I'm not using an English version of Visual Studio and I couldn't find any official translation for these error messages, so I've translated them to English myself - hence, phrasing might vary a little, but meaning should be clear).
Is this a known problem, does postweaving not work at all when any generics are involved in a library?
And is there any way to circumvent these issues and postweave libraries that do contain generics (even if that'd mean linfu wouldn't post-process any specific class or method in the library that is generic)?
How likely is a .NET Core version? Can the approach LinFu is taking to make dynamic proxies be reused with .NET Core's limited API?
SingletonFactory.CreateInstance has a threading bug:
if (_instances.ContainsKey(key))
return _instances[key];
lock (_lock)
{
T result = _createInstance(request);
if (result != null)
{
_instances[key] = result;
}
}
The read check is done outside the lock so it is possible multiple threads could not find the singleton, then try to create it, leading to more than 1 singleton instance getting created. Either the read needs to be done inside the lock or a second copy of it needs to be pasted into the lock (for lazy locking). If it were up to me I'd do the latter. :)
if (_instances.ContainsKey(key))
return _instances[key];
lock (_lock)
{
if (_instances.ContainsKey(key))
return _instances[key];
T result = _createInstance(request);
if (result != null)
{
_instances[key] = result;
}
}
Is it expected that you cannot use the current git source unless you're using .NET 4?
As soon as I add the post-weave task in a 3.5 targeted project, VS complains:
Warning 2 The primary reference "\LinfuLib.dll" could not be resolved because it has an indirect dependency on the .NET Framework assembly "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which has a higher version "4.0.0.0" than the version "2.0.0.0" in the current target framework. C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets 1360 9 Linfu35Test
Looking at my Linfu.AOP.Tasks DLL in Reflector shows references to both mscorlib 2 and 4, and I have no idea how it's getting those.. (This is a locally built DLL, but the same problem applies with the 2.3 package from github).
Thanks.
I'm playing around with various concepts. The test framework has three assemblies (A, B, and C). A has a reference to B, and C has a reference to B (A+B, C+B). It's a simple plug-in test with MEF. One of the dependencies being loaded is a simple service locator. When I attempt to use generic methods on the locator, the post compile method frags the assembly. When I use regular methods, it works...
The class:
[Export(typeof(IPlugin))] public class MudPlugin : IPlugin { [Import] public IServiceHost MyServiceHost { get; set; } public void DoWork() { //MyServiceHost.Register<INoInterfaceObject, NoInterfaceObject>(); MyServiceHost.Register(typeof(INoInterfaceObject), typeof(NoInterfaceObject)); //var o = MyServiceHost.Resolve<INoInterfaceObject>(); var o = (INoInterfaceObject)MyServiceHost.Resolve(typeof(INoInterfaceObject)); o.DoWork(); } }
The exception seen in ILSpy when the generic methods are used instead:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. at Mono.Collections.Generic.Collection`1.get_Item(Int32 index) at Mono.Cecil.SignatureReader.GetGenericParameter(GenericParameterType type, UInt32 var) at Mono.Cecil.SignatureReader.ReadTypeSignature(ElementType etype) at Mono.Cecil.MetadataReader.GetTypeSpecification(UInt32 rid) at Mono.Cecil.MetadataReader.LookupToken(MetadataToken token) at Mono.Cecil.Cil.CodeReader.ReadOperand(Instruction instruction) at Mono.Cecil.Cil.CodeReader.ReadCode() at Mono.Cecil.Cil.CodeReader.ReadFatMethod() at Mono.Cecil.Cil.CodeReader.ReadMethodBody() at Mono.Cecil.Cil.CodeReader.ReadMethodBody(MethodDefinition method) at Mono.Cecil.MethodDefinition.b__2(MethodDefinition method, MetadataReader reader) at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TRet& variable, TItem item, Func`3 read) at Mono.Cecil.MethodDefinition.get_Body() at ICSharpCode.Decompiler.CodeMappings.CreateCodeMapping(MethodDefinition member, Tuple`2 codeMappings) at ICSharpCode.Decompiler.Ast.AstBuilder.CreateMethod(MethodDefinition methodDef) at ICSharpCode.Decompiler.Ast.AstBuilder.AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) at ICSharpCode.Decompiler.Ast.AstBuilder.CreateType(TypeDefinition typeDef) at ICSharpCode.Decompiler.Ast.AstBuilder.AddType(TypeDefinition typeDef) at ICSharpCode.ILSpy.CSharpLanguage.DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) at ICSharpCode.ILSpy.TreeNodes.TypeTreeNode.Decompile(Language language, ITextOutput output, DecompilationOptions options) at ICSharpCode.ILSpy.TextView.DecompilerTextView.DecompileNodes(DecompilationContext context, ITextOutput textOutput) at ICSharpCode.ILSpy.TextView.DecompilerTextView.<>c__DisplayClass10.b__f()
I don't believe this to just be an issue with ILSpy, because of the behavior of the calling application. When the generics are used, the assembly is rendered unusable by the parent app (A cannot use MEF to load C). When generics are not used, everything functions normally.
Please let me know what other info I can supply...
I realize this is slightly off topic but I'm having trouble installing via Nuget
PM> Install-Package LinFu.Core
Install-Package : The element 'metadata' in namespace 'http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd' has invalid child element 'releaseNotes' in namespace 'http://schema
s.microsoft.com/packaging/2010/07/nuspec.xsd'. List of possible elements expected: 'iconUrl, dependencies, frameworkAssemblies, language, tags' in namespace 'http://schemas.microsoft
.com/packaging/2010/07/nuspec.xsd'.
At line:1 char:16
I just wanted to start off by thanking you for all the hard work that has gone into this. I think this is a great project with a lot of potential. The ability to unlock, fix, extend, etc. in third party libraries is awesome.
I am trying to intercept calls to a Microsoft library (Microsoft.Data.Schema.ScriptDom) to change the manner in which SQL is generated for SQL Azure. I have added a PostWeaveTask to intercept all methods, but this is having an undesirable side effect in the assembly that I am implementing the IMethodReplacementProvider and IInterceptor interfaces to replace the logic. Essentially the post weave is generating invalid IL in some method bodies preventing them from being run in a unit test or decompiled in ILSpy.
In my MethodReplacementProvider the CanReplace method is invalid when I uncomment the commented out lines below:
public bool CanReplace(object host, IInvocationInfo info)
{
var declaringType = info.TargetMethod.DeclaringType;
if (!declaringType.Equals(_targetType)) return false;
//bool isCorrectMethod = (info.TargetMethod.Name.Equals("ExplicitVisit"));
//if (!isCorrectMethod) return false;
//object objectBeingVisited = info.Arguments[0];
//return (objectBeingVisited is RaiseErrorLegacyStatement);
return false;
}
So specifically if I just uncomment the bool isCorrectMethod line, it generates invalid IL. In another class, the following method also has problems:
public void FixForAzure(string inputSql, out string outputSql, out IList<ParseError> errors)
{
using (var sqlReader = new StringReader(inputSql))
using (var sqlWriter = new StringWriter())
{
FixForAzure(sqlReader, sqlWriter, out errors);
outputSql = sqlWriter.ToString();
}
}
I tried to take Dénes Magyari's updated version and unfortunately that has not solved the problem either. I am wondering if there may be a work around by changing the PostWeaveTask to focus on 1 assembly. There would however appear to be an issue with the IL weave that leaves problems with some methods. Note that I am using .Net 4.0 as the MS libraries I'm using require them.
I ran PEVerify on the altered DLL and this is the output:
Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.1 Copyright (c) Microsoft Corporation. All rights reserved. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::.ctor][offset 0x0000001F][found ref ('this' ptr) 'SqlAzureConverter.Common.AzureConverter'] Uninitialized item on stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::Parse][offset 0x0000001B][found address of ref ][expected ref 'System.Object'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::Parse][offset 0x00000252][found ref 'System.Collections.Generic.IList`1[Microsoft.Data.Schema.ScriptDom.ParseError]'][expected address of ref ] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::Parse][offset 0x00000252][found ref 'System.Object'][expected ref 'Microsoft.Data.Schema.ScriptDom.Parser'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::FixForAzure][offset 0x00000016][found address of ref ][expected ref 'System.Object'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::FixForAzure][offset 0x000004F5][found ref 'System.Object'][expected ref 'Microsoft.Data.Schema.ScriptDom.ScriptGenerator'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::FixForAzure][offset 0x0000024D][found ref 'System.Collections.Generic.IList`1[Microsoft.Data.Schema.ScriptDom.ParseError]'][expected address of ref ] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::FixForAzure][offset 0x0000024D][found ref 'System.Object'][expected ref 'SqlAzureConverter.Common.AzureConverter'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.AzureConverter::FixForAzure][offset 0x0000076E] jmp / exception into the middle of an instruction. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.RaiserrorConverter::.ctor][offset 0x00000013][found ref ('this' ptr) 'SqlAzureConverter.Common.RaiserrorConverter'] Uninitialized item on stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x00001266][found ref 'System.Object'][expected ref 'System.Reflection.MethodBase'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x00000D23][found ref 'System.Object'][expected ref 'System.Reflection.MemberInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x00000ADF][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x000008A0][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x00000661][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x00000422][found ref 'System.Object'][expected ref 'System.Reflection.MemberInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::Intercept][offset 0x000001E5][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor::.ctor][offset 0x00000013][found ref ('this' ptr) 'SqlAzureConverter.Common.Replacements.RaiseErrorLegacyStatementInterceptor'] Uninitialized item on stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider::CanReplace][offset 0x0000069A][found ref 'System.Object'][expected ref 'System.Type'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider::CanReplace][offset 0x00000422][found ref 'System.Object'][expected ref 'System.Reflection.MemberInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider::CanReplace][offset 0x000001E5][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider::GetMethodReplacement][offset 0x00000454][found ref 'System.Object'][expected ref 'LinFu.AOP.Interfaces.IInvocationInfo'] Unexpected type on the stack. [IL]: Error: [SqlAzureConverter.Common.dll : SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider::.ctor][offset 0x00000013][found ref ('this' ptr) 'SqlAzureConverter.Common.Replacements.SqlAzureScriptGeneratorVisitorProvider'] Uninitialized item on stack. 23 Error(s) Verifying SqlAzureConverter.Common.dll
We recently saw LinFu throw a RecursiveDependencyException for one of our services in one of our test labs. What makes this unusual is that the service in question is only using default constructors so there shouldn't be any dependency issues. A little background:
Our service has a factory that creates one of two named service instances, depending on a registry value, like this:
ISomeService IFactory<ISomeService> CreateInstance(IFactoryRequest request)
{
// read registry value.
if (value == Proxy)
return request.Container.GetService<ISomeService>("WCF");
else
return request.Container.GetService<ISomeService>("Database");
}
It's being used to allow an outside tier to use a WCF proxy and for an internal tier to talk directly to the db, depending on the registry value. Two classes implement the interface using named instances as above.
The code ran as part of a windows service for about a month w/o restarting (in our production environment this isn't uncommon). Once we started getting the RecursiveDependencyException for this service every request returned this exception.
I took a peek in the code and I'm not sure if it's the only problem, but there are some issues in ContainerExtensions.AutoCreateInternal. Part of the method is below:
// Keep track of the number of pending type requests
_counter.Increment(concreteType);
// Keep track of the sequence
// of requests on the stack
lock (_requests)
{
_requests.Push(concreteType);
}
// This is the maximum number of requests per thread per item
const int maxRequests = 10;
if (_counter.CountOf(concreteType) > maxRequests)
{
// Build the sequence of types that caused the overflow
var list = new LinkedList<Type>();
lock (_requests)
{
while (_requests.Count > 0)
{
Type currentType = _requests.Pop();
list.AddLast(currentType);
}
}
throw new RecursiveDependencyException(list);
}
var activator = container.GetService<IActivator<IContainerActivationContext>>();
var context = new ContainerActivationContext(concreteType, currentContainer, additionalArguments);
object result = activator.CreateInstance(context);
lock (_requests)
{
_requests.Pop();
}
_counter.Decrement(concreteType);
The first obvious problem is that the recursive detection counter gets incremented and if it exceeds the limit of 10 an exception gets thrown but it doesn't get decremented. This means that once you get into the state of throwing this exception the counter will never go down and you'll be in it forever. The second problem is that the code is unguarded so if any exceptions occur in code between the increment/decrement the decrement never happens and you 'leak' a counter. I haven't followed through all the code so I'm not sure this is possible but that could explain why we saw this problem after a month or so.
I think that the pop of _requests and the decrement of the counter need to be in a finally block to ensure they always occur (made even more complicated because pop/decrement need to be guarded from each other as well). I think the method needs to look like this:
_counter.Increment(concreteType);
try
{
// Keep track of the sequence
// of requests on the stack
lock (_requests)
{
_requests.Push(concreteType);
}
try
{
// Boring method details ommitted.
}
finally
{
lock (_requests)
{
_requests.Pop();
}
}
}
finally
{
_counter.Decrement(concreteType);
}
I am using LinFu to work with proxy classes, allowing me to transparently store additional data. Over the lifetime of the process there may be many millions of intercepted calls.
Lately, I've been getting OutOfMemory exceptions on 32bit computers, which I tracked to the IgnoredInstancesRegistry. In there, every intercepted call is stored in a HashTable. The HashTable thus keeps getting bigger, fragmenting the large object heap and eventually causing the OOM.
Unfortuantely, there is no real documentation on the IgnoredInstancesRegistry. What is it supposed to be used for? Would it be possible to allow disabling its functionality?
The following code sample fails with a ServiceNotFoundException for both IFactory & IFactory{T}. If MyClass{T} is changed to MyClass the sample code works correctly (the factory is called to instantiate the service with "frobozz" as the service name).
[TestClass]
public class Test
{
[TestMethod]
public void TestMethod1()
{
ServiceContainer container = new ServiceContainer();
container.Initialize();
container.LoadFrom(typeof(MyClass<>).Assembly);
// Get ServiceNotFoundException here instead of a service instance.
var service = container.GetService<MyClass<string>>("frobozz");
Console.WriteLine("foo");
}
}
[Factory(typeof(MyClass<string>))]
public class MyFactory :
//IFactory<MyClass<string>>
IFactory
{
public object CreateInstance(IFactoryRequest request)
{
if (string.IsNullOrWhiteSpace(request.ServiceName))
throw new ArgumentNullException("ServiceName");
return new MyClass<string>();
}
//MyClass<string> IFactory<MyClass<string>>.CreateInstance(IFactoryRequest request)
//{
// return (MyClass<string>)CreateInstance(request);
//}
}
public class MyClass<T>
{ }
First of all, thanks for this lovely framework. However I am having some issues using this framework, which are hopefully easy to fix and probably my own fault of miss-using this wonderful framework.
I am quite an experienced Hobby-Programmer, however I have not worked too much with assembly code in general and found Mono.Cecil to be it quite difficult to use, if you want to achieve more complex results, besides adding some static method calls, so I was very happy that I found this on codeProject.com.
I am trying to inject some smaller code into an already compiled assembly, so I am using PostWeaver.exe. I tried weaving the complete assembly at the beginning, however that failed horribly with lots of exceptions, when running the resulting assembly, which was expected since the assembly is a really complex one, with lots of native library bindings. Which is why I started to weave only filtered method bodies and nothing else, but that should not be the problem, right?
I can modify methods returning void or objects quite well, however I run into problems when I want to edit a method returning a 'bool'. I have not tried to extend a wide range of methods, so I am not sure if this might also happen on other 'primitive' types.
The code of the to be modified assembly looks like this before weaving:
C#
private bool sendSilentRequest (string request)
{
if (this.m_Socket != null && this.m_Socket.Connected && this.IsServerInfoReceived ())
{
if (!request.EndsWith ("\n"))
{
request += "\n";
}
byte[] bytes = Encoding.get_UTF8 ().GetBytes (request);
this.m_Socket.Send (bytes);
return true;
}
return false;
}
IL
.method private hidebysig
instance bool sendSilentRequest (
string 'request'
) cil managed
{
// Method begins at RVA 0x31a50
// Code size 96 (0x60)
.maxstack 14
.locals init (
[0] uint8[]
)
IL_0000: ldarg.0
IL_0001: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_0006: brfalse IL_005e
IL_000b: ldarg.0
IL_000c: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_0011: callvirt instance bool [System]System.Net.Sockets.Socket::get_Connected()
IL_0016: brfalse IL_005e
IL_001b: ldarg.0
IL_001c: call instance bool Communicator::IsServerInfoReceived()
IL_0021: brfalse IL_005e
IL_0026: ldarg.1
IL_0027: ldstr "\n"
IL_002c: callvirt instance bool [mscorlib]System.String::EndsWith(string)
IL_0031: brtrue IL_0043
IL_0036: ldarg.1
IL_0037: ldstr "\n"
IL_003c: call string [mscorlib]System.String::Concat(string, string)
IL_0041: starg.s 'request'
IL_0043: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_UTF8()
IL_0048: ldarg.1
IL_0049: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string)
IL_004e: stloc.0
IL_004f: ldarg.0
IL_0050: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_0055: ldloc.0
IL_0056: callvirt instance int32 [System]System.Net.Sockets.Socket::Send(uint8[])
IL_005b: pop
IL_005c: ldc.i4.1
IL_005d: ret
IL_005e: ldc.i4.0
IL_005f: ret
} // end of method
After Weaving it looks like this:
C#
private bool sendSilentRequest (string request)
{
bool isInterceptionDisabled;
if (this is IModifiableType)
{
isInterceptionDisabled = (this as IModifiableType).IsInterceptionDisabled;
}
IInvocationInfo invocationInfo;
IAroundInvokeProvider methodBodyReplacementProvider;
IAroundInvoke surroundingImplementation;
IAroundInvoke surroundingImplementation2;
if (!isInterceptionDisabled)
{
Type[] typeArguments = new Type[0];
object[] arguments = new object[]
{
request
};
MethodBase methodFromHandle = MethodBase.GetMethodFromHandle (methodof (Communicator.sendSilentRequest (string)).MethodHandle, typeof(Communicator).TypeHandle);
invocationInfo = new InvocationInfo (this, methodFromHandle, new StackTrace (1, false), new Type[]
{
typeof(string)
}, typeArguments, typeof(bool), arguments);
IgnoredInstancesRegistry.AddInstance (invocationInfo);
if (!isInterceptionDisabled)
{
IMethodReplacementProvider methodReplacementProvider = ((IMethodReplacementHost)this).MethodBodyReplacementProvider;
if (this is IModifiableType && !isInterceptionDisabled)
{
methodBodyReplacementProvider = ((IMethodReplacementHost)this).MethodBodyReplacementProvider;
methodReplacementProvider = ((IAroundInvokeHost)this).AroundMethodBodyProvider;
if (methodReplacementProvider != null)
{
surroundingImplementation = methodReplacementProvider.GetSurroundingImplementation (invocationInfo);
}
surroundingImplementation2 = AroundMethodBodyRegistry.GetSurroundingImplementation (invocationInfo);
if (surroundingImplementation2 != null)
{
surroundingImplementation2.BeforeInvoke (invocationInfo);
}
if (surroundingImplementation != null)
{
surroundingImplementation.BeforeInvoke (invocationInfo);
}
}
}
}
IMethodReplacementProvider provider = MethodBodyReplacementProviderRegistry.GetProvider (this, invocationInfo);
if (!isInterceptionDisabled)
{
if (methodBodyReplacementProvider != null || provider != null)
{
IInterceptor methodReplacement;
if (methodBodyReplacementProvider != null)
{
methodReplacement = methodBodyReplacementProvider.GetMethodReplacement (this, invocationInfo);
}
if (methodReplacement == null)
{
if (provider != null)
{
methodReplacement = provider.GetMethodReplacement (this, invocationInfo);
}
}
if (methodReplacement != null)
{
(bool)methodReplacement.Intercept (invocationInfo);
goto IL_245;
}
}
}
if (this.m_Socket != null && this.m_Socket.Connected && this.IsServerInfoReceived ())
{
if (!request.EndsWith ("\n"))
{
request += "\n";
}
byte[] bytes = Encoding.UTF8.GetBytes (request);
this.m_Socket.Send (bytes);
1;
}
else
{
0;
}
IL_245:
object obj;
if (!isInterceptionDisabled)
{
if (surroundingImplementation == null)
{
}
if (surroundingImplementation != null)
{
surroundingImplementation.AfterInvoke (invocationInfo, obj);
}
if (surroundingImplementation2 == null)
{
}
if (surroundingImplementation2 != null)
{
surroundingImplementation2.AfterInvoke (invocationInfo, obj);
}
}
return obj != null;
}
IL
.method private hidebysig
instance bool sendSilentRequest (
string 'request'
) cil managed
{
// Method begins at RVA 0x1c4a4
// Code size 671 (0x29f)
.maxstack 7
.locals init (
[0] uint8[],
[1] bool,
[2] class LinFu.AOP.Interfaces.IInvocationInfo,
[3] class LinFu.AOP.Interfaces.IAroundInvokeProvider,
[4] class LinFu.AOP.Interfaces.IMethodReplacementProvider,
[5] object,
[6] class LinFu.AOP.Interfaces.IMethodReplacementProvider,
[7] class [mscorlib]System.Reflection.MethodBase,
[8] class [mscorlib]System.Type[],
[9] object[],
[10] class [mscorlib]System.Type[],
[11] class LinFu.AOP.Interfaces.IAroundInvoke,
[12] class LinFu.AOP.Interfaces.IAroundInvoke,
[13] class LinFu.AOP.Interfaces.IInterceptor
)
IL_0000: ldarg.0
IL_0001: isinst LinFu.AOP.Interfaces.IModifiableType
IL_0006: brfalse IL_001a
IL_000b: ldarg.0
IL_000c: isinst LinFu.AOP.Interfaces.IModifiableType
IL_0011: callvirt instance bool LinFu.AOP.Interfaces.IModifiableType::get_IsInterceptionDisabled()
IL_0016: stloc 1
IL_001a: nop
IL_001b: ldloc 1
IL_001f: brtrue IL_014a
IL_0024: ldc.i4 0
IL_0029: newarr [mscorlib]System.Type
IL_002e: stloc 10
IL_0032: ldc.i4 1
IL_0037: newarr [mscorlib]System.Object
IL_003c: stloc 9
IL_0040: ldloc 9
IL_0044: ldc.i4 0
IL_0049: ldarg 'request'
IL_004d: stelem.ref
IL_004e: ldarg.0
IL_004f: ldtoken method instance bool Communicator::sendSilentRequest(string)
IL_0054: ldtoken Communicator
IL_0059: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
IL_005e: stloc 7
IL_0062: ldloc 7
IL_0066: ldc.i4.1
IL_0067: ldc.i4.0
IL_0068: newobj instance void [mscorlib]System.Diagnostics.StackTrace::.ctor(int32, bool)
IL_006d: ldc.i4 1
IL_0072: newarr [mscorlib]System.Type
IL_0077: stloc 8
IL_007b: ldloc 8
IL_007f: ldc.i4 0
IL_0084: ldtoken [mscorlib]System.String
IL_0089: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_008e: stelem.ref
IL_008f: ldloc 8
IL_0093: ldloc 10
IL_0097: ldtoken [mscorlib]System.Boolean
IL_009c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00a1: ldloc 9
IL_00a5: newobj instance void LinFu.AOP.Cecil.InvocationInfo::.ctor(object, class [mscorlib]System.Reflection.MethodBase, class [mscorlib]System.Diagnostics.StackTrace, class [mscorlib]System.Type[], class [mscorlib]System.Type[], class [mscorlib]System.Type, object[])
IL_00aa: stloc 2
IL_00ae: ldloc 2
IL_00b2: call void LinFu.AOP.Cecil.IgnoredInstancesRegistry::AddInstance(object)
IL_00b7: ldloc 1
IL_00bb: brtrue IL_0149
IL_00c0: ldarg.0
IL_00c1: callvirt instance class LinFu.AOP.Interfaces.IMethodReplacementProvider LinFu.AOP.Interfaces.IMethodReplacementHost::get_MethodBodyReplacementProvider()
IL_00c6: stloc 4
IL_00ca: ldarg.0
IL_00cb: isinst LinFu.AOP.Interfaces.IModifiableType
IL_00d0: brfalse IL_0148
IL_00d5: ldloc 1
IL_00d9: brtrue IL_0148
IL_00de: ldarg.0
IL_00df: callvirt instance class LinFu.AOP.Interfaces.IMethodReplacementProvider LinFu.AOP.Interfaces.IMethodReplacementHost::get_MethodBodyReplacementProvider()
IL_00e4: stloc 3
IL_00e8: ldarg.0
IL_00e9: callvirt instance class LinFu.AOP.Interfaces.IAroundInvokeProvider LinFu.AOP.Interfaces.IAroundInvokeHost::get_AroundMethodBodyProvider()
IL_00ee: stloc 4
IL_00f2: ldloc 4
IL_00f6: brfalse IL_010c
IL_00fb: ldloc 4
IL_00ff: ldloc 2
IL_0103: callvirt instance class LinFu.AOP.Interfaces.IAroundInvoke LinFu.AOP.Interfaces.IAroundInvokeProvider::GetSurroundingImplementation(class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0108: stloc 11
IL_010c: nop
IL_010d: ldloc 2
IL_0111: call class LinFu.AOP.Interfaces.IAroundInvoke LinFu.AOP.Interfaces.AroundMethodBodyRegistry::GetSurroundingImplementation(class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0116: stloc 12
IL_011a: ldloc 12
IL_011e: brfalse IL_0130
IL_0123: ldloc 12
IL_0127: ldloc 2
IL_012b: callvirt instance void LinFu.AOP.Interfaces.IBeforeInvoke::BeforeInvoke(class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0130: nop
IL_0131: ldloc 11
IL_0135: brfalse IL_0147
IL_013a: ldloc 11
IL_013e: ldloc 2
IL_0142: callvirt instance void LinFu.AOP.Interfaces.IBeforeInvoke::BeforeInvoke(class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0147: nop
IL_0148: nop
IL_0149: nop
IL_014a: nop
IL_014b: ldarg.0
IL_014c: ldloc 2
IL_0150: call class LinFu.AOP.Interfaces.IMethodReplacementProvider LinFu.AOP.Interfaces.MethodBodyReplacementProviderRegistry::GetProvider(object, class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0155: stloc 6
IL_0159: ldloc 1
IL_015d: brtrue IL_01dc
IL_0162: ldloc 3
IL_0166: brtrue IL_0179
IL_016b: ldloc 6
IL_016f: brtrue IL_0179
IL_0174: br IL_01dc
IL_0179: nop
IL_017a: ldloc 3
IL_017e: brfalse IL_0195
IL_0183: ldloc 3
IL_0187: ldarg.0
IL_0188: ldloc 2
IL_018c: callvirt instance class LinFu.AOP.Interfaces.IInterceptor LinFu.AOP.Interfaces.IMethodReplacementProvider::GetMethodReplacement(object, class LinFu.AOP.Interfaces.IInvocationInfo)
IL_0191: stloc 13
IL_0195: nop
IL_0196: ldloc 13
IL_019a: brtrue IL_01bb
IL_019f: ldloc 6
IL_01a3: brfalse IL_01ba
IL_01a8: ldloc 6
IL_01ac: ldarg.0
IL_01ad: ldloc 2
IL_01b1: callvirt instance class LinFu.AOP.Interfaces.IInterceptor LinFu.AOP.Interfaces.IMethodReplacementProvider::GetMethodReplacement(object, class LinFu.AOP.Interfaces.IInvocationInfo)
IL_01b6: stloc 13
IL_01ba: nop
IL_01bb: nop
IL_01bc: ldloc 13
IL_01c0: brfalse IL_01dc
IL_01c5: ldloc 13
IL_01c9: ldloc 2
IL_01cd: callvirt instance object LinFu.AOP.Interfaces.IInterceptor::Intercept(class LinFu.AOP.Interfaces.IInvocationInfo)
IL_01d2: unbox.any [mscorlib]System.Boolean
IL_01d7: br IL_0245
IL_01dc: nop
IL_01dd: ldarg.0
IL_01de: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_01e3: brfalse IL_023f
IL_01e8: ldarg.0
IL_01e9: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_01ee: callvirt instance bool [System]System.Net.Sockets.Socket::get_Connected()
IL_01f3: brfalse IL_023f
IL_01f8: ldarg.0
IL_01f9: call instance bool Communicator::IsServerInfoReceived()
IL_01fe: brfalse IL_023f
IL_0203: ldarg.1
IL_0204: ldstr "\n"
IL_0209: callvirt instance bool [mscorlib]System.String::EndsWith(string)
IL_020e: brtrue IL_0220
IL_0213: ldarg.1
IL_0214: ldstr "\n"
IL_0219: call string [mscorlib]System.String::Concat(string, string)
IL_021e: starg.s 'request'
IL_0220: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_UTF8()
IL_0225: ldarg.1
IL_0226: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string)
IL_022b: stloc.0
IL_022c: ldarg.0
IL_022d: ldfld class [System]System.Net.Sockets.Socket Communicator::m_Socket
IL_0232: ldloc.0
IL_0233: callvirt instance int32 [System]System.Net.Sockets.Socket::Send(uint8[])
IL_0238: pop
IL_0239: ldc.i4.1
IL_023a: br IL_0240
IL_023f: ldc.i4.0
IL_0240: br IL_0245
IL_0245: nop
IL_0246: ldloc 1
IL_024a: brtrue IL_0299
IL_024f: ldloc 11
IL_0253: brtrue IL_0258
IL_0258: nop
IL_0259: ldloc 11
IL_025d: brfalse IL_0273
IL_0262: ldloc 11
IL_0266: ldloc 2
IL_026a: ldloc 5
IL_026e: callvirt instance void LinFu.AOP.Interfaces.IAfterInvoke::AfterInvoke(class LinFu.AOP.Interfaces.IInvocationInfo, object)
IL_0273: nop
IL_0274: ldloc 12
IL_0278: brtrue IL_027d
IL_027d: nop
IL_027e: ldloc 12
IL_0282: brfalse IL_0298
IL_0287: ldloc 12
IL_028b: ldloc 2
IL_028f: ldloc 5
IL_0293: callvirt instance void LinFu.AOP.Interfaces.IAfterInvoke::AfterInvoke(class LinFu.AOP.Interfaces.IInvocationInfo, object)
IL_0298: nop
IL_0299: nop
IL_029a: ldloc 5
IL_029e: ret
} // end of method
The exception I get on runtime looks like this:
ERROR connecting new socket: System.InvalidProgramException: Invalid IL code in Communicator:sendSilentRequest (string): IL_029e: ret
at Communicator.sendSilentRequest (.Message msg) [0x00000] in <filename unknown>:0
at Communicator.sendPing () [0x00000] in <filename unknown>:0
at Communicator.makeConnection (System.String ip, Int32 port) [0x00000] in <filename unknown>:0
I do not really depend on modifying this specific function and may work-around this somehow, however it would be much nicer this way and I do not want to run into this error on methods as well, especially, if it should be my own fault.
Greetings, looking forward to some answers,
Victor Brekenfeld
The exception occurs while executing the example Interception (MethodReplacement) program
public class SampleInterceptor : IInterceptor
{
public object Intercept(IInvocationInfo info)
{
var methodName = info.TargetMethod.Name;
Console.WriteLine("method '{0}' called", methodName);
object retValue = info.TargetMethod.Invoke(info.Target, info.Arguments); //Throws Exception : "Common Language Runtime detected an invalid program"
return retValue; //retValue is always null
}
}
(Creating a new issue for easy tracking)
The following exception is being shown, while trying to run the sample Interception program:
"JIT Compiler encountered an internal limitation."
Please note that this exception is being thrown from within the following method (class BankAccount):
public void Deposit(int amount)
{
_balance += amount;
Console.WriteLine("Deposited: {0}", amount);
Console.WriteLine("New Balance: {0}", Balance);
}
So, if I comment the above method call (Deposit()) within the Pay() method, the program works fine:
public void Pay(int wage)
{
var currentAmount = wage;
//_checkingAccount.Deposit(currentAmount);
Console.WriteLine("Paid {0} units", wage);
}
However, my intention is to intercept all the methods and get return value correctly from within the target methods (If they are not void). For example:
Let's change the Pay() method to return an int
public int Pay(int wage)
{
var currentAmount = wage;
//_checkingAccount.Deposit(currentAmount);
Console.WriteLine("Paid {0} units", wage);
return wage;
}
And, Intercept the method call and also get the return value correctly from within the intercepted method as follows:
public object Intercept(IInvocationInfo info)
{
var methodName = info.TargetMethod.Name;
Console.WriteLine("method '{0}' called", methodName);
// Replace the input parameter with 42
var result = info.TargetMethod.Invoke(info.Target, new object[]{42});
//Get the return value correctly from the target method.
return result;
}
Right now, the program throws the mentioned exception and hence not able to return correct value.
Using a reflector, I took a look at the post weaven Pay() method, after modifying the Pay() as returning an int. There I found the following codes, alsong with the injected codes
... int amount = wage;
this._checkingAccount.Deposit(amount);
Console.WriteLine("Paid {0} units", wage);
int num2 = wage;
....
return (int) obj2;
//Please note that, the obj2 is never assigned with a value and hence, the postweaven methods always return null. This may give you some clue.
Thanks
I can build the solution, but AOP doesn't work and PostWeaver.exe crashes on simple .NET 4 or 4.5 libraries. The PostWeaveTask crashes as well.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.