I have C# dll that is working good with .NET Framework application.
That Dll provides WCF client.
Problem is that mentioned client does not work as a part of Unity application.
I spent some time trying to understand the problem and here is what I found:
factory's CreateChannel() method returns MarshalByRefObject instead of __TransparentProxy.
I am using System.Reflection to get remote object's properties and invoke them. That approach works perfect for __TransparentProxy. And it does not work at all for MarshalByRefObject instance. __TransparentProxy has all the same properties as the remote object. On the other hand MarshalByRefObject instance does not have any of these properties.
Is there anything I can do in this situation?
UPDATE:
Here is the code sample
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
object[] parameters = new object[]
{
binding,
new EndpointAddress("net.tcp://127.0.0.1:1234/ICP01")
};
Type factoryType = typeof(ChannelFactory<>).MakeGenericType(typeof(IICP01Remote));
ChannelFactory<IICP01Remote> factory = (ChannelFactory<IICP01Remote>)Activator.CreateInstance(factoryType, parameters);
IICP01Remote remote = factory.CreateChannel();
//remote is MarshalByRefObject not a __TransparentProxy
float result = remote.GetValue(1);
factory.Close();
Related
I'm trying to execute a method from an object which is loaded from an assembly that is dynamically generated with CompilerResults.CompiledAssembly. However, I need this assembly to have restricted permissions because the methods it contains have an unexpected behavior.
I've searched a lot and the Microsoft docs suggest to use the security features provided by .NET Framework 4. This is one of the many sources I've read about sandboxing, which uses a different AppDomain with restricted permissions. Theoretically, I can create instances from the class within the assembly that is loaded in the restricted AppDomain and this instance will be considered a remote object.
To use the new object as a reference, a proxy is created internally when you try to access the object if the class extends the MarshalByRefObject class. In my case, the class which extends MarshalByRefObject is at the top of the hierarchy.
A simplified version of the code based on the link I've mentioned before is:
var permissionSet = ...;
var dllPath = ...;
// Create the AppDomainSetup
var info = new AppDomainSetup
{
// Set the path to the assembly to load.
ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
};
var strongName = assembly.Evidence.GetHostEvidence<StrongName>();
// Create the domain
var sandboxDomain = AppDomain.CreateDomain("RestrictedDomain", null, info, permissionSet, new StrongName[] { strongName });
var handle = Activator.CreateInstanceFrom(sandboxDomain, dllPath, "MyNamespace.MyClass");
var myLoadedTypeInstance = handle.Unwrap() as MyClass;
The code above works, the assembly is loaded in the AppDomain (only can do it referencing it's dll location, not it's name). But when I try to use a method from myLoadedTypeInstance with two serializable parameters I get an exception. The call is something like myLoadedTypeInstance.MyMethod(param1, param2) and the exception is:
"Method InitializeLifetimeService is not supported on this proxy, this can happen if the method is not marked with OperationContractAttribute or if the interface type is not marked with ServiceContractAttribute."
Some details:
I don't know if it matters, but the first parameter is an objects which contains a property of type TChannel, created with ChannelFactory<T>.CreateChannel().
It confuses me that the code fails when initializing lifetime service, but if I use RemotingServices.GetLifetimeService(myLoadedTypeInstance) as ILease I can access all the remote object's lifetime info.
I've also tried to treat it as a remote object explicitly using Activator.GetObject() with the URL provided by RemotingServices.GetObjectUri(myLoadedTypeInstance), which is redundant because I end up creating two instances of the object. But it was a desperate move which had the same ending.
I cannot debug this with VisualStudio as it's running in a separate process.
i'm writing an application that uses .net Remoting via MarshalByRefObject.
I can connect and everything works fine for simple things like method calls.
now the problem is, when i try to access properties on an object i received from an earlier call, the property-getters are execute "client"-side, and not inside the host process.
inside these getters i'm using Marshalling on the local process, so they are required to be running on the host process instead of the client.
My question now: is there any specific way to achieve what i'm trying to do, or will i have to go the route and on the host-side write additional methods in the exposed interface and implementing class, that will return the value of the getters?
My code looks like this:
MyApi api = new MyApi();
var channel = new IpcChannel(processId.ToString());
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.On;
RemotingConfiguration.ApplicationName = "MyApi-Server" + processId;
RemotingServices.Marshal(api, "service");
for the host process.
And this is the Client-Side
api = (IMyApi)Activator.GetObject(typeof(IMyApi), "ipc://MyApi-" + process.Id + "/service");
MessageBox.Show(api.GetSomething().Someproperty);
thanks for your help
outch, i'm stupid.
not only the implementation of the interface class should derive from MarshalByRefObject, all the other objects that i'm passing around should too.
I have a WCF Host with something like this:
[ServiceContract]
public interface IMountToOs
{
[OperationContract]
char GetMountDriveLetter();
[OperationContract]
MyTestClass MyTest();
}
public class MyTestClass
{
public string A { get; set; }
public string B { get; set; }
}
Client
private IMountToOs _proxy;
public IMountToOs Proxy
{
get
{
if (_proxy == null)
{
NetTcpBinding binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = TimeSpan.FromMilliseconds(50000);
EndpointAddress address = new EndpointAddress("net.tcp://localhost:1234/MountToOsHost");
//_proxy = new MountToOsClient(binding, address);
ChannelFactory<IMountToOs> factory = new ChannelFactory<IMountToOs>(binding);
_proxy = factory.CreateChannel(address);
}
return _proxy;
}
}
While I can access
MessageBox.Show("Okay - " + Proxy.GetMountDriveLetter());
I can't call this method:
MessageBox.Show("Okay - " + Proxy.MyTest().A);
The complete extension is not working. But only while using it in an extension. Even if I insert a Messagebox in the first line of the extension it is not hit. I don't know why. It seems to run a pre-check and find the call of the custom class which is refused or so...
If I use a winform or so there is no problem.
.net 3.5
curious is that I have a break-point and a message of the hosts side. So I see that the method is not called
Update
now I moved the wcf-call in the Load Method of the extension and get a exception:
System.MissingMethodException: method not found:
"Contracts.Interfaces.MyTestClass
Contracts.Interfaces.IMountToOs.MyTest()".
My winform test and this extension use the same interface so that the method should known from both. no contract or so is outdated
According to what I found here and in the comments of the post: "For creating dynamic service proxy using client channel factory method, you will need datacontracts of the service. If you don't have datacontracts but you have the service URL, then you could use reflection to create proxy at runtime and call the service method."
Seems that the MyTestClass type is not known on the client side, so I think you could use reflection, or share the class between the client and server or much more simple, use the datacontract attribute.
Also, found something on MSDN that says something like this:
"When to use a proxy?
We create proxy using svcutil.exe. The output of this tool gives a proxy class and makes corresponding changes to the application configuration file. If you have a service that you know is going to be used by several applications or is generic enough to be used in several places, you'll want to continue using the generated proxy classes. We use proxy in WCF to be able to share the service contract and entities with the client. Proxies have several restrictions like they need to have gets and sets , contructors can't be exposed , methods other than the service contract cannot be exposed, repetition of code, everytime that we add/modify a service contract/data contract/message contract we need to re-generate the proxy for the client.
When to use ChannelFactory
The other option is using the ChannelFactory class to construct a channel between the client and the service without the need of a proxy . In some cases, you may have a service that is tightly bound to the client application. In such a case, it makes sense to reference the Interface DLL directly and use ChannelFactory to call your methods using that. One significant advantage of the ChannelFactory route is that it gives you access to methods that wouldn't otherwise be available if you used svcutil.exe..
When to use a ChannelFactory vs Proxy class?
A DLL is helpful if the client code is under you control and you'd like to share more than just the service contract with the client -- such as some utility methods associated with entities and make the client & the service code more tightly bound. If you know that your entities will not change much and the client code is less, then a DLL would work better than a proxy. If the client to your service is external to the system, such as API, it makes sense to use a proxy, because it makes sharing the contract easier by giving a code file rather than a DLL."
We cant see the class
MountToOsClient: IMountToOs
So we can only assume it is ok.
[DataContract] // Missing
public class MyTestClass
{
[DataMember] // Missing
public string A { get; set; }
[DataMember] // Missing
public string B { get; set; }
}
MountToOsClient can not expose Mytestclass without these attributes.
I have multiple services in my application. WebService1, WebService2,WebService3 and so on..
All the services have same methods, but they are hosted on different IPs.
Now when a client calls a methodA(1) then
WebService1Client.Method() should be called;
client calls a methodA(2) then WebService2Client.Method() should be called.
I do not want to do a switch case for each and every function on the client.
I would rather prefer to create some class/methods which would return the appropriate proxyClient.
How can I create a class to return the object and further how to use that object.
Please point me to some sample codes or references.
Thanks
If all your services implement the same contract (I mean exactly the same, not a contract with the same methods), you can simply create proxies using the ChannelFactory class and cast the returned object into the contract interface.
This should give you the expected generic behavior.
One way to ensure the same interface is used all over is to put it into a separate class library and share it between all projects. Make sure you configure your service references to reuse types in referenced assemblies.
EDIT: This is how you would use the ChannelFactory, you can get rid of the service reference:
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");
ChannelFactory<IMath> myChannelFactory = new ChannelFactory<IMath>(myBinding, myEndpoint);
I am not quite sure why you want to wrap the creation of the proxies into a factory. The easiest usage pattern is to new the proxy where you need it and each time when you need. When you are not running reliable sessions or something other heavy stuff it does not have much overhead to new a proxy instance. On the other hand it makes sure that you have a connection that is working and that the channel is not in a faulted state.
When using the proxy you should make sure to close it when done and abort it when it throws an exception.
var proxy = new Proxy();
try { proxy.SomeMethod(); }
catch { proxy.Abort(); }
finally { proxy.Close(); }
I have what I thought was a simple .NET Remoting Client/Server (Code Below)... When hosting/running in a Console application it works fine, but when hosted in a Windows Service, all calls to members of proxies returned from Activator.GetObject result in a NullReferenceException.
To simplify things I placed all this in a single Console and it worked fine... Created a basic Windows Service and placed the same code on the OnStart method and once I access the "TheString" property I get a NullReferenceException.
I can confirm there are no other exceptions, the ports are available, and the service is run as an administrator. Also, my solution will require a singleton which is why I am using that.
At the moment this is being hosted on Windows 7 which may be a factor. If I could learn how to see more of what underlying error may be causing this, I may be able to figure it out... How can I see what might be happening underneath (ex. sink, formatter, etc...)?
Server Code:
var provider = new BinaryServerFormatterSinkProvider
{
TypeFilterLevel = TypeFilterLevel.Full
};
IDictionary properties = new Hashtable();
properties["port"] = 20001;
properties["exclusiveAddressUse"] = false;
_channel = new TcpChannel(properties, null, provider);
ChannelServices.RegisterChannel(_channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(HostClass), "TheHost", WellKnownObjectMode.Singleton);
Client Code:
var retInstance = (HostClass)Activator.GetObject(typeof(HostClass),
string.Format("tcp://{0}:{1}/TheHost", "MyHostName", 20001));
string host = retInstance.TheString; //This is where the NullReference is experienced
Remoting Object:
public class HostClass : MarshalByRefObject, IHostClass
{
public HostClass()
{
TheString = "Hello World";
}
public override object InitializeLifetimeService()
{
return null;
}
public string TheString { get; set; }
}
Any ideas would be appreciated.
As it turns out the limitation relates to the remoting engines inability to serialize and proxy interface types, which while not part of my sample (sorry) was ultimately the root of the issue.