In fact, this is the minimal implementation code for a part of a more complex project.
Due to the type being changed to System.Object, code encountered issues in build 1879.
Actually, I heavily rely on reflection and proxies.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
namespace test1
{
internal class Program
{
static void Main(string[] args)
{
var service = new Service();
var proxy = new Proxy(service);
var interfaceProxy = (IInterface)proxy.GetTransparentProxy();
interfaceProxy.DoSomething();
Console.Read();
}
public class Proxy : RealProxy
{
private IInterface _target;
public Proxy(IInterface target) : base(typeof(IInterface))
{
_target = target;
}
public override IMessage Invoke(IMessage msg)
{
if (msg is IMethodCallMessage methodCall)
{
Console.WriteLine("Proxy is intercepting the method call.");
Console.WriteLine(methodCall.TypeName.ToString());
var result = methodCall.MethodBase.Invoke(_target, methodCall.InArgs);
Console.WriteLine("Proxy has called the service class method.");
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
return null;
}
}
}
public class Service : MarshalByRefObject, IInterface
{
public void DoSomething()
{
Console.WriteLine("Service is doing something.");
}
}
public interface IInterface
{
void DoSomething();
}
}
Proxy is intercepting the method call.
test1.IInterface, test1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Service is doing something.
Proxy has called the service class method.
Protected Result:
Proxy is intercepting the method call.
System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Proxy has called the service class method.
Proxy is intercepting the method call.
test1.IInterface, test1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Service is doing something.
Proxy has called the service class method.
In reality, we dynamically create objects in the Invoke method based on the content of the IMethodCallMessage, rather than having a _target variable as shown in the example. Therefore, when the file is protected, an additional Invoke is triggered to call System.Object’s GetType. This causes our program to run incorrectly, failing to create the correct object. We end up not knowing who to proxy for, as we can’t find the relevant IInterface at that time
Hello Admin, this is a preliminary example. In terms of the direct outcome of the program, it results in inconsistent execution.
In practical processes, we utilize such a method for IoC + Service Locator.
As a result, since GetType runs before the specific class, we are unable to locate the concrete service.
public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage message)
{
System.Runtime.Remoting.Messaging.IMethodCallMessage methodMessage = new System.Runtime.Remoting.Messaging.MethodCallMessageWrapper((System.Runtime.Remoting.Messaging.IMethodCallMessage)message);
System.Reflection.MethodBase method = methodMessage.MethodBase;
if (interfaceType == null) interfaceType = method.DeclaringType;
// becuase addtional System.Object.GetType() called here. it can't find service and unable to initialize service class
// if it's not System.Object.GetType() calling, it should be an Iinterface type and then we can get the actual service class initialized then invoke something..
if (target == null) target = getObject(interfaceType);
// some code to invoke method...
}
Can we avoid the initial System.Object.GetType()?
If it’s unavoidable, as a workaround, could you tell us what to return?
Whether we return typeof(object), typeof(this), or null, it leads to a NullReferenceException.
I understand that we should return an IInterface Type at this point, but since System.Object.GetType is called first, we are unable to determine what the IInterface is.
give me a liitle time, I’ll give you another example later
You can use castclass without virtualization with the following code:
static T CastTo<T>(object obj) where T : class
{
return obj as T;
}
static void Main(string[] args)
{
var service = new Service();
var proxy = new Proxy(service);
var interfaceProxy = CastTo<IInterface>(proxy.GetTransparentProxy());
interfaceProxy.DoSomething();
Console.Read();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Runtime.Remoting;
namespace test1
{
internal class Program
{
static void Main(string[] args)
{
ServiceFactory.RegisterService(typeof(IInterface), typeof(Service));
IInterface service = ServiceFactory.GetService() as IInterface;
service.DoSomething();
Console.Read();
}
public class UniversalServiceProxy : RealProxy, IRemotingTypeInfo
{
public string TypeName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public UniversalServiceProxy() : base(typeof(MarshalByRefObject))
{
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
Type serviceInterfaceType = methodInfo.DeclaringType;
if (!ServiceFactory.IsServiceRegistered(serviceInterfaceType))
{
throw new InvalidOperationException($"No service registered for type {serviceInterfaceType.Name}");
}
Type implementationType = ServiceFactory.GetImplementationType(serviceInterfaceType);
object serviceInstance = Activator.CreateInstance(implementationType);
try
{
Console.WriteLine($"Invoking method {methodInfo.Name} on {implementationType.Name}");
var result = methodInfo.Invoke(serviceInstance, methodCall.Args);
Console.WriteLine($"Method {methodInfo.Name} on {implementationType.Name} invoked successfully");
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
Console.WriteLine($"Exception occurred during invocation: {e.Message}");
return new ReturnMessage(e, methodCall);
}
}
public bool CanCastTo(Type fromType, object o)
{
return ServiceFactory.IsServiceRegistered(fromType);
}
}
public static class ServiceFactory
{
private static readonly Dictionary<Type, Type> _services = new Dictionary<Type, Type>();
public static void RegisterService(Type interfaceType, Type implementationType)
{
_services[interfaceType] = implementationType;
}
public static object GetService()
{
var proxy = new UniversalServiceProxy();
return proxy.GetTransparentProxy();
}
public static bool IsServiceRegistered(Type interfaceType)
{
return _services.ContainsKey(interfaceType);
}
public static Type GetImplementationType(Type interfaceType)
{
return _services[interfaceType];
}
}
}
public class Service : MarshalByRefObject, IInterface
{
public void DoSomething()
{
Console.WriteLine("Service is doing something.");
}
}
public interface IInterface
{
void DoSomething();
}
}
Before protect:
Invoking method DoSomething on Service
Service is doing something.
Method DoSomething on Service invoked successfully
After protect:
System.InvalidOperationException: No service registered for type Object
This example is more closer to our actual situation.
To prevent piracy, we have hundreds of functions that need protection, and if possible, we would prefer to avoid modifying existing code as much as we can. We hope you can provide some suggestions. Thank you!
I tried this one, modified to this: (based on above example)
{
IInterface service = CastTo<IInterface>(ServiceFactory.GetService());
service.DoSomething();
Console.Read();
}
static T CastTo<T>(object obj) where T : class
{
return obj as T;
}
It did work, but since there is already a lot of existing code, (it’s a very large product.) is there a solution that does not involve modifying the existing code?
You still don’t understand what your code does (virtualized “isinst” works like “castclass” and it calls Object.GetType too).
static T CastTo<T>(object obj) where T : class
{
return obj as T;
}
static void Main(string[] args)
{
ServiceFactory.RegisterService(typeof(IInterface), typeof(Service));
IInterface service = CastTo<IInterface>(ServiceFactory.GetService());
service.DoSomething();
Console.Read();
}
The virtual machine calls A() via MethodInfo.Invoke that doesn’t support BindingFlags.DoNotWrapExceptions for .NET Framework. So the class an exception in the “catch” block is wrong (“TargetInvocationException” instead of “CustomException”). The virtualized “A()” will throw correct exception.
I think this is very challenging, as it means more functions require virtualization. For instance, if I need to call a service and catch its various exceptions, it’s not just about virtualizing this function, but also virtualizing the service and its internal call chain.
It’s not only A(), but also A->B->C->D->…
This also means that if we miss adding any function, it could lead to changes in the behavior of the application.
I earnestly request you to make the necessary modifications.
In our code, a function may call different assembly, and the call chain may be very very long.
We indeed need to virtualize the functions, so we can’t remove virtualization.
However, it’s nearly impossible for us to fully apply virtualization to the entire call chain.
Thank you to fix the problem in 1911build. Could you please also send the fixed build to …
Which is also the registered user email, it’s my employer.
Thank you very very very much!!!