My interface look like this:
[ServiceContract]
public interface IMyService
{
[OperationContract]
myConnectedService.SomeComplexResponseType someMethod(myConnectedService.SomeComplexRequestType request);
}
My implementation look like this:
public class MyService : IMyService
{
myConnectedService_client client = new myConnectedService_client();
public myConnectedService.SomeComplexResponseType someMethod(myConnectedService.SomeComplexRequestType request)
{
myConnectedService.SomeComplexResponseType response = client.connectedServiceMethod(request);
return response ;
}
}
The error i get when i am trying to run my service:
Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.
and
error CS0644: 'System.ComponentModel.PropertyChangedEventHandler' cannot derive from special class 'System.MulticastDelegate'
So currently I'm creating a wcf client instance using the following code:
Service1Client client = (Service1Client)_container.Resolve<IService1>(new ParameterOverride("remoteAddress", url),
new ParameterOverride("endpointConfigurationName", "basicEndpoint"));
however this doesn't work when I'm creating unit tests as I'm casting the object as a Service1Client so my unit test bombs out as it cannot cast a Mock object:
//Mock the WCF service
var wcfMock = new Mock<IService1>();
//register with container!
var container = new UnityContainer();
container.RegisterInstance(wcfMock.Object);
Any ideas on how best to resolve this issue?
You claim to be casting to Service1Client so you can access the methods Open(), Abort() and Close() of System.ServiceModel.ClientBase.
Those methods are defined in System.ServiceModel.ICommunicationObject, so let your interface IService1 inherit from that:
public interface IService1 : ICommunicationObject
{
}
Then you can omit the cast.
I currently am running some WCF REST services in a Windows Service (not IIS), using the WebServiceHost. I have a separate interface and class defined for each service, but I'm having some issues understanding how WebServiceHost, ServiceEndpoint and ServiceContracts can be used together to create a selfhosted solution.
The way that I currently set things up is that I create a new WebServiceHost for each class which implements a service and use the name of the class as part of the URI but then define the rest of the URI in the interface.
[ServiceContract]
public interface IEventsService
{
[System.ServiceModel.OperationContract]
[System.ServiceModel.Web.WebGet(UriTemplate = "EventType", ResponseFormat=WebMessageFormat.Json)]
List<EventType> GetEventTypes();
[System.ServiceModel.OperationContract]
[System.ServiceModel.Web.WebGet(UriTemplate = "Event")]
System.IO.Stream GetEventsAsStream();
}
public class EventsService: IEventsService
{
public List<EventType> GetEventTypes() { //code in here }
public System.IO.Stream GetEventsAsStream() { // code in here }
}
The code to create the services looks like this:
Type t = typeof(EventService);
Type interface = typeof(IEventService);
Uri newUri = new Uri(baseUri, "Events");
WebServicesHost host = new WebServiceHost(t, newUri);
Binding binding = New WebHttpBinding();
ServiceEndpoint ep = host.AddServiceEndpoint(interface, binding, newUri);
This works well and the service endpoint for each service is created at an appropriate url.
http://XXX.YYY.ZZZ:portnum/Events/EventType
http://XXX.YYY.ZZZ:portnum/Events/Event
I then repeat for another service interface and service class. I would like to remove the Events in the Url though but if I do that and create multiple WebServiceHosts with the same base URL I get the error:
The ChannelDispatcher at 'http://localhost:8085/' with contract(s) '"IOtherService"' is unable to open its IChannelListener
with the internal Exception of:
"A registration already exists for URI 'http://localhost:8085/'."
I'm trying to understand how the WebServiceHost, ServiceEndpoint and ServiceContract work together to create the ChannelListener.
Do I need a separate WebServiceHost for each class which implements a service? I don't see a way to register multiple types with a single WebServiceHost
Secondly, I'm passing in the interface to the AddServceEndpoint method and I assume that method checks the object for all of the OperationContract members and adds them, the problem is how does the WebServiceHost know which class should map to which interface.
What I would love would be an example of creating a WCF self hosted service which runs multiple services while keeping the interface and the implementation classes separate.
Sounds to me like the problem that you are having is you are trying to register more than one service on the same service URI. This will not work, as you have noticed, each service must have a unique endpoint.
Unique By
IP
Domain
Port Number
Full URL
Examples
http://someserver/foo -> IFoo Service
http://someserver/bar -> IBar Service
http://somedomain -> IFoo Service
http://someotherdomain -> IBar Service
http://somedomain:1 -> IFoo Service
http://somedomain:2 -> IBar Service
You get the idea.
So to directly address your question, if you want more than once service to be at the root url for you site, you will have to put them on different ports. So you could modify your code to be something like
public class PortNumberAttribute : Attribute
{
public int PortNumber { get; set; }
public PortNumberAttribute(int port)
{
PortNumber = port;
}
}
[PortNumber(8085)]
public interface IEventsService
{
//service methods etc
}
string baseUri = "http://foo.com:{0}";
Type iface = typeof(IEventsService);
PortNumberAttribute pNumber = (PortNumberAttribute)iface.GetCustomAttribute(typeof(PortNumberAttribute));
Uri newUri = new Uri(string.Format(baseUri, pNumber.PortNumber));
//create host and all that
I think it might be useful for you to re-think about your URI approach. Uri is a unique resource identifier.
Each your endpoint says that you try to expose outside a different kind of resource it's "Events" and "OtherResource". Thus you need to change your UriTemplates a bit.
I would make it so:
[ServiceContract]
public interface IEventTypesService
{
[OperationContract]
[WebGet(UriTemplate = "", ResponseFormat=WebMessageFormat.Json)]
IList<EventType> GetEventTypes();
[OperationContract]
[WebGet(UriTemplate = "{id}")]
EventType GetEventType(string id);
}
[ServiceContract]
public interface IEventsService
{
[OperationContract]
[WebGet(UriTemplate = "")]
Stream GetEventsAsStream();
[OperationContract]
[WebGet(UriTemplate = "{id}")]
Event GetEvent(string id);
}
public class EventsService: IEventsService, IEventTypesService
{
public IList<EventType> GetEventTypes() { //code in here }
public EventType GetEventType(string id) { //code in here }
public Stream GetEventsAsStream() { // code in here }
public EventType GetEventType(string id) { // code in here }
}
Type t = typeof(EventService);
Type interface1 = typeof(IEventsService);
Type interface2 = typeof(IEventTypesService);
var baseUri = new Uri("http://localhost");
Uri eventsUri= new Uri(baseUri, "Events");
Uri eventTypesUri= new Uri(baseUri, "EventTypes");
WebServicesHost host = new WebServiceHost(t, baseUri);
Binding binding = New WebHttpBinding();
host.AddServiceEndpoint(interface1, binding, eventsUri);
host.AddServiceEndpoint(interface2, binding, eventTypesUri);
And yes, you are right - you have to have different addresses, but it's really different resources. To understand it better you can refer: RESTful API Design, best-practices-for-a-pragmatic-restful-api
To finish, there is a way to use the same address, but the approach a bit weird:
Using the same address
The following solution:
allows a single object to handle a specific endpoint
no part of the path is in the URI template
uses the same port for all of the services
It does requires more than one WebServiceHost - one per object that handles requests. Another difficulty is that adding deeper endpoints (like /events/2014) means they either need to have unique parameters or the URI template must include part of the path, if you go convention over configuration that shouldn't be a problem.
A WebServiceHost can only host one thing (class) but that object can have multiple interfaces to handle multiple different types of requests on different URLs. How can different WebServiceHosts bind to the same domain:port? They can't so I guess WebServiceHost wraps an underlying static object that routes requests to the right object. This doesn't technically answer your question but I think this implementation allows you to do what you want right?
A console app that hosts the web services.
public class Program
{
static void Main (string[] args)
{
var venueHost = new WebServiceHost (typeof (Venues));
venueHost.AddServiceEndpoint (typeof (IVenues), new WebHttpBinding (), "http://localhost:12345/venues");
venueHost.Open ();
var eventHost = new WebServiceHost (typeof (Events));
eventHost.AddServiceEndpoint (typeof (IEvents), new WebHttpBinding (), "http://localhost:12345/events");
eventHost.Open ();
while (true)
{
var k = Console.ReadKey ();
if (k.KeyChar == 'q' || k.KeyChar == 'Q')
break;
}
}
}
The Venues class implements IVenues and handles any requests to http://localhost:12345/venues/
[ServiceContract]
public interface IVenues
{
[WebInvoke (Method = "GET", UriTemplate = "?id={id}")]
string GetVenues (string id);
}
public class Venues : IVenues
{
public string GetVenues (string id)
{
return "This would contain venue data.";
}
}
The Events class implements IEvents and handles any requests to http://localhost:12345/events/
[ServiceContract]
public interface IEvents
{
[WebInvoke (Method = "GET", UriTemplate = "?venue={venue}")]
string GetEvents (string venue);
}
public class Events : IEvents
{
public string GetEvents (string venue)
{
return "This would contain event data.";
}
}
WCF self hosting can be done in many ways like Console application hosting, Windows service hosting, etc.
I had tried to host two services using a single console application. The structure of the services was similar to what you mentioned, that is, separate classes and interfaces for both the services.
You might want to have a look at this link:
Hosting two WCf services using one console app
So I started to create TDD tests for a new WCF service I wanted to create. In TDD, you create the test, and start adding objects that don't exist yet into your tests. First object I wanted to test was that the service is not null after instantiated.
Then then I said wait, how the hell can you do that in WCF...a service extension is .svc. Yes there's a .svc.cs but the main parent is .svc. I don't see a way I can to TDD on this part where you've have something like this but it'd create an .svc instead of just a .cs:
[TestMethod]
public void UponInitialization_ServiceIsNotNull()
{
// Arrange
// Act
NyNewService service = new MyNewService();
// Assert
Assert.IsTrue(service != null);
}
This is a very fundamental necessary first test, testing the very simplest possible from the start...this is very common on any TDD or XP team doing TDD.
Any thoughts on how I can create a new .svc from within my test here? not a plain .cs?
I'd start with creating acceptance test for non-existing WCF service:
private Uri _baseAddress = new Uri("http://localhost:8713/service1");
private IService1 _client;
[SetUp]
public void Setup()
{
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress(_baseAddress);
var factory = new ChannelFactory<IService1>(binding, endpoint);
_client = factory.CreateChannel();
}
[TearDown]
public void TearDown()
{
if (_client != null)
((ICommunicationObject)_client).Close();
}
[Test]
public void ShouldReturnSampleData()
{
Assert.That(_client.GetData(42), Is.EqualTo("You entered: 42"));
}
Keep in mind, that nothing is created yet - we start from test. Now you can create service interface:
public interface IService1
{
string GetData(int value);
}
Test now compiles, but of course, it fails with error
Attempted to get contract type for IService1, but that type is not a
ServiceContract, nor does it inherit a ServiceContract.
Good, that's because we should mark our interface with [ServiceContract] attribute. We add this attribute and run test again:
Method GetData 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.
Ok, mark our service interface with required attributes:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Now we see another error (because nothing is actually running our non-existing service)
There was no endpoint listening at http://localhost:8713/service1 that
could accept the message. This is often caused by an incorrect address
or SOAP action. See InnerException, if present, for more details.
We can use ServiceHost to run our service (at this moment we need to create service class to compile tests):
private ServiceHost _host;
[SetUp]
public void Setup()
{
_host = new ServiceHost(typeof(Service1), _baseAddress);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
_host.Description.Behaviors.Add(smb);
_host.Open();
// creating client as above
}
[TearDown]
public void TearDown()
{
// closing client as above
if (_host != null)
_host.Close();
}
You also need to implement IService1 interface by service class (otherwise test will fail):
public class Service1 : IService1
{
public string GetData(int value)
{
throw new NotImplementedException();
}
}
Now I'd created some unit-tests for Service1 class in order to implement GetData functionality. With these tests passing you will have acceptance test passing also. Thats it. You did test first, and your WCF service is completely ready to be hosted.
I have a ServiceHost listening on a NetNamedPipeBinding endpoint. I have a service contract class with a single method which is being called by the client and handled by the server. The method (We'll call it PipeRequest()) has a Request parameter. On the client side I populate this object but it's empty by the time it gets sent over to the server. Any ideas why this would be the case?
_Host = new ServiceHost(typeof(PipeService), new Uri(ServiceRequestRouter.URI));
_Host.AddServiceEndpoint(
typeof(IPipeService),
new NetNamedPipeBinding(),
_PipeName
);
_Host.Open();
[ServiceContract(Namespace = "http://www.example.com/PipeCommunication")]
interface IPipeService
{
[OperationContract]
void PipeRequest(ServiceRequestBase request);
}
[DataContract]
[KnownType(typeof(DerivedServiceRequest))]
[KnownType(typeof(SomeEnumType))]
public abstract class ServiceRequestBase
{
...
public void Dispatch(string pPipeName = ServiceRequestRouter.DefaultPipeName)
{
EndpointAddress epa = new EndpointAddress(_address_));
IPipeService proxy = ChannelFactory<IPipeService>.CreateChannel(new NetNamedPipeBinding(), epa);
proxy.PipeRequest(this);
}
}
It look like it has to do with proxy.PipeRequest(this);
You need to pass in a class that inherits ServiceRequestBase, if you class does inherit the ServiceRequestBase then it might not be serializable.
It turns out I had to specify (as part of the data contract) any derived classes from ServiceRequestBase class.
[DataContract]
[KnownType(typeof(CitrixInfoServiceRequest))] // added this line
[KnownType(typeof(RegStateServiceRequest))] // added this line
public abstract class ServiceRequestBase
{
// ...
}