I have a WCF service and application. My application occasionally sends some text messages (string[]) to the WCF service, which then parses it.
Now I would like my application to send objects of class MyObject to WCF service. Then the service should have chance also parse (I mean it should has chance to deserialize its data (e.g. myObjectInstance.name, etc.))
How to implement that?
Thanks in advance for help.
Divide your code into (at least) three assemblies:
'Metadata' — contains MyObject and IMyService (which is your service's contract); may not reference any assembly that cannot be deployed at client-side
'Server' — implements IMyService and exposes the WCF service; references 'Metadata'
'Client' — contains the code of the client; reference 'Metadata'
That way you can easily share the 'Metadata' assembly between server and clients. Then it's just a matter of using MyObject as the type of any parameters of any methods in IMyService as you need to.
Yes, you can, but you should use Message. Take a look on the following example
As a result, you code could look like
private static void Main()
{
var createRequest = new CreateClientRequest
{
Email = "emial#emial.com"
};
var response = SoapServiceClient.Post<CreateClientRequest, ClientResponse>(createRequest);
Console.WriteLine("POST: {0}", response);
var updateRequest = new UpdateClientRequest
{
Email = "new#email.com",
Id = response.Id
};
response = SoapServiceClient.Put<UpdateClientRequest, ClientResponse>(updateRequest);
Console.WriteLine("PUT: {0}", response);
var getClient = new GetClientRequest
{
Id = response.Id
};
response = SoapServiceClient.Get<GetClientRequest, ClientResponse>(getClient);
Console.WriteLine("GET: {0}", response);
var deleteRequest = new DeleteClientRequest
{
Id = response.Id
};
SoapServiceClient.Delete(deleteRequest);
Console.ReadKey();
}
with simple ServiceContract
[ServiceContract]
public interface ISoapService
{
[OperationContract(Action = ServiceMetadata.Operations.Process,
ReplyAction = ServiceMetadata.Operations.ProcessResonse)]
Message Process(Message message);
[OperationContract(Action = ServiceMetadata.Operations.ProcessWithoutResonse)]
void ProcessWithoutResonse(Message message);
}
Related
I'm having trouble with implementing URL redirection using message inspectors for my WCF REST service. The idea is to implement AfterReceiveRequest to change the incoming request to effectively do nothing, and then in BeforeSendReply, make call to another URI which provides the actual service. You can think of this scenario as something where we do not want to break clients, so they continue to use old URIs for invocations, but internally we redirect them to a different URI.
For example, this is what my service contract looks like:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(UriTemplate = "person/{person}")]
string GreetMe(string person);
[OperationContract]
[WebGet(UriTemplate = "donothing")]
string DoNothing();
}
And this is the implementation:
public class Service1 : IService1
{
public string GreetMe(string person)
{
return string.Format("Hi {0}", person);
}
public string DoNothing()
{
return string.Empty;
}
}
Then I'm adding a MessageInspector to endpoint behavior. The AfterReceiveRequest of this inspector is like this:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
OperationContext operationContext = OperationContext.Current;
if (WebOperationContext.Current != null && WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
{
UriBuilder baseUriBuilder = new UriBuilder(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri);
UriBuilder requestUriBuilder = new UriBuilder(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri);
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = baseUriBuilder.Uri.ToString();
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = baseUriBuilder.Uri.ToString() + "donothing";
OperationContext.Current.IncomingMessageHeaders.To = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
operationContext.IncomingMessageProperties["Via"] = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
request.Headers.To = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
}
return null;
}
Basically, I want to change all incoming requests to go to DoNothing() operation. However, when I run this, I still see that the request makes it to GreetMe method. I attached the debugger and can see that my code in AfterReceiveRequest is getting executed, but I'm not sure why the URI redirection does not happen.
Any ideas?
I have a desktop app with a duplex WCF service, but I have some troubles using the callback.
The service is started as following in main of program.cs:
ServiceHost svcHost = new ServiceHost(typeof(PeriodicService));
svcHost.Open();
Console.WriteLine("Available Endpoints :\n");
svcHost.Description.Endpoints.ToList().ForEach(endpoint => Console.WriteLine(endpoint.Address.ToString() + " -- " + endpoint.Name));
For the service I created a subscribe function where the callbackchannel is saved in a global variable, then the callback uses that global variable to talk back to the client (there will be only one client connecting).
IPeriodicCallback callbackClient;
public IPeriodicCallback Proxy
{
get
{
return this.callbackClient;
}
}
public void joinPeriodicService()
{
Console.WriteLine("Client subscribe");
this.callbackClient = OperationContext.Current.GetCallbackChannel<IPeriodicCallback>();
}
The thing I want to do now is call the callbackclient from an other class.
In the other class I created the service as:
private PeriodicService periodicService = new PeriodicService();
And I try to write data to it using:
if(this.periodicService.Proxy != null)
{
this.periodicService.Proxy.On1MinuteDataAvailable(tmpPeriod);
}
However the proxy stays null, I also tried to move the proxy part to the class but this also results in it staying null.
When the client connects I nicely get the message "Client Subscribe" but it seems there are two instances running of the periodicservice.
But my problem is I don't see an other way to access the periodicservice then creating it in my class, or is it also already created by the svcHost?
Can ayone point me in the right direction?
This repository shows the a duplex WCF imeplementation I made to answer a similar question a while ago, its a full working example with as little extra stuff as possible.
https://github.com/Aelphaeis/MyWcfDuplexPipeExample
Lets say we have a Service Contract like this :
[ServiceContract(CallbackContract = typeof(IMyServiceCallback),SessionMode = SessionMode.Required)]
public interface IMyService
{
[OperationContract(IsOneWay=true)]
void DoWork();
}
Note that I specified a CallbackContract.
If you want to make a duplex, you would want to perhaps make your Service Behavior implementation of the above contract like this :
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
public void DoWork()
{
Console.WriteLine("Hello World");
Callback.WorkComplete();
}
IMyServiceCallback Callback
{
get
{
return OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
}
}
}
The important thing here is the Callback. This is how your service would allow you to access specified to you by the Client.
You also need to define the callback interface, In my case its quite simple :
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract(IsOneWay = true)]
void WorkComplete();
}
Now I want to create a client to use this Duplex Service. The first thing I need to do is implement the IMyServiceCallback. I need to do this on the client. In this case the implementation is this:
class Callback : IMyServiceCallback
{
public void WorkComplete()
{
Console.WriteLine("Work Complete");
}
}
Now when I want to open my duplex connection with the services I would create a proxy class like this something like this:
public class MyServiceClient: IMyService, IDisposable
{
DuplexChannelFactory<IMyService> myServiceFactory { get; set; }
public MyServiceClient(IMyServiceCallback Callback)
{
InstanceContext site = new InstanceContext(Callback);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
EndpointAddress endpointAddress = new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName);
myServiceFactory = new DuplexChannelFactory<IMyService>(site, binding, endpointAddress);
}
public void DoWork()
{
myServiceFactory.CreateChannel().DoWork();
}
public void Dispose()
{
myServiceFactory.Close();
}
}
Notice that I specified an InstanceContext. That Instance Context will be an instance of the object I created that implements IMyServiceCallback.
That's all you need to do! Simple as that!
Update :
Callback objects are just like any other object. You can store them into a collection and iterate through them and based on some condition.
One way is to create a property in the IMyServiceCallback that can uniquely identify it. When a client connects to the service it can call a method which specifies a callback object which can then be cached or saved for later use. You can then iterate the callbacks and based on some condition you can call a method for a specific client.
This is certainly more complicated; however, it is certainly manageable. I will add an example in a bit.
Update 2
This is a working example of exactly what you want; however, its a lot more complicated. I'll try to explain as simply as I can : https://github.com/Aelphaeis/MyWcfDuplexPipeExample/tree/MultiClient
Here is a list of the changes:
I've modified the client proxy (and service) so that when initialized it calls the init Method
I've also modified the Service implementation so that now it is a single instance dealing with all requests (for convenience).
I added a new OperationContract in the Service interface called Msg
I've added a new Method in the IMyServiceCallback called RecieveMessage.
I've added a way to identify the client.
In the proxy class I have the following :
public MyServiceClient(IMyServiceCallback Callback)
{
InstanceContext site = new InstanceContext(Callback);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
EndpointAddress endpointAddress = new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName);
myServiceFactory = new DuplexChannelFactory<IMyService>(site, binding, endpointAddress);
Init();
}
public void Init()
{
myServiceFactory.CreateChannel().Init();
}
In my service I have the following :
public class MyService : IMyService
{
public List<IMyServiceCallback> Callbacks { get; private set; }
public MyService(){
Callbacks = new List<IMyServiceCallback>();
}
public void Init()
{
Callbacks.Add(Callback);
}
// and so on
My IMyServiceCallback has been redefined to :
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract]
int GetClientId();
[OperationContract(IsOneWay = true)]
void WorkComplete();
[OperationContract(IsOneWay = true)]
void RecieveMessage(String msg);
}
By specifying a number, you can contact the client that corresponds with that number. If two clients have the same Id, both clients will be contacted.
I've been working on implementing signalr as part of a wcf service to talk to a .net client. Apart form a connection message all communication is one way passing a dynamic payload to the client side.
I've managed to set it up so that the client will connect to the service and pass a connection message but I can't get the pushing of a message from the service to the client.
Sorry if I've missed this answered else where but I've been unable to find a reason for this failing as it seems to follow the "how to's"
Any help would be much appreciated and thank you in advance
Server side:
WCF external call
public class MessageService : IMessageService
{
public string PushAlerts()
{
var payLoad = new PayLoad
{
MethodName = "alerts"
};
IHubContext connectionHub = GlobalHost.ConnectionManager.GetHubContext<PushConnection>();
connectionHub.Clients.All.Notify(payLoad);
}
}
My Hub
[HubName("PushHub")]
public class PushHub : Hub
{
public override Task OnConnected()
{
var connectionMessage = Context.QueryString["CONNECTION MESSAGE"];
if (connectionMessage != null)
{
Debug.WriteLine("connectionMessage");
}
return base.OnConnected();
}
}
ClientSide:
var querystringData = new Dictionary<string, string>{};
querystringData.Add("CONNECTION MESSAGE", "foo Connection");
var hubConnection = new HubConnection("http://localhost:60479/", querystringData); //Running local till working
hubConnection.TraceLevel = TraceLevels.All;
hubConnection.TraceWriter = Console.Out;
IHubProxy clientHubProxy = hubConnection.CreateHubProxy("PushHub");
clientHubProxy.On("Notify", payLoad =>
SynchronizationContext.Current.Post(delegate
{
ResponseMethod(payLoad);
}, null)
);
await hubConnection.Start();
I've missed out payload but that only holds a string value at present. I've also setup a pipemodule for logging perposes.
Thanks Again
Ok so I resolved this problem in two ways firstly I moved the call to the client inside the hub its self, which I then called from a method in my wcf service.
[HubName("PushHub")]
public class PushHub : Hub
{
IHubContext connectionHub = GlobalHost.ConnectionManager.GetHubContext<PushConnection>();
public void Send(Payload payload)
{
connectionHub.Clients.All.Notify(payLoad);
}
}
Secondly the client code for the method was all wrong. In the end this worked:
clientHubProxy.On("Notify", (payLoad) => { dostuff };
Took a lot of fiddling but hope my answer helps others.
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
I am trying to make an echo web service that replies back with the request content, regardless of what that content is. Just an endpoint listening for anything and spitting it back.
So for example if it is called with "hi", the response content is "hi". If it is called with a multi-part message containing a form data, the data comes back. If it is a JSON message then JSON comes back. This is regardless of what the actual content is or what url parameters are provided. Basically I want it to send the same thing back regardless of the mime type, don't try to interpret it, just spit it back.
I'm starting with the following:
[ServiceContract]
private interface IEchoService
{
[OperationContract]
[WebInvoke]
object Echo(object s);
}
private class EchoService : IEchoService
{
public object Echo(object s)
{
return s;
}
}
WebServiceHost host = new WebServiceHost(typeof(EchoService), new Uri("http://localhost:8002/"));
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IEchoService), binding, "echo");
Any ideas how to make this work? This just returns back a HTTP status code of bad request when called.
It looks like the answer is to use the System.ServiceModel.Channels.Message class.
[ServiceContract]
private interface IEchoService
{
[OperationContract]
[WebInvoke]
Message Echo(Message s);
}
private class EchoService : IEchoService
{
public Message Echo(Message s)
{
return s;
}
}