I have a basic Contracts project:
[ServiceContract]
public interface IEchoService
{
[OperationContract]
string GetUpper(string text);
[OperationContract]
string GetLower(string text);
}
Service project:
public class EchoService : IEchoService
{
public string GetUpper(string text)
{
return text.ToUpper();
}
public string GetLower(string text)
{
return text.ToLower();
}
}
Self host project:
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
AllTypes
.FromThisAssembly()
.InSameNamespaceAs<IEchoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new NetTcpBinding(SecurityMode.None))
.At(string.Format(
"net.tcp://localhost:10333/MyServices/{0}",
c.Implementation.Name)
)))));
Console.WriteLine("hosting...");
while (Console.ReadKey().Key != ConsoleKey.Q)
{
}
}
When I tried connecting to my service from my client, I get this error msg:
Could not connect to net.tcp://localhost:10333/MyServices/EchoService.
The connection attempt lasted for a time span of 00:00:02.0904037.
TCP error code 10061: No connection could be made because the target
machine actively refused it 127.0.0.1:10333.
So I checked netstat, and found out that my console service, while able to run, isn't even listening on port 10333. I have no other programs using that port, I have even changed to a few other port nubmers, but it just doesn't show up on netstat.
What could be wrong with my console service? or any configuration settings I might have missed out?
Related
I'm new to WCF services, I'm trying to replicate tutorial of "Hosting a WCF Service in a Managed Windows Service":
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-host-a-wcf-service-in-a-managed-windows-service
I managed to create service and its installer (in ServiceProject), I managed to install service with sysutil command. I was able to connect to service from separate console project (let's name it TestProject) and call its functions - it works when I run them from Visual Studio. The problem is: when I'm trying to use executable file of TestProject - it doesn't work. I tried to do it after manually starting service from windows services list, but it just returns error. Can you help me with understanding what I'm doing wrong?
The code I'm trying to run from TestProject looks like this:
static void Main(string[] args)
{
try
{
WinWCFServiceClient client = new WinWCFServiceClient();
client.ShowTextMessageAsync("it works as win service!!!");
}
catch (Exception ex)
{
Console.WriteLine("There were errors");
Console.WriteLine(ex.ToString());
}
Console.WriteLine("The end");
Console.ReadLine();
}
It crushes with exeption looking like this:
? System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
? System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
? System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress) ? System.ServiceModel.ConfigurationEndpointTrait1.CreateSimplexFactory()
? System.ServiceModel.ConfigurationEndpointTrait1.CreateChannelFactory() ? System.ServiceModel.ClientBase1.CreateChannelFactoryRef(EndpointTrait1 endpointTrait) ? System.ServiceModel.ClientBase1.InitializeChannelFactoryRef()
? System.ServiceModel.ClientBase`1..ctor()
? WinWCFServiceClient..ctor() ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\generatedProxy.cs:?????? 35
? CheckWinWCF_NF.Program.Main(String[] args) ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\Program.cs:?????? 16
And my service looks like this:
[ServiceContract]
public interface IWinWCFService
{
[OperationContract]
void ShowTextMessage(string str);
}
public class WinWCFService : IWinWCFService
{
public void ShowTextMessage(string str)
{
MessageBox.Show(String.Format("You send this message {0}:", str));
}
}
Installer part:
public class WinWCFServiceBase:ServiceBase
{
public ServiceHost serviceHost = null;
public WinWCFServiceBase()
{
// Name the Windows Service
ServiceName = "WCFWinServiceRS";
}
public static void Main()
{
ServiceBase.Run(new WinWCFServiceBase());
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(WinWCFService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
private void InitializeComponent()
{
//
// WinWCFServiceBase
//
this.ServiceName = "WinWCFServiceRS";
}
}
What is the problem: System.TimeoutException: 'The request channel timed out while waiting for a reply after 00:00:59.977913. So, basically it can be everything.
What do I have:
I create a simple solution to found a fix. What really make me confused is that console app works just fine, however wpf app with same configuration does not work. Solution include four projects(code made for debugging purpose, please don't judge it):
library with contracts and their implementation.
public class DeviceService : IDeviceService
{
public string GetDevices()
{
return "hello world";
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
library with host.
public class DeviceServiceHostFactory
{
ServiceHost host;
public DeviceServiceHostFactory()
{
ServiceMetadataBehavior metadataBehavior;
BasicHttpBinding binding = new BasicHttpBinding();
Uri address = new Uri("http://localhost:4000/");
host = new ServiceHost(typeof(DeviceService), address);
Type contract = typeof(IDeviceService);
host.AddServiceEndpoint(contract, binding, "");
}
public void Start()
{
host.Open();
}
public void Stop()
{
host.Close();
}
}
desktop app that start service and consume it (does not work)
public partial class MainWindow : Window
{
private DeviceServiceHostFactory _deviceService;
public MainWindow()
{
InitializeComponent();
try
{
_deviceService = new DeviceServiceHostFactory();
_deviceService.Start();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
private void Btn_custom_Click(object sender, RoutedEventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
txt_custom.Text = channel.GetDevices();
Console.WriteLine();
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
console app (works fine)
class Program
{
static void Main(string[] args)
{
DeviceServiceHostFactory _deviceService = new
DeviceServiceHostFactory();
try
{
_deviceService.Start();
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
Console.WriteLine(channel.GetDevices());
Console.ReadLine();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
I really spend a lot of time for this, and I will be very grateful for every solution or thought how can I debug it more advanced.
Hosting wcf service in application with UI is little bit tricky, so I hope this will help someone.
Took it from book Learning WCF: A hands-On Guide By Michele Leroux Bustamante, Chapter 4, so fo more information please find this book.
To host service in Windows application or WPF application, we have to create a new thread to start it in a new synchronization context. It can be done in two ways:
First, is to create service host before the UI thread created. Here service executes in a new synchronization contenxt before application starts.
static class Program
{
static void Main()
{
DeviceServiceHostFactory deviceService = new DeviceServiceHostFactory();
deviceService.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow);
}
}
Second, is to initialize service host on a separate thread, after UI been created
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread;
thread = new Thread(ServiceInitialize);
thread.IsBackground = true;
thread.Start();
}
private void ServiceInitialize()
{
var service = new DeviceServiceHostFactory();
service.Start();
}
}
This means the messages are processed on threads form the thread pool instead of through the message loop.
First, we should give the current account permissions when we occupy the Operation system ports to host services.
This function could be accomplished by the below command.
Netsh http add urlacl url=https://+:80/MyUri user=DOMAIN\user
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
If we don’t want to do this, we could directly run the service with administrator accounts.
Thereby I suspect there is something wrong with the process of hosting the service. Have you tried running the WPF application with an administrator account?
Besides, I suggest you add a namespace in the service contract.
[ServiceContract(Namespace ="MyNamespace")]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
Sometimes, it could run into problems when the service contract doesn’t have a namespace property.
Feel free to let me know if the problem still exists.
Here is a simple Service Fabric stateless service with WCF communication and it's client - a console app. It works well on the local cluster, client gets responce from the service. But I don't know how to communicate with a service if I deploy it in the cloud. What should I do to access it from console app?
SF Stateless service with WCF communications:
Contract:
[ServiceContract]
public interface IPresidentialService
{
[OperationContract]
Task<string> GetInfo();
}
Service:
internal sealed class PresidentialService : StatelessService, IPresidentialService
{
public PresidentialService(StatelessServiceContext context) : base(context)
{
}
public Task<string> GetInfo() => Task.FromResult($"Node {Context.NodeContext.NodeName} operating");
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(context =>
new WcfCommunicationListener<IPresidentialService>(wcfServiceObject: this, serviceContext: context,
endpointResourceName: "WcfServiceEndpoint",
listenerBinding: WcfUtility.CreateTcpListenerBinding()))
};
}
}
}
Client console app:
WCF client:
public class PresidentialServiceClient : ServicePartitionClient<WcfCommunicationClient<IPresidentialService>>
{
public PresidentialServiceClient(
ICommunicationClientFactory<WcfCommunicationClient<IPresidentialService>> communicationClientFactory,
Uri serviceUri, ServicePartitionKey partitionKey = null,
TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null,
OperationRetrySettings retrySettings = null) : base(communicationClientFactory, serviceUri, partitionKey,
targetReplicaSelector, listenerName, retrySettings)
{
}
public Task<string> GetInfo() => InvokeWithRetryAsync(client => client.Channel.GetInfo());
}
Client App:
private static void Main(string[] args)
{
var binding = WcfUtility.CreateTcpClientBinding();
var partitionResolver = ServicePartitionResolver.GetDefault();
var wcfClientFactory =
new WcfCommunicationClientFactory<IPresidentialService>(binding,
servicePartitionResolver: partitionResolver);
var serviceUri = new Uri("fabric:/Application5/PresidentialService");
var client = new PresidentialServiceClient(wcfClientFactory, serviceUri, ServicePartitionKey.Singleton);
do
{
Console.WriteLine(client.GetInfo().Result);
Console.ReadKey();
} while (true);
}
Added to ServiceManifest.xml:
<Endpoints>
<Endpoint Name="WcfServiceEndpoint" />
</Endpoints>
UPDATE
Changed ServicePartitionResolver:
var partitionResolver = new ServicePartitionResolver("sfapp.westeurope.cloudapp.azure.com:19000");
Still not works.
UPDATE
Added a load balancer rule for TCP port 777.
When the service is running in the cloud, you can't use the default resolver.
The default ServicePartitionResolver assumes that the client is
running in same cluster as the service. If that is not the case,
create a ServicePartitionResolver object and pass in the cluster
connection endpoints.
Try something like
ServicePartitionResolver resolver = new ServicePartitionResolver("mycluster.cloudapp.azure.com:19000");
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-wcf
Trying to get a simple demo of NetTcpBinding working in order to expand it into another project.
Architecture: 2 console apps (1 host/server, 1 client) and 1 type library project. Both console apps have a reference to the type library project.
Host application:
class Program
{
static void Main()
{
var netTcpBinding = new NetTcpBinding(SecurityMode.None)
{
PortSharingEnabled = true
};
var netTcpAdddress = new Uri("net.tcp://127.0.0.1:1234/HelloWorldService/");
var tcpHost = new ServiceHost(typeof(HelloWorldService), netTcpAdddress);
tcpHost.AddServiceEndpoint(typeof(IHelloWorld), netTcpBinding, "IHelloWorld");
tcpHost.Open();
Console.WriteLine($"tcpHost is {tcpHost.State}. Press enter to close.");
Console.ReadLine();
tcpHost.Close();
}
}
public class HelloWorldService : IHelloWorld
{
public void HelloWorld()
{
Console.WriteLine("Hello World!");
}
public void WriteMe(string text)
{
Console.WriteLine($"WriteMe: {text}");
}
}
Client application:
static void Main()
{
Console.WriteLine("Press enter when the service is opened.");
Console.ReadLine();
var endPoint = new EndpointAddress("net.tcp://127.0.0.1:1234/HelloWorldService/");
var binding = new NetTcpBinding ();
var channel = new ChannelFactory<IHelloWorld>(binding, endPoint);
var client = channel.CreateChannel();
try
{
Console.WriteLine("Invoking HelloWorld on TcpService.");
client.HelloWorld();
Console.WriteLine("Successful.");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
Console.WriteLine("Press enter to quit.");
Console.ReadLine();
}
Type Library:
[ServiceContract]
public interface IHelloWorld
{
[OperationContract]
void HelloWorld();
[OperationContract]
void WriteMe(string text);
}
I believe I have all necessary services installed and running:
Obviously I'm trying to do all the config at runtime.
I consistently get this error message on the client:
Invoking HelloWorld on TcpService.
Exception: There was no endpoint listening at
net.tcp://127.0.0.1:1234/HelloWorldService/ that could accept the
message. This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. Press enter to quit.
Am I missing something obvious?
Your service is exposing the endpoint at address:
net.tcp://127.0.0.1:1234/HelloWorldService/IHelloWorld
but your client is connecting to:
net.tcp://127.0.0.1:1234/HelloWorldService/
You'll also need to set the client NetTcpBinding SecurityMode the same as the server (None).
When creating a NServiceBus SendOnly endpoint, the purpose is to just fire-and-forget, i.e. just send a message and then someone else will take care of it. Which seems like the thing I need. I dont want any communication between the bus and the system handling messages. System "A" wants to notify system "B" about something.
Well the creation of an SendOnly endpoint if very straightforward but what about the system listening for messages from an SendOnly endpoint.
I'm trying to set up a listener in a commandline project that will handle messages. The messages get sent to the queue but they doesnt get handled by system "B".
Is this the wrong approach? Is a bus overkill for this type of functionality?
System A:
public class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.SendOnly();
while(true)
{
Console.WriteLine("Send a message");
var message = new Message(Console.ReadLine());
bus.Send(message);
}
}
}
System B:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
Console.WriteLine("Waiting for messages...");
while(true)
{
}
}
}
public class MessageHandler : IHandleMessages<Message>
{
public void Handle(Message message)
{
Console.WriteLine(message.Data);
}
}
public class Message : IMessage
{
public Message()
{
}
public Message(string data)
{
Data = data;
}
public string Data { get; set; }
}
In the MessageEndpointMappings you need to update it as follows:
Replace DLL with the name of the assembly containing your messages (e.g. "Messages")
Change the Endpoint to the name of the queue which System B is reading from (You can check the queue name by looking in the MSMQ snapin under private queues).
<add Messages="Messages" Endpoint="SystemB" />
NServiceBus 3 automatically creates the queue name based upon the namespace of the hosting assembly.
Additionally, you may want to look at using the NServiceBus.Host to host your handlers instead of your own console application.