Is there an easy way to consume operations exposed by a workflow service (WF 4) so that I can use the async keyword from a service client?
Service interface:
[ServiceContract]
public interface IMyService
{
[OperationContract]
Task<int> GetSomething();
}
Usage:
var service = GetChannel<IMyService>();
var result = await service.GetSomething();
How can I implement the channel with and (if needed) the Receive/Send reply activities in the workflow service?
Remark: I would like to avoid the automatic generation of the proxies.
Related
I have a fairly simple design question about interaction between a self hosted WCF Service and other business classes.
Here is the WCF service contract :
/// <summary>
/// Represent requests on hardware components made by a client to the controler service
/// </summary>
[ServiceContract(CallbackContract = typeof(IHardwareServiceCallback))]
public interface IHardwareService
{
[OperationContract(IsOneWay = true)]
void OpenLeftDrawer();
[OperationContract(IsOneWay = true)]
void OpenRightDrawer();
}
The service implementation
public class HardwareService : IHardwareService
{
public void OpenLeftDrawer()
{
}
public void OpenRightDrawer()
{
}
}
A class which purpose is to handle the business logic regarding client calls on the server
class DrawerRequestManager
{
// Server side Business logic to handle OpenDrawer requests from client
}
Hosting scenario
Uri adrbase = new Uri(srvConfig.Address);
var host = new ServiceHost(typeof(HardwareService), adrbase);
host.AddServiceEndpoint(typeof(IHardwareService), srvConfig.Binding, srvConfig.Address);
host.Open();
Since this is the host that is managing the service instance lifetime, what is the proper way to handle the link between the service instance and business logic classes (DrawerRequestManager for exemple).
I'm using IOC container but i'm also interested in the response when not using IOC container.
Thanks in advance !
WCF uses parameterless constructor to create service objects, but there is a way to alter that. You need to implement your own instance provider.
You can inject your instance provider via ServiceHostFactory: see here.
Alternatively you can inject instance provider by using custom attribute for your service: see here.
Either way gives you full control of how services instances are created. You can use IOC there or just call constructor manually passing any parameters you want (e.g. reference to DrawerRequestManager instance).
I have created WCF service in VS2015:
[ServiceContract(CallbackContract = typeof(IMyCallback))]
public interface IMyService { }
IMyCallback looks like:
[ServiceContract]
public interface IMyCallback {
[OperationContract]
Task<string> OnServerEvent(UserAppEventData evData);
I've built the server, run it, then added service reference (by right click on solution explorer).
The client object is defined as
[CallbackBehaviorAttribute(
ConcurrencyMode = ConcurrencyMode.Reentrant,
IncludeExceptionDetailInFaults = true,
UseSynchronizationContext = true,
ValidateMustUnderstand = true
)]
public class QMyClient : IMyCallback { }
Automatically generated interface implementation made method in sync manner:
public string OnServerEvent(UserAppEventData evData) { }
This code does't work (and isn't asynchronous) and hangs client at OnServerEvent.
When I changed code manuallly to
public async Task<string> OnServerEvent(UserAppEventData evData)
and have done the same in auto generated "service references\...\Reference.cs, all works fine. But I don't want to change Referenece.cs every time I'm updating Service Reference.
Is there any method to force "Update Service Reference" make TBA OperationContractAttribute on callback?
At ordinary WCF service direction everything works OK, VS generates task based operations.
By default the service reference you've added to solution doesn't have asynchronous operations, but you can enable them and decide which option you use for your async methods - task-based or old-fashion asynchronous. This option is available in Advanced settings for service reference.
If you're using a svcutil tool, it will create the task-based methods by default, however, you can change that behavior by some flags like /async or /syncOnly.
What #VMAtm suggested will work out just fine.
I think, you could also use ChannelFactory for this scenario. It is very flexible and you can then await on the service operations from client side. Additional benefit, you don't need to modify client when there are these kind of changes on service side.
Something like:
var channelFactory = new ChannelFactory<IService>(
"WSHttpBinding_IService" // endpoint name
);
IService channel = channelFactory.CreateChannel();
string result = await channel.OnServerEvent();
Console.WriteLine(result);
Please note that for this scenario, you will have to import common interface library to client side as dll because then it will need to know about contracts and data contracts.
I'm in the process of converting our WCF services to use async programming. As expected the interface looks like this:
public interface IFoo
{
Task<string> DoSomething(string request);
}
On the client side I'm not creating a service reference from Visual Studio. Since I own both client and server I just share the interface with the client, then I create (and cache) a ChannelFactory. To invoke the method asynchronously I use the expected syntax:
IFoo clientChannel = channelFactory.CreateChannel();
bool result = await clientChannel.DoSomething("Hello World");
My question is: Is the IClientChannel generated by the ChannelFactory really using the async features underneath? I mean, can I be sure there's no thread blocked waiting for the server response?
Looking at the ClientBase code, async calls all boil down to:
http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Channels/ServiceChannel.cs,0353de22100bb396
There doesn't seem to be any reason to think the thread would block waiting for a network response.
I want to know what is the opinion of you fellow Developers regarding WCF WebApi services.
In an N-tier application we can have multiple layers of services. We can have services consuming data from external services. In that scenario its worth to create Async Rest Services using WCF 4.0.
public interface IService
{
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginGetStock(string code, AsyncCallback callback, object asyncState);
//Note: There is no OperationContractAttribute for the end method.
string EndGetStock(IAsyncResult result);
}
But with the release of WCF WebApi this approach is still required? to create async services?
How to host them in IIS/WAS/Self Hosting
looking forward for suggestion and comments.
Well What i feel,In order to create asynchronous operations in the latest WCF WebAPIs (preview 6) I can still use same pattern (Begin/End), but I can also use the Task programming model to create asynchronous operations, which is a lot simpler.
One example of an asynchronous operation written using the task model is shown below.
[WebGet]
public Task<Aggregate> Aggregation()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and orders
Task<List<Contact>> contactsTask = client.GetAsync(backendAddress + "/contacts").ContinueWith<Task<List<Contact>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Contact>>();
}).Unwrap();
Task<List<Order>> ordersTask = client.GetAsync(backendAddress + "/orders").ContinueWith<Task<List<Order>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Order>>();
}).Unwrap();
// Wait for both requests to complete
return Task.Factory.ContinueWhenAll(new Task[] { contactsTask, ordersTask },
(completedTasks) =>
{
client.Dispose();
Aggregate aggregate = new Aggregate()
{
Contacts = contactsTask.Result,
Orders = ordersTask.Result
};
return aggregate;
});
}
[WebGet(UriTemplate = "contacts")]
public Task<HttpResponseMessage> Contacts()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and return task directly
return client.GetAsync(backendAddress + "/contacts");
}
WCF Web API comes with an completely async HttpClient implementation and you can host in IIS and also completely sefhost.
For a async REST "service" scenario please read "Slow REST"
I have some problems with mocking WCF services:
1) I declare a class with empty methods which only implements my service interface:
public class MyFakeService : IMyService {
...
public virtual MyResult GetResult(MyResponse response){
throw new NotImplementedException();
};
}
2) I have the MyResponse class:
public class MyResponse {
public long myField;
}
3) I create a mock of the service class and a service host to host this fake service:
myFakeService = mocks.StrictMock<MyFakeService>();
ServiceHost host = new ServiceHost(myFakeService);
(here I have ommited the endpoint configuration etc.)
4) And now I try to test my client. The client.GetSomethingFromService() method exactly calls the GetResult(MyResponse) method of the service.
With.Mocks(mocks)
.Expecting(() => Expect
.Call(myFakeService.GetResult(null))
.IgnoreArguments()
.Constraints(PublicField.Value("myField", 777))
.Return(new MyResult()))
.Verify(() => myClient.GetSomethingFromService());
The issue is that if something wrong in the service, I can only see something like this:
System.ServiceModel.CommunicationObjectFaultedException:
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used
for communication because it is in the Faulted state.
How do I know what exactly wrong? Maybe arguments constraints verification failed or something else...?
Thanks.
Firstly, avoid using strict mocks. They're a bad practice because they make your tests too brittle.
Secondly if you're testing a WCF service you don't need to spin up a ServiceHost since you'll then be doing an integration test. You're just wanting to test the logic of your service, not the WCF infrastructure.
For a run through of how to use RhinoMocks and WCF services have a look at my blog post on unit testing WCF services