I have WCF Web service using https. It has next interface:
[ServiceContract]
class Service
{
[OperationContract]
[WebInvoke(UriTemplate="Method", BodyStyle=WebMessageBodyStyle.Bare)]
byte[] Method(Stream request)
{
// ... Some logic ...
return someBytes;
}
}
This works good but has one little issue. After method completition it closes up https connection. I have another method in service with WebGet. It returns Stream object, and this one doesn't close https connection.
I've tried to use same approach in my first Method and rewrited it as follows:
[ServiceContract]
class Service
{
[OperationContract]
[WebInvoke(UriTemplate="Method", BodyStyle=WebMessageBodyStyle.Bare)]
Stream Method(Stream request)
{
// ... Some logic ...
return new MemoryStream(someBytes);
}
}
But when I'm trying to consume Method with a client the service responds: "Method not allowed. Allowed: GET, HEAD".
Please tell me if I'm doiing it wrong by returning Stream object, or I have missed something.
UPD:
I also appreciate in any hints about tracing down this problem.
Related
I have a publisher / subscriber pattern WCF Duplex ServiceHost that is hosted by a Windows Service. The Windows Service receives events from a separate process. OnEvent I would like to force my WCF Host to publish that data to all subscribed clients. Typically if a Client is calling this is straight forward. But when my Service Host needs to do this - I can't get my head around HOW to do that.
I have 2 questions:
1: I do not know how to create a Channel in WCFHost from my Windows Service so that it can use to publish to the Subscribers.
2: I read Creating WCF ChannelFactory so I do know I am creating a DuplexChannelFactory (2 per second ) which might be too much overhead.
Any help examples, hints are greatly appreciated. I am not a WCF expert and currently know more about it than I thought I should have to know in order to use it.
I had read on SO
Can I call a Method in a self hosted wcf host locally?
So then I have created a method inside my WCFHost like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
I get an error of course that there is no InstanceContext because I am constructing using typeof(Cback) ..
"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."
So I am not sure how I can go about performing this ?
And for those that say read the error : yes I read the error.
Now how to do that with an InstanceContext that does not exist as OperationContext.Current does not exist at this point as I am calling this method form my Hosting Process into my WCFHost.
So if I could have a nice example of how to do this - even if I must use the code example on the 2nd link (of course implementing the DuplexChannelFactory) I would greatly appreciate it.
EDIT
Basically the windows Service is doing some heavy work monitoring other services, about 2 times a second it then must publish that to "Subscribed" Clients via WCF.
I think you have got very confused about how everything is wired together and are mixing concepts from the client in with the service. You haven't provided much concrete information about your scenario to go on so I'm going to provide a small example and hopefully you will be able to apply the ideas to your problem.
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
In your OnEvent method, you would call something similar to this inside your event method.
MyService.SendDataToClients(mydata);
This uses static data to store the list of clients. If you wanted to do something like segment your clients for different endpoints, you would need to do something different. There is a potential out of order message and scaling problem with this code if your OnEvent method can be called again while the previous call hasn't completed. For example, if you receive 2 messages, the first being large and the second being small, you could potentially send the second smaller message to clients later in the HashSet iteration order before they have been sent the first message. Also this won't scaled to a large number of clients as you could block timing out on one client holding up messages being sent to other clients. You could use something similar to Task's to dispatch multiple message deliveries. If this needs to scale, I would suggest looking at Reactive Extensions for .Net
I have been reading and experimenting with WCF and trying to understand the workings in simple terms. So my questions are for verification and validation of what I believe to be correct but I need to be sure:
In a typical Publish-Subscribe Duplex service.
1: Service Contract - this is the communication path that clients must make to the service.
2: Callback contract - this is the communication methods back to the client.
3: Setting the IsOneWay = true property on a callback contract means the Client will not get anything back from the server.
4: setting IsOneWay = true on the ServiceContract means the server will not get anything back from the client.
5: void return methods still send a reply back, if IsOneWay=true, the reply is is ignored, if false error and soap info can be obtained. ^
for brevity I have looked at the following and then Some^ⁿ:
Understanding WCF
WCF issue with using IsOneWay attribute
Understanding WCF Client to Server
https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.isoneway(v=vs.110).aspx
Take a look at this tutorial for WCF, and this MSDN Article on duplex services.
You're almost there with your definitions, I would define the above myself as:
Service Contract - The interface that defines the operations a web service exposes to clients.
Callback Contract - Similar to a service contract, but as you note, for the client side. This is defines how a web service can communicate to client as a separate call. (As opposed to simply returning data from the calls in the service contract). These are often used for returning values from long-running web service calls, or event signaling.
IsOneWay = true on the service contract - This specifies that the service operation is returns no value, and hence the client will simply "fire and forget". The call to the webservice will not block the client until it completes, but instead return immediately. For this reason, operations with IsOneWay = true can only return void.
IsOneWay = true on the callback contract - This is much the same as it is on the service contract. When the server calls the operation on the callback contract, it will return immediately and not block until the operation completes.
Void returns - If IsOneWay is not set to true, the call will still block until the operation completes, a SOAP message will still be returned, but with no data (unless you are passing back faults). If you wish to actually return values, you can either do so exactly as you would with normal methods, setting the return type of the operation i.e
[ServiceContract]
public interface IService
{
[OperationContract]
DateTime GetDateTime();
}
public class Service : IService
{
public DateTime GetDateTime()
{
return DateTime.Now;
}
}
Alternatively, you could create a duplex service, with a callback contract, and IsOneWay = true
[ServiceContract(CallbackContract = typeof(ICallbackService))]
public interface IService
{
[OperationContract(IsOneWay = true)]
void GetDateTime();
}
public interface ICallbackService
{
[OperationContract(IsOneWay = true)]
void GetDateTimeCompleted(DateTime dateTime);
}
public class Service : IService
{
public void GetDateTime()
{
// Do long action here.
...
Callback.GetDateTimeCompleted(DateTime.Now);
}
ICallbackService Callback
{
return OperationContext.Current.GetCallbackChannel<ICallbackService>();
}
}
Using this method:
The call to the webservice GetDateTime() operation would return immediately
The "Very long operation" would execute on the server
The GetDateTimeCompleted(DateTime dateTime) on the client would get triggered when the server completes.
Please note that the above duplex example is not complete, you'll need to ensure you're handling things like sessions correctly.
You're definitely on the right track. I'd recommend following the tutorials linked above, (along with any others you find) and experimenting. You'll soon get a good feel for what is possible.
I'm building WCF rest service and it's client. I plan, that client does not know much about the service, just right URL's to call methods and expected results.
My service contract is:
[WebInvoke(Method="POST", UriTemplate="/tasks")]
[OperationContract]
void SubmitTask(Transaction task);
[WebGet(UriTemplate = "/tasks/{taskId}")]
[OperationContract]
[XmlSerializerFormat]
Transaction GetTask(string taskId);
SubmitTask is realized like:
SubmitTask(Transaction task)
{
DoSomethingWithTask(task);
task.Status = "SomeStatus";
DoSomethingElseWithTaks(task);
task.Status = "SomeOtherStatus";
}
What I expect on client:
ButtonClick()
{
SubmitTask(task);
while(true)
{
string status = Transaction GetTask(task.taskId).Status;
Textbox.Text+= status;
if(status==ok)
break;
Thread.Sleep(1000);
}
}
The problem is - GetTask is not performed on service side, while all SubmitTask operations are completed, so I get only last task status on client side. How to realize asynchronos operation performing in this situation?
Thanks in advance!
Have you read this interesting little article? Tweaking WCF to build highly scalable async REST API and the following article that is very good and which will hopefully provide the answer you desire Fixing WCF to build highly scalable async REST API
I've written a C# Windows Service that provides a REST api through WCF. This Service needs to call another web service which also uses a REST api. My service can communicate perfectly with the other service unless someone has made a call my service and it is currently responding. I wrote up a simple test:
public void TestConnection()
{
WebChannelFactory<IOtherService> wf = new WebChannelFactory<IOtherService>(otherURI);
IOtherService service = wf.CreateChannel();
service.Test();
}
[ServiceContract]
public interface IOtherService
{
[WebGet(UriTemplate = "services/account?username=testuser&password=d625a4de623dce36af2b75102eaf0ce7&locale=en-US", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
[OperationContract]
AccountServiceInfo Test();
}
Normally when I call TestConnection it works perfectly, but when someone makes a call to my service that requires me to call TestConnection the other service sees a POST rather than a GET and returns 400. Does anyone have any idea why this might be the case or how I can fix it? Thanks.
When using a WebChannelFactory inside a WCF service that already has an OperationContext, you may need to create a new context before being able to successfully callout using a channel created by the WebChannelFactory.
public void TestConnection()
{
var wf = new WebChannelFactory<IOtherService>(otherURI);
var service = wf.CreateChannel();
using ((IDisposable)service)
using (new OperationContextScope((IContextChannel)service))
{
service.Test();
}
}
http://blogs.msdn.com/b/pedram/archive/2008/07/19/webchannelfactory-inside-a-wcf-service.aspx
We are using WCF for communication between a client and a server application. The client application has many features that requires communication to the server - and we have chosen to implement this in multiple classes (seperation of responsability)
For the time, we are creating new WCF endpoints and service contracts for each object - Invoicing, Accounting, Content Management, etc. This causes a lot of endpoint configuration both on the client and server (with potential misconfiguration problems when moving into the test and production platforms).
I would like to know if I can define a single WCF endpoint that can deliver multiple service contact implementations. Our configuration files would then contain a single endpoint (to the service factory) and I can request different services by specifying the interface of the service I am interested in.
e.g.
using (IServiceClientFactory serviceClientFactory = new RealProxyServiceClientFactory())
{
// This is normal WCF proxy object creation.
IServiceFactory serviceFactory = serviceClientFactory.CreateInstance<IServiceFactory>("");
// This is what we would like to do
IInvoiceService invoiceService = serviceFactory.getService(typeof(IInvoiceService));
invoiceService.executeOperation(data);
}
The clue being a single endpoint configuration per client/server pair, instead of an endpoint configuration per service contact I would like to make available.
Is this possible?
I'm not 100% clear on what you're trying to do, but if you just want to be able to host different contracts on the same address with the implementation inside one service class, this is completely possible. To share an endpoint address, you must ensure that you use the same binding instance for each service endpoint.
Here is a complete sample which defines 3 contracts, 1 service class which implements all of them, and a ServiceHost with the 3 contract endpoints at the exact same address:
using System;
using System.ServiceModel;
[ServiceContract]
interface IContractA
{
[OperationContract]
void A();
}
[ServiceContract]
interface IContractB
{
[OperationContract]
void B();
}
[ServiceContract]
interface IContractC
{
[OperationContract]
void C();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Service : IContractA, IContractB, IContractC
{
public Service()
{
}
public void A()
{
Console.WriteLine("A");
}
public void B()
{
Console.WriteLine("B");
}
public void C()
{
Console.WriteLine("C");
}
}
class Program
{
public static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/Service/");
ServiceHost host = new ServiceHost(new Service(), address);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(IContractA), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractB), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractC), binding, string.Empty);
host.Open();
IContractA proxyA = ChannelFactory<IContractA>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyA.A();
((IClientChannel)proxyA).Close();
IContractB proxyB = ChannelFactory<IContractB>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyB.B();
((IClientChannel)proxyB).Close();
IContractC proxyC = ChannelFactory<IContractC>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyC.C();
((IClientChannel)proxyC).Close();
host.Close();
}
}
I doubt that this would work. Xml serialization might be the biggest problem here.
Also I don't think you actually need it. If I was in your shoes I would try and abstract my communication with the service. Basically you would always send a "Message" to the service, which has a "Target" being one of the classes you wanted to access. The service would always reply with a "Response", of which the contents would be filled by the class the "Message" was send to.
Another approach would be to route all these messages trough a service that would echo the request to the appropriate service. This way you keep scalability up, but it does still have a large configuration burden.
HTH.
Sounds like you want to keep your seperate services but have some kind of bus that routes is throught. MSMQ maybe, then you can have one services that takes every message pops it onto a specific queue and then a dedicated service can read that off that particular queue.
Not really a WCF based solution though admittedly.
The notion of a single interface(read as ServiceContract) implemented by multiple classes wont work. So you'd need one 'monster' service that implements all and routes through to the correct service. Facade pattern springs to mind.