I have an interface in C#, something like this:
interface ITest
{
int Method1(int something);
}
All methods have parameters of basic types (integer, string, enum).
Now I want the implementation and the client to run on different machines communicating over a socket. What I could do manually is to make an implementation like this:
class Test : ITest
{
int Method1(int something)
{
m_Serializer.Serialize(something, m_Socket);
int result = (int)m_Serializer.Deserialize(m_Socket, typeof(int));
return result;
}
}
Is there a way to automate it, i.e. to generate such a wrapper for a given interface automatically?
I could generate it manually via Reflection.Emit, but that's quite complex. Any easy way?
WCF (Windows Communication Foundation) would be what you're looking for. It does pretty much exactly this - it does however have a somewhat steep learning curve.
I like to think of it as a framework that automatically generates a network "protocol" that is defined by your interface - the service contract. The "protocol" is also independent of the underlying network transport - there are bindings for raw TCP, HTTP, HTTPS, all with different use cases in mind.
You never have to actually care about what the network traffic actually looks like at the protocol or byte level - the whole lot is done for you seamlessly.
Clever stuff, worth learning.
Complete example of a WCF client and server over plain TCP, with no config files (all programmatic)
Create a class library which will be shared between two other programs, your client and server, containing an interface.
[ServiceContract]
public interface IMyApi
{
[OperationContract]
string SayHello(string s);
}
In program one, the server:
Add a reference to the class library above.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyApi : IMyApi
{
public string SayHello(string s)
{
return "Hello " + s;
}
}
static void Main()
{
var api = new MyApi();
var svcHost = new ServiceHost(api, new Uri("net.tcp://localhost:12345/MyService"));
svcHost.Open();
Thread.CurrentThread.Join();
}
Program two, the client:
Add a reference to the class library above.
static void Main()
{
var binding = new NetTcpBinding();
var endpoint = new EndpointAddress("net.tcp://localhost:12345/MyService");
var cf = new ChannelFactory<IMyApi>(binding, endpoint);
var client = cf.CreateChannel();
Console.WriteLine(client.SayHello("Tom")); // output on the console should be "Hello Tom"
}
While you could just serialize the data yourself (see Serialization) and deserialize on the other side, there are better options.
Windows Communication Foundation is a technology in the .NET framework which handles this for you. It automatically manages all of the communication (sockets) as well as the transfer of objects across multiple transport technologies.
Related
As .NET Remoting has been removed from .NET Core framework, I tried to use NetTcpBinding from the WCF library, but it's not included in .NET Core.
Is there some other analog of TCPChannel that I can use?
I would try to adopt a different RPC framework instead - ideally a platform-neutral one instead of one which is tightly coupled to .NET.
There are lots of options available. Just off the top of my head:
You could implement a Web API using ASP.NET Core, probably (but not necessarily) with a JSON payload.
You could use gRPC, probably (but not necessarily) using Protocol Buffers as the payload
You could use Thrift
Those are just examples - there are an awful lot of RPC and RPC-like frameworks available. None of these will be as "transparent" as using remoting, but:
They'll make it a lot clearer when you're making a network call
They'll allow you to evolve between service versions more easily
They'll allow you to use a mixture of platforms for servers and clients - which you may not need right now, but is good for future-proofing
If you have a large codebase that is based on .NET Remoting, then switching to WebAPI or gRPC could lead to rewrite half of your application.
CoreRemoting (MIT licensed) may be an alternative: https://github.com/theRainbird/CoreRemoting
It makes is possible to migrate .NET Remoting based Client/Server applications to .NET Core / .NET 5.
In contrast to gRPC or WebAPI, the procedure for CoreRemoting is very similar to .NET Remoting. Only remote method calls are made between .NET objects. A conversion of the calls to HTTP calls (building URLs with string concatenation) as with WebAPI is not necessary. Interfaces between client and server are defined in shared .NET assemblies instead of in a special interface language as with gRPC. Events and callbacks are supported out-of-the-box and can be used in a natural way for a C# developer (Compared to gRPC's more complex streaming approach).
The following example shows how a simple client/server chat application can be created using CoreRemoting.
Shared Contract Assembly
namespace HelloWorld.Shared
{
public interface ISayHelloService
{
event Action<string, string> MessageReceived;
void Say(string name, string message);
}
}
Server
using System;
using CoreRemoting;
using CoreRemoting.DependencyInjection;
using HelloWorld.Shared;
namespace HelloWorld.Server
{
public class SayHelloService : ISayHelloService
{
// Event to notify clients when users post new chat messages
public event Action<string, string> MessageReceived;
// Call via RPC to say something in the chat
public void Say(string name, string message)
{
MessageReceived?.Invoke(name, message);
}
}
public static class HelloWorldServer
{
static void Main(string[] args)
{
using var server = new RemotingServer(new ServerConfig()
{
HostName = "localhost",
NetworkPort = 9090,
RegisterServicesAction = container =>
{
// Make SayHelloSevice class available for RPC calls from clients
container.RegisterService<ISayHelloService, SayHelloService>(ServiceLifetime.Singleton);
}
});
server.Start();
Console.WriteLine("Server is running.");
Console.ReadLine();
}
}
}
Client
using System;
using CoreRemoting;
using HelloWorld.Shared;
namespace HelloWorld.Client
{
public static class HelloWorldClient
{
static void Main(string[] args)
{
using var client = new RemotingClient(new ClientConfig()
{
ServerHostName = "localhost",
ServerPort = 9090
});
client.Connect();
// Create a proxy of the remote service, which behaves almost like a regular local object
var proxy = client.CreateProxy<ISayHelloService>();
// Receive chat messages send by other remote users by event
proxy.MessageReceived += (senderName, message) =>
Console.WriteLine($"\n {senderName} says: {message}\n");
Console.WriteLine("What's your name?");
var name = Console.ReadLine();
Console.WriteLine("\nEntered chat. Type 'quit' to leave.");
bool quit = false;
while (!quit)
{
var text = Console.ReadLine();
if (text != null && text.Equals("quit", StringComparison.InvariantCultureIgnoreCase))
quit = true;
else
{
// Post a new chat message
proxy.Say(name, text);
}
}
}
}
}
CoreRemoting is only working from .NET to .NET. If you need to communicate with Javascript, Java, Python, ..., then it is not the right tool.
But if you only want to do RPC in a pure .NET environment and you want to do it in a comfortable way, thean CoreRemoting may be very helpful.
I would like to note that I am the developer of the CoreRemoting project.
I'm trying to figure out if there's a way to "Find all references" (using the VS feature, as opposed to Control+F entire solution). when it comes to WCF Data and OperationContracts. In case that is unclear:
namespace WcfTestReferences
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello world");
DoStuff();
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
var results = client.GetData(42);
Console.WriteLine(results);
}
static void DoStuff() { }
}
}
namespace WcfTestReferences.WCFApp
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
}
Solution looks like this:
Now, if I look at DoStuff() with code lens, I can see that it in fact has a reference to it:
But the same does not hold true for the methods being called in the wcf service:
In the above, the only references to the interface/method is the interface/method. I understand that the reference that I was hoping would be there (from the main method):
var results = client.GetData(42);
is not there, because the client is generated, and is not actually my Service1 implementation... but is there a way to change this?
In the real world, we have a WCF layer with thousands of methods, many of which are not used - but I cannot rely on Code Lens/Find all references to make this determination. Is there any way to change this behavior?
because the client is generated, and is not actually my Service1
implementation
This is the root of the problem.
You are correct - there is no way for your code analyser to determine that the GetData() call you are making from your client is semantically the same thing as the GetDate() service operation you have defined on your interface, because from a binary perspective they are defined in two completely different types.
The root of this is that you're using a service reference. WCF provides service references as the default way of connecting to a service, but in my opinion service references are problematic and should be avoided.
Luckily, WCF provides another way of consuming and calling a service via the user of ChannelFactory<T>. One of the many benefits you will get when using this instead of a service reference is that your client will have use of the service interface via a binary reference to the assembly containing your service definition.
This will allow tools like code lens to resolve references to your interface methods directly to your consuming clients.
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 need some advice on what's the best way to create WCF client proxy wrapper for ASP .NET client. I want to work equally well with ObjectDataSource control with no extra coding and also when I need to manually call WCF service to get some data. I basically have come up with two models, but I'd like to know which is is more efficient.
Here is the first client wrapper
public class Facade1 : IDisposable
{
private readonly IClient proxy = ClientProxyFactory.GetObject<IClient>();
public List<string> GetData()
{
proxy.GetData()
}
public List<string> GetMoreData()
{
proxy.GetMoreData()
}
public void Dispose()
{
ClientProxyFactory.CloseChannel(this.proxy);
}
}
Now here is another WCF wrapper.
public class Facade2
{
public List<string> GetData()
{
IClient proxy = ClientProxyFactory.GetObject<IClient>();
try
{
return client.GetData();
}
finally
{
ClientProxyFactory.CloseChannel(proxy);
}
}
public List<string> GetMoreData()
{
IClient proxy = ClientProxyFactory.GetObject<IClient>();
try
{
return client.GetMoreData();
}
finally
{
ClientProxyFactory.CloseChannel(proxy);
}
}
}
In the first example, there is only one instance of the client proxy and it can be reused between various methods, but the class needs to implement IDisposable so that the proxy can be correctly disposed by the client. In the second example, there is one client proxy per method and the client does not have worry about disposing the proxy.
Is reusing proxy between different method a good way to go? Is there performance hit when you open/close WCF proxy? (In both examples, assume that ChannelFactory is cached and new channel is created every time via cached_factory.CreateChannel() method.)
For example, with the first wrapper I can do something like:
using (Facade1 facade = new Facade1())
{
facade.GetData()
...
...
facade.GetMoreData()
}
In the second example, I can just instantiate my facade and call the needed methods without worrying about disposing a proxy.
Thanks in advance,
Eric
If you use this wrapper for multiple calls to WCF service in single HTTP request processing in your ASP.NET application than the model with shared proxy is better. If you want to share the wrapper (make it global) then second model should be used.
Performance of recreating a proxy is dependent on type of used binding and its configuration. For example in case of BasicHttpBinding recreation of a proxy can be quick because there can still exists persistant HTTP connection from previous proxy. But in case of WSHttpBinding with security context, recreation of proxy means new security handshake for estabilishing security session.
We are using WCF for communication between a client and a server application. The client application has many features that requires communication to the server - and we have chosen to implement this in multiple classes (seperation of responsability)
For the time, we are creating new WCF endpoints and service contracts for each object - Invoicing, Accounting, Content Management, etc. This causes a lot of endpoint configuration both on the client and server (with potential misconfiguration problems when moving into the test and production platforms).
I would like to know if I can define a single WCF endpoint that can deliver multiple service contact implementations. Our configuration files would then contain a single endpoint (to the service factory) and I can request different services by specifying the interface of the service I am interested in.
e.g.
using (IServiceClientFactory serviceClientFactory = new RealProxyServiceClientFactory())
{
// This is normal WCF proxy object creation.
IServiceFactory serviceFactory = serviceClientFactory.CreateInstance<IServiceFactory>("");
// This is what we would like to do
IInvoiceService invoiceService = serviceFactory.getService(typeof(IInvoiceService));
invoiceService.executeOperation(data);
}
The clue being a single endpoint configuration per client/server pair, instead of an endpoint configuration per service contact I would like to make available.
Is this possible?
I'm not 100% clear on what you're trying to do, but if you just want to be able to host different contracts on the same address with the implementation inside one service class, this is completely possible. To share an endpoint address, you must ensure that you use the same binding instance for each service endpoint.
Here is a complete sample which defines 3 contracts, 1 service class which implements all of them, and a ServiceHost with the 3 contract endpoints at the exact same address:
using System;
using System.ServiceModel;
[ServiceContract]
interface IContractA
{
[OperationContract]
void A();
}
[ServiceContract]
interface IContractB
{
[OperationContract]
void B();
}
[ServiceContract]
interface IContractC
{
[OperationContract]
void C();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Service : IContractA, IContractB, IContractC
{
public Service()
{
}
public void A()
{
Console.WriteLine("A");
}
public void B()
{
Console.WriteLine("B");
}
public void C()
{
Console.WriteLine("C");
}
}
class Program
{
public static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/Service/");
ServiceHost host = new ServiceHost(new Service(), address);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(IContractA), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractB), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractC), binding, string.Empty);
host.Open();
IContractA proxyA = ChannelFactory<IContractA>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyA.A();
((IClientChannel)proxyA).Close();
IContractB proxyB = ChannelFactory<IContractB>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyB.B();
((IClientChannel)proxyB).Close();
IContractC proxyC = ChannelFactory<IContractC>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyC.C();
((IClientChannel)proxyC).Close();
host.Close();
}
}
I doubt that this would work. Xml serialization might be the biggest problem here.
Also I don't think you actually need it. If I was in your shoes I would try and abstract my communication with the service. Basically you would always send a "Message" to the service, which has a "Target" being one of the classes you wanted to access. The service would always reply with a "Response", of which the contents would be filled by the class the "Message" was send to.
Another approach would be to route all these messages trough a service that would echo the request to the appropriate service. This way you keep scalability up, but it does still have a large configuration burden.
HTH.
Sounds like you want to keep your seperate services but have some kind of bus that routes is throught. MSMQ maybe, then you can have one services that takes every message pops it onto a specific queue and then a dedicated service can read that off that particular queue.
Not really a WCF based solution though admittedly.
The notion of a single interface(read as ServiceContract) implemented by multiple classes wont work. So you'd need one 'monster' service that implements all and routes through to the correct service. Facade pattern springs to mind.