The contract type HelloIndigo.Service is not attributed with
ServiceContractAttribute. In order to define a valid contract, the
specified type (either contract interface or service class) must be
attributed with ServiceContractAttribute.
I build a library class and referenced to the class in the console application.
The library class:
namespace HelloIndigo
{
public class Service : IHelloIndigoService
{
public string HelloIndigo()
{
return "Hello Indigo";
}
}
[ServiceContract(Namespace = "http://www.thatindigogirl.com/samples/2006/06")]
interface IHelloIndigoService
{
[OperationContract]
string HelloIndigo();
}
}
The console application:
namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(HelloIndigo.Service),
new Uri("http://localhost:8000/HelloIndigo")))
{
host.AddServiceEndpoint(typeof(HelloIndigo.Service),
new BasicHttpBinding(),"Service");
host.Open();
Console.WriteLine("Press enter to terminate the host service");
Console.ReadLine();
}
}
}
}
When you add the endpoint, you should supply the interface that is the contract:
host.AddServiceEndpoint(typeof(HelloIndigo.IHelloIndigoService),
new BasicHttpBinding(),"Service");
Related
I have the following complete program (which can be copy-pasted-built-and-run. you might have to add a few references). The objective of the program is for the service to detect (e.g. receive a SocketException or IOException of some form or as attempted in the code via some event handling) that a connected client (tested/test from web-browser) has disconnected before the response has been fully delivered (see return statements in method Talk(string animal)). To reproduce the issue, there is a configurable parameter (see new AnimalTalkService(3)) which dictates how long the service will take to respond to a given request. And within this time frame, i can close the browser in order to raise the client-disconnection event (see method ClientDisconnected() in class ClientConnectionTracker). I am unable to get any exceptions thrown into the implementation of the service or get the Closed and Faulted events triggered. Would someone have an idea on how to go about to (implement) get the desired effect?
// Code:
using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Threading;
namespace TestClientDisconnect
{
class ClientConnectionTracker : IChannelInitializer
{
public void Initialize(IClientChannel channel)
{
channel.Closed += ClientDisconnected;
channel.Faulted += ClientDisconnected;
}
private void ClientDisconnected(object sender, EventArgs e)
{
Console.WriteLine("Client Disconnected");
throw new NotImplementedException();
}
}
class ClientConnectionTrackerEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ChannelDispatcher.ChannelInitializers.Add(new ClientConnectionTracker());
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
[ServiceContract]
interface IAnimalTalkService
{
[OperationContract]
[WebInvoke(UriTemplate = "/{animal}", Method = "GET")]
string Talk(string animal);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class AnimalTalkService : IAnimalTalkService
{
private int delayInSeconds;
public AnimalTalkService(int delayInSeconds = 0)
{
this.delayInSeconds = delayInSeconds;
}
public string Talk(string animal)
{
Console.WriteLine("Creating sentence for animal {0} ...", animal);
if (delayInSeconds > 0)
{
// Simulate heavy duty work:
Thread.Sleep(1000 * delayInSeconds);
}
switch(animal.ToLower())
{
case "sheep":
return "baa";
case "dog":
return "woof";
case "cat":
return "miao";
default:
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
AnimalTalkService serviceInstance = new AnimalTalkService(3);
Uri address = new Uri("http://127.0.0.1:1234/");
WebServiceHost host = new WebServiceHost(serviceInstance, address);
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(IAnimalTalkService), binding, "");
endPoint.EndpointBehaviors.Add(new WebHttpBehavior() { DefaultOutgoingResponseFormat = WebMessageFormat.Json });
endPoint.EndpointBehaviors.Add(new ClientConnectionTrackerEndpointBehavior());
host.Open();
Console.WriteLine("Service is running at {0}. Press Enter key to exit", host.BaseAddresses[0]);
Console.ReadLine();
}
}
}
Thanks in advance.
The word "disconnection" implies a session, isn't it?
The best way, in my opinion, to have methods, that explicitly creates and terminates the session using an explicit session id (here I used an arbitrary type):
[ServiceContract]
public interface IWebService
{
[OperationContract]
SessionId BeginNewSession();
[OperationContract]
void DoSomething(SessionId id, ...);
[OperationContract]
void EndSession(SessionId id);
}
This is certainly recommended for HTTP protocol, which doesn't support transport-level sessions.
In this case you can write another class, that will housekeep outdated sessions which haven't been closed.
In case you use a binding that supports transport-level sessions, there is another option - to set up session-bound service instance management (and use corresponding binding), implement IDisposable interface in the service class and place the related code inside Dispose() method:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TheService : IService, IDisposable
{
...
public void Dispose()
{
// code of session termination
...
}
}
Finally you can combine both options by marking the explicit session-terminating method with [OperationContract(IsTerminating = true)] attribute:
[ServiceContract(..., SessionMode=SessionMode.Required)]
public interface IService
{
[OperationContract(IsTerminating = true)]
void Close();
...
}
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).
A WCF file.
namespace DatabaseTransferViaWcf
{
[ServiceContract]
public interface IService1
{
[OperationContract]
int generateId();
}
}
The corresponding file.
namespace DatabaseTransferViaWcf
{
public class Service1 : IService1
{
public int generateId()
{
return 5700 ;
}
}
}
I added them to my WPF Project as a service reference called "SendRecieveData".
How I am trying to use it.
public partial class Transfer : Window
{
private void button9_Click(object sender, RoutedEventArgs e)
{
ServiceHost host = null;
try
{
using (ServiceHost host = new ServiceHost(typeof(SendRecieveData.Service1)))
{
host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <enter /> to terminate service.");
Console.ReadLine();
}
wcfHostId = wcf.generateId();
textBox5.Text = "" + wcfHostId;
}
catch (Exception ex)
{
MessageBox.Show("Error = " + ex.Message);
}
}
}
It says I am missing a reference to Service1 but all the tutorials and blogs I have looked at don't have any more steps to them.
WPF application is a client of your service so you shouldn't use ServiceHost class. It is used if you want to host a service within your application. It is not your case. In your situation you should just use a proxy generated automatically when you added a service reference to your project.
Your service reference has not been added correctly. Try removing it and make sure you name it Service1 and not Service1Service or something similar.
EDIT:
Try something like
Service1Client service1Client = new service1Client();
Console.WriteLine(service1Client.generateId());
It is usually how the services are named.
I've been doing some research on this and I got nothing.
I have a server and client.
My client does request to the server and the server runs some callbacks.
This works fine.
But now, there are some functions from the clients I need to call from the server and are not a result of a client call so I can't use callbacks there.
I'm using WCF and .net 4.0
Any suggestions?
CLIENT:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.IO;
using System.Collections;
namespace WCFClient
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(ICallbacks))]
public interface IMessageHandler
{
[OperationContract]
void HandleMessage();
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void QueuePaths_Callback(string cPath, string EPath, string RPath, string IPath, string OPath);
}
public class Callbacks : ICallbacks
{
public void QueuePaths_Callback(string cPath)
{
Console.WriteLine("QueuePaths_Callback: " + cPath);
}
}
class Program
{
static void Main(string[] args)
{
Callbacks myCallbacks = new Callbacks();
DuplexChannelFactory<IMessageHandler> pipeFactory =
new DuplexChannelFactory<IMessageHandler>(
myCallbacks,
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeReverse"));
IMessageHandler pipeProxy =
pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
pipeProxy.HandleMessage();//send the type for example
}
}
public void IWANTTOCALLTHISFROMSERVER()
{ }
}
}
SERVER:
namespace WCFServer
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(ICallbacks))]
public interface IMessageHandler
{
[OperationContract]
void HandleMessage();
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void QueuePaths_Callback(string cPath);
}
public class StringReverser : IMessageHandler
{
public void HandleMessage()//handle the type and do the request
{
ICallbacks callbacks = OperationContext.Current.GetCallbackChannel<ICallbacks>();
callbacks.QueuePaths_Callback("path1");
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IMessageHandler),
new NetNamedPipeBinding(),
"PipeReverse");
host.
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
//BLA BLA BLA
//CALL IWANTTOCALLTHISFROMSERVER();
host.Close();
}
}
}
}
If you want to inform client that something happened on the server you're looking for Duplex Service.
In full .net you have 2 options for bindings:
netTcpBinding
wsDualHttpBinding
netTcpBinding is much better since it doesn't require the client to open port (wsDualHttpBinding does require it).
To be honest the best binding is PollingDuplexHttpBinding that is only available for silverlight. However, it is not that hard to emulate it using basicHttpBinding.
The topic is quite broad so I recommend further reading.
The following code uses the Castle Windsor 3.0's WCF Integration Facility to register a WCF self-hosted service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWcfSession(),
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new BasicHttpBinding()).At("basic"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}
Trying to invoke the SayHello method using WcfTestClient.exe results in the following error:
Could not obtain scope for component SelfHost.PerSession. This is most
likely either a bug in custom IScopeAccessor or you're trying to
access scoped component outside of the scope (like a per-web-request
component outside of web request etc)
What is the correct way to use PerWcfSession components?
So I was missing a few things:
The ServiceContract needs to set the SessionMode property
[ServiceContract(SessionMode = SessionMode.Required)]
Likewise the ServiceBehavior needs to set the InstanceContextMode
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
Finally, the service registration needs to change the Lifestyle from the default (Singleton) so that it gets recreated for each request (and the dependencies are re-evaluated) - Transient or PerWcfSession would work.
Also, because we require a session, the binding needs to change from the basicHttpBinding to something that that supports sessions:
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifestyleTransient()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
Which makes the final code look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWebRequest,
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifeStyle.PerWebRequest
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}