We have the following code...
DiscoveryService.cs
[ServiceContract]
public interface IDiscoveryService
{
[OperationContract]
void PrintHello();
}
public class DiscoveryService : IDiscoveryService
{
public void PrintHello()
{
MessageBox.Show("Hello");
}
}
Server.cs
private void InitializeDiscovery()
{
Uri baseAddress = DiscoveryHelper.AvailableTcpBaseAddress;
ServiceHost host = new ServiceHost(typeof (DiscoveryService), baseAddress);
host.EnableDiscovery();
host.Open();
}
Client.cs
private void DiscoverAddressClick(object sender, EventArgs e)
{
EndpointAddress address = DiscoveryHelper.DiscoverAddress<IDiscoveryService>();
Binding binding = new NetTcpBinding();
IDiscoveryService proxy = ChannelFactory<IDiscoveryService>.CreateChannel(binding, address);
proxy.PrintHello();
(proxy as ICommunicationObject).Close();
}
Now, this code seems to work up until the point where we modify anything having to do with the Service Contract, at which point we get a TCP Exception, Error Code 10061 (Connection Actively Refused). However, we cant figure out who is refusing, or why. If we try to revert our code to a previous state, when it was working, we can't, it simply refuses to work after (it seems) we add / remove things from the project.
Every time I build I clean first. We're also following the instructions posted here.
Any thoughts?
I will begin by stating that I'm not all that familiar with WCF Discovery....though I may implement it in our new server stack. But one thing I do not see here is the presence of a proxy server in what you present here.
As I understand it from what I've read on MSDN your WCF service will basically register it's presence to a proxy server running on the network. Your client will then 'discover' your service server via the DiscoveryProxy server. That may be the piece of the plumbing you are missing.
You current implementation of the server will close down the server as soon as the InitializeDiscovery Method is complete because your host only has function scope and will be cleaned up by the garbage collector unless you keep a reference somewhere else.
Related
I am trying to extend an application which supports COM/ActiveX objects. The COM dll needs to send some data to other system on local network for further processing and actions.
I have tested a basic WCF Host-Client setup and it works fine from console client to console host. But now I need to send data through a client in com-visible dll.
This is the code of the dll :
namespace Client
{
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
[ComVisible(true)]
public interface ISend
{
[DispId(1)]
bool SendData(string msg);
}
[ClassInterface(ClassInterfaceType.None), Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), ProgId("Client.Send")]
[ComVisible(true)]
public class Send : ISend
{
static BasicHttpBinding binding = new BasicHttpBinding();
static EndpointAddress endpoint = new EndpointAddress(new Uri("http://192.168.1.6:8000/WCFHost/Service/GetData"));
GetDataClient client = new GetDataClient(binding, endpoint);
[ComVisible(true)]
public bool SendData(string msg)
{
try
{
if (client.getData(msg))
{
client.Close();
return true;
}
else
{
client.Close();
return false;
}
}
catch (Exception e)
{
client.Abort();
return false;
}
}
}
}
The dll works fine as a reference but cannot create object through target application(It has the functionality to access COM/ActiveX objects). When I try to access the dll by :
obj = CreateObject ("Client.Send");
obj.SendData("Hello")
It says :
COM/object handle is null
on second line nothing more!
I created a com-visible dll in similar way using Remoting to achieve this and it worked like a charm. But now its not working as a WCF Client.
It would be really appreciated if someone could point out what I am doing wrong.
I had moved to Remoting where this was not a problem, but I was suggested to stay away from it and achieve this through WCF.
P.S : I am new to C# so please excuse any stupid mistakes.
COM does not support static methods, see here for further details. You'll need to remove the static keyword from the class in order to let your client create an instance. This will also allow you to implement the interface, which is not possible for static classes.
As a side note, your code shouldn't even compile, since the static modifier on an interface is illegal. Remove it as well, then recompile and re-register your DLL.
I have a very complex scenario in which my services are dynamically loaded and everything is done programmatically. In particular I have a service that has 2 endpoints
net.pip://localhost/test
net.pipe://localhost/test/mex
I have a client that access this without issue as well as the WCF Test Client tool.
I am trying to access the service from the selfhost wrapper. I have read you just treat it as a client and create a factory and channel but something is preventing this from working. The same code that works on the client will not work in the wrapper. The code just
private IAgentBase GetLocalClient(string serviceEndpointName)
{
var factory = new ChannelFactory<IAgentBase>(serviceEndpointName);
return factory.CreateChannel();
}
This does return a proxy and then I call a method on the service...
var proxy = GetLocalClient("net.pipe://localhost/test");
proxy.DoThis();
But the code just goes someplace - keeps running and no error. The statement never completes. When I step over that line or set a BP or a try catch, it never completes the method call
Change your GetLocalClient to the following
public IAgentBase GetlocalClient(string ed)
{
EndpointAddress edi = new EndpointAddress(ed);
var channel = ChannelFactory<IAgentBase>.CreateChannel(new NetNamedPipeBinding(), edi);
return channel;
}
Most of the examples I've found for SignalR are assuming ASP.NET (MVC or not). I'm using NancyFX. I'm having just one problem, so I'm hoping there's something I'm overlooking or some thing I need to do in Nancy to compensate for not being ASP.NET.
My one goal is to be able to notify the client browsers when a server event happens. I don't plan on replacing my Nancy routes with hub methods. But I would like the ability to call into the browser from my routes (actions).
I have very simple Hub that I created following the example in the SignalR Wiki. I'm not even sure I need it, since I don't plan on calling client to server.
public interface IUserNotifier
{
void Start();
void Notify(object #event);
}
I used an interface in hopes that I would be able to inject the same hub later on to use in my nancy routes... I'm not sure that is in the cards.
[HubName("userNotifier")]
public class UserNotifier : Hub, IUserNotifier
{
public void Start()
{
Notify(new {Status = "Started"});
}
public void Notify(object #event)
{
Clients.notification(#event);
}
}
When I have the following code in my html file, I can see that it executes the Start() method, and then the Notify() method, delivering content to my client.
var communicator = $.connection.userNotifier;
$.extend(communicator, {
Notification: function(event) {
alert("notification received from server!");
console.log(event);
}
});
$.connection.hub.start()
.done(function() {
communicator.start();
});
Like I said, "starting" the hub works and sends a notification to the client. Very cool. But, then, my primary goal hasn't been accomplished yet. I need to initiate these notifications from other places in my code where they might not be directly associated with a "request".
I tried injecting my IUserNotifier in my nancy modules for use in the routes, but when the Notify() is fired, I get:
That's because the Clients property on the Hub base class is null (hasn't been initialized). So, I switched gears. I tried to follow multiple examples, including the example from the wiki page about hubs in the section called "Broadcasting over a Hub from outside of a Hub":
public class NotifierModule : NancyModule
{
public NotifierModule(){
Get["/notify/{message}"] = p => {
var context = GlobalHost.ConnectionManager.GetHubContext<UserNotifier>();
context.Clients.notification(new { Message = p.message });
};
}
}
My Nancy route executes without throwing errors. Except my browser never receives the message. If I set a breakpoint in the route, I can see that Clients is initialized. Maybe the collection of clients is initialized but empty. Who knows? Maybe you do. :)
Again, my main goal is to be able to send events/notifications to the browser from anywhere in my code, any time. Is that too much to ask? What should I be doing here?
I'm sure you must have found the answer already. However, I figured I could try and help out in case anyone else runs into a similar problem. In order for your server on the .NET side to send messages to clients, it would also need to have a connection made to the hub.
var connection = new HubConnection("http://localhost/");
connection.Start();
connection.Notify("Hello");
Check out an official example at:
https://github.com/SignalR/SignalR/blob/master/samples/Microsoft.AspNet.SignalR.Client.Samples/Program.cs
I'm hosting WCF as Widnows Service but I have a problem with handling Faulted state of WCF channel. Faulted event on ServiceHost never rise up.
Hosting application:
protected override void OnStart(string[] args)
{
_serviceHost = new ServiceHost(typeof(WCF_FaultTest.Service1));
_serviceHost.Faulted += _serviceHost_Faulted;
_serviceHost.Open();
}
void _serviceHost_Faulted(object sender, EventArgs e)
{
// never raise up..
}
Faulted state I try to simulate like this:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService1
{
public string GetFault()
{
throw new Exception("Should went to fault..");
}
Do I using it correctly? Thank you.
You are using more than one CommunicationObject. When you throw the exception in your service implementation the channel is faulted, but the host it is not. The ServiceHost.Faulted event does not apply in this case.
One thing to remember is that once a CommunicationObject enters the faulted state, it can no longer be used. The only thing to do with a faulted CommunicationObject is to close/abort. After your service throws the exception, if you create a new channel you can still call the service. Therefore the service is not faulted.
From an architecture point of view, a service host event is not the "right" place to implement error handling. In general you want error processing to be part of the service configuration. For example error handling in a ServiceHost event doesn't easily move to IIS hosting. Your comment makes it sound like IErrorHandler didn't meet your requirements. What requirement are you trying to implement?
I'm modifying the code in this tutorial to build some basic subscribe push wcf client/server classes, and I've just hit a bit of a brick wall.
The server class in the tutorial is created using the following code:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IStringReverser),
new NetNamedPipeBinding(),
"PipeReverse");
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
host.Close();
}
}
}
Which I assume publishes an instance of StringReverser my problem is I need a reference to that instance so I can call a method on it to push data back to the client.
In the tutorial the server just replies to the client using a callback method, instead I'm storing a reference to the client in a list of subscribers. When I need to push data back to the clients I need a reference to the Service object so I can actually utilize do the callback.
Is there a way to publish a Service using WCF that lets you have a reference to the service object? or can I get a reference to the service object from the host object?
Any help would be appreciated...
You can use the singleton pattern in your StringReverser class and pass the instance of it to the ServiceHost constructor:
ServiceHost host = new ServiceHost(
StringReverser.Instance,
new Uri[]{new Uri("net.pipe://localhost")}
);
I agree that Julien's answer is the correct approach, but it is incomplete (at least for .NET 4.5). After you pass in the instance of the service, you have to set the instance context mode for the ServiceHost to Single. If you don't do that, you'll get an error when the ServiceHost Open() method is called.
The way to set the context mode was not at all obvious. Here is a fragment from one of my programs, taken from a different SO answer:
var baseAddress = new Uri("http://localhost:15003/MockGateway");
using (var host = new ServiceHost(new MockGatewayService(), baseAddress))
{
// Since we are passing an instance of the service into ServiceHost (rather
// than passing in the type) we have to set the context mode to single.
var behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
// Continue to use the service here. If you ever need to get a reference
// to the service object you can do so with...
MockGatewayService myService = host.SingletonInstance as MockGatewayService;
// ...
}
in your servicecontract you can call
OperationContext.Current.GetCallbackChannel());
in any method that is called after the service connects, and then pass it out of the service contract. I typically have a join method where I get a guid for the client and grab the callback there. This is harder than it seems. You either need a singleton/global variable to get it out (easy), or you need to make it so that WCF can use parameterized constructors (hard). For the latter, more correct way of doing it, you need to roll your own classes that implement IInstanceProvider and IEndPointBehavior and add your behavior to the endpoint you are interested in. This has the added benefit of allowing you to use different constructors with different endpoints without redefining your contract. There is unfortunately no typesafe way to do this as you will have to use reflection. Sorry I can't provide a sample, but everything I have is proprietary.