I am working on an n-Tier application using WCF between the layers such that:
Tier 1: Silverlight application
Invokes the search request
IClientBroker clientBroker = UIContext.CreateWcfInterface<IClientBroker>("Data/ClientBroker.svc");
clientBroker.BeginSearchForClients(SearchTerm, 20, (result) =>
{
SearchResult[] results = ((IClientBroker)result.AsyncState).EndSearchForClients(result).ToArray();
// do stuff, update UI, etc.
}, clientBroker);
Tier 2: is a WCF web service using basicHttp for Silverlight to call. This is acting as a proxy to the 3rd tier.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
class ClientBroker : IClientBroker
{
[OperationContract] // as defined in IClientBroker
public SearchResult[] SearchForClients(string keywords, int? maxResults)
{
ClientBrokerClient clientBroker = CreateClientBrokerClient();
SearchResult[] searchResults=clientBroker.SearchForClients(keywords, maxResults);
return searchResults;
}
}
Tier 3: is the "server", in that this offers a net.tcp endpoint (allowing secure clients to connect without using Silverlight). This is the ultimate target of a request.
public class ClientBroker : IClientBroker // note this is different to tier 2 interface
{
public SearchResult[] SearchForClients(string keywords, int? maxResults)
{
// do stuff
if (maxResults.HasValue)
{
return results.Take(maxResults.Value).ToArray();
}
else
{
return results.ToArray();
}
}
}
So my calls go:
Silverlight -> httpBasic -> IIS-hosted Proxy WCF service --> net.tcp --> EXE-hosted WCF service
This works well. I can pass headers through the layers, and maintain sessions, etc. And it is pretty trim.
BUT it takes only a few calls through this to cause a Timeout in the communication.
The time the server-EXE takes to do its work is neglible.
The problem I am seeing is that the server "freezes" in returning results to Tier 2.
I think this is to do with a thread getting locked.
I've looked around and see that the ideal way of doing this is to make my Tier 2 run asyncronously, similar to the code below:
public SearchResult[] SearchForClients(string keywords, int? maxResults)
{
ClientBrokerClient clientBroker = CreateClientBrokerClient();
clientBroker.BeginSearchForClients(keywords, maxResults, result =>
{
SearchResult[] searchResults=((ClientBrokerClient)result.AsyncState).EndSearchForClients(result);
// how to return results from here?
}, clientBroker);
}
But how do I achieve this when my Tier 1 client is waiting for the result of this method, which will just drop straight out before the callback execute? Am I missing something on my construction of my OperationContract methods?
UPDATE:
I have since put my server (Tier 3) through its paces from a client avoiding Tier 2 by making many requests from it. Seems the net.tcp WCF channel for Tier 3 is rock solid.
UPDATE 2:
This blog post outlined using the IAsyncResult pattern, which I have eluded to here. Am I barking up the wrong tree here? http://blogs.msdn.com/wenlong/archive/2009/02/09/scale-wcf-application-better-with-asynchronous-programming.aspx
UPDATE 3:
Ok, this paragraph from that blog:
"If you are building N-tier WCF
services, you would have WCF service
operations invoking WCF client proxies
for other backend services. In this
case, you would need to make sure that
the middle-tier (routing layer) has
asynchronous service operation
invoking asynchronous WCF proxy
operations. In this way, your
middle-tier won’t run out of threads
when processing many slow operations."
seems to confirm my suspicions that the problem lies in the middle layer (Tier 2). How can I achieve this Begin/End asynchrony? Do I have to do this manually or can I retain VS tools to generate the proxy classes for me? (REALLY don't want to have to do this manually, the contracts have a degree of flux in them)
Well, I think I've solved it. This topic helped me:
wcf service stops after few requests
Basically, I hadn't been closing my client proxies in my Tier 2, which I realise would cause blocking. The evolution of the code was such that I ended up removing using() {} blocks to facilitate exceptions not getting extinguished with the client proxy. However, I have restructured and retested and my Tier 2 code now looks like:
public SearchResult[] SearchForClients(string keywords, int? maxResults)
{
ClientBrokerClient clientBroker = CreateClientBrokerClient();
SearchResult[] searchResults=clientBroker.SearchForClients(keywords, maxResults);
clientBroker.Close();
return searchResults;
}
... and exceptions are not extinguished.
Related
TL;DR:
What is a good and testable way to implement the dependency between the ViewModels and the WCF services in a MVVM client?
Please read the rest of the question for more details about the problems I encountered while trying to do this:
I am working on a silverlight client that connects to a wcf service, and I want to write unit tests for the client.
So I'm looking for a good solution for using the wcf clients in my ViewModels and testing that interaction. I have found two solutions until now:
Solution 1: This is actually how I have implemented it until now:
public class ViewModelExample
{
public ViewModelExample(IServiceClient client)
{
client.DoWorkCompleted += ..
client.DoWorkAsync();
}
}
//This is how the interface looks like
public interface IServiceClient
{
event EventHandler<AsyncCompletedEventArgs> DoWorkCompleted;
void DoWorkAsync();
}
//I was able to put the interface on the generated clients because they are partial classes, like this:
public partial class GeneratedServiceClient : IServiceClient
{
}
The good part: it's relatively easy to mock
The bad part: my service client lives as long as my ViewModel, and when I have concurrent requests I don't know which answer belongs to which request.
Solution 2: Inspired by this answer
WCF Service Client Lifetime.
public class ViewModelExample
{
public ViewModelExample(IServiceFactory factory)
{
var client = factory.CreateClient();
client.DoWorkCompleted += ...
client.DoWorkAsync();
}
}
The good part: each request is on a different client, so no more problems with matching requests with answers.
The bad part: it's more difficult to test. I would have to write mocks for both the factory and the wcf client every time. This is not something I would like to do, since I alreay have 200 tests... :(
So my question is, how do you guys do it? How do your ViewModels talk to the wcf services, where do you inject the dependency, and how do you test that interaction?
I feel that I'm missing something..
Try having a Func<IServiceClient> injected into your VM instead of the a client instance; you'll have a 'language-level factory' injected instead of building a class for this. In the factory method you can instantiate your client however you want (each access could create a new instance for that for example).
The downside is that you'll still have to touch your tests for the most part, but I assume it will be less work:
public ViewModelExample(Func<IServiceClient> factoryMethod)
{
var client = factoryMethod();
client.DoWorkCompleted += ...
client.DoWorkAsync();
}
The WCF service should have it's own tests that confirm the functionality of itself.
You should then be mocking this WCF service and writing unit tests within your consumers.
Unfortunately, it's a pain and something we all have to do. Be pragmatic and get it done, it will save you getting bitten in the future.
Are you using IoC container by a chance? If you had, this problem would be totally mitigated by container (you'll simply register IService dependency to be created as brand new upon each request).
If that's not the case, then
I would have to write mocks for both the factory and the wcf client every time
is how you deal with this kind of "problems". The cost is relatively small, probably 2-3 extra lines of code per test (all you have to do is setup factory mock to return service mock, which you do need either way).
Imagine I have the following, standard WCF, code :
[ServiceContract]
interface ICustomerService {
[OperationContract]
Customer GetCustomer();
}
public ICustomerService {
public Customer GetCustomer()
{
return MyStore.WhatIsNeeded();
}
}
This is working well and allows me to distribute the service and the consuming code.
Is it possible (and is it a good idea) to completely bypass the WCF engine if working in a single box ?
In fact, I want the app to be able to run on farm servers, or on small single box servers.
To reduce WCF messaging cost, I'd like to have something like :
ICustomerService service = null;
if(singlebox)
{
service = new CustomerService(); // Direct instanciation of the service class. No WCF here ...
}
else
{
service = new CustomerServiceClient(); // Wcf client
}
var cust = service.GetCustomer();
If wrapped properly, can this technique reduce server charge ?
That won't work because the client will be attempting to access an endpoint for a service that no longer is exposing one. The WCF plumbing is required for the both the service and the client. For single box scenarios, look at the NetNamedPipeBinding which is the WCF plumbing done through the equivalent of shared memory.
This will surely reduce the overhead of WCF runtime. I'd create a factory class which will check if(singlebox) and new up the right implementation of ICustomerService.
I'm developing a service oriented architecture for an application and I would like the services to be exposed both over WCF as well as usable through a simple library. Ideally I would like to reduce duplicated code.
Conceptually, this maps to:
Client => WCF Service => Service Library (actual implementation)
or
Client => Service Library (actual implementation)
based on where the client is located (local or remote).
Here's a simple example:
[ServiceContract]
public interface ICalculator
{
[OperationContract]
int Add(int a, int b);
}
public class Calculator : ICalculator
{
public int Add(int a, int b)
{
return a + b;
}
}
public class CalculatorFactory
{
public static ICalculator CreateCalculator()
{
return new Calculator();
}
}
And my client application did the following
int result = CalculatorFactory.CreateCalculator().Add(1,2);
or
int result = IChannelFactory<ICalculator>().CreateChannel().Add(1,2);
depending on if it were local or remote.
Is it a bad practice to call into WCF annotated code directly (i.e., without using WCF)?
Additional comments:
I realize that I could use WCF in all cases and just host the service using NamedPipes for local connections. I would like to avoid this if I can for simplicity sake.
The alternative to the above is to essentially duplicate the ICalculator interface in the service library and change the WCF service implementation to contain CalculatorFactory.CreateCalculator().Add(1,2). This seems like a lot of overhead given that I want the interface to be the same.
You can create and consume WCF annotated classes localy without any problems unless you start to use some WCF related features like OperationContext etc.
Generally this is useually abstracted in different way:
Client => ServiceAgent => Business Service
or
Client => ServiceAgent => WCF Service => Business service
The client itself doesn't know if the service is local all remote. The service agent is client side component which based on its implementation either creates local service instance or callse remote WCF service which in turn creates business service instance. ServiceAgent can be injected as dependency into client which will make your application pretty good configurable. Also you can expose different interface on the service agent (the same as business service implements) and if you want WCF service and proxy can use different one.
If you decite to use WCF service all the time including local calls don't use NamedPipes. NamedPipes are for inter process communication on the same machince. If you want to use communication in the same process use NullTransport or Local Channel instead. It still has worse performance then direct call.
I'm putting together a WCF service using net.tcp and netTcpBinding to get duplex comms with my Silverlight client. I call into the service from the Silverlight app and the service calls out to another server, passing it a callback method in the WCF service class. The remote server calls back several times and each time it does, the WCF service uses the callbackchannel to send the data to the Silverlight client. It all works nicely most of the time.
If the user puts in a big request, I get a TimeoutException after a large number of callbacks have already worked. (Clearly, there's some work to do elsewhere to prevent this but I'd like to robustify the service, first.)
I was expecting to do some kind of 'if (client.ConnectionState == faulted)' check before trying to call back to the Silverlight client but I can't seem to find the object that holds the state of the connection. Is there one? Am I approaching this from the wrong side?
This is my first venture into a service net.tcp and duplex. I just moved house and my WCF bible is still in a box. Somewhere. :-) So, I can't do my usual background reading.
Any pointers would be gratefully received. Here's some bare code in case my description is too soupy:
private IActiveDirectoryClient client;
private AsyncSearchRunner runner;
public void Search(Request request)
{
this.client = OperationContext.Current.GetCallbackChannel<IActiveDirectoryClient>();
runner = new AsyncSearchRunner();
runner.Run(request.SearchRoot, request.SearchFilter, request.PageSize,
System.DirectoryServices.Protocols.SearchScope.Subtree, SendObjects);
}
private void SendObjects(List<DirectoryObject> items)
{
Response response = new Response();
response.DirectoryObjects = items.ToArray();
client.SendResponse(response);
}
Yes, there is a State property that is defined in the ClientBase<> class (all the proxy classes are derived from ClientBase<>).
There are some proxy wrappers out there that handle fault states of the connection and re-establish connections as needed. Google for "wcf proxy wrapper".
You can also home-brew something if you use some kind of ServiceLocator pattern.
I have a WPF appliction that uses WCF services to make calls to the server.
I use this property in my code to access the service
private static IProjectWcfService ProjectService
{
get
{
_projectServiceFactory = new ProjectWcfServiceFactory();
return _projectServiceFactory.Create();
}
}
The Create on the factory looks like this
public IProjectWcfService Create()
{
_serviceClient = new ProjectWcfServiceClient();
//ToDo: Need some way of saving username and password
_serviceClient.ClientCredentials.UserName.UserName = "MyUsername";
_serviceClient.ClientCredentials.UserName.Password = "MyPassword";
return _serviceClient;
}
To access the service methods I use somethingn like the following.
ProjectService.Save(dto);
Is this a good approach for what I am trying to do? I am getting an errorthat I can't track down that I think may be realted to having too many service client connections open (is this possible?) notice I never close the service client or reuse it.
What would the best practice for WCF service client's be for WPF calling?
Thanks in advance...
You're on the right track, I'd say ;-)
Basically, creating the WCF client proxy is a two-step process:
create the channel factory
from the channel factory, create the actual channel
Step #1 is quite "expensive" in terms of time and effort needed - so it's definitely a good idea to do that once and then cache the instance of ProjectWcfServiceFactory somewhere in your code.
Step #2 is actually pretty lightweight, and since a channel between a client and a service can fall into a "faulted state" when an exception happens on the server (and then needs to be re-created from scratch), caching the actual channel per se is less desirable.
So the commonly accepted best practice would be:
create the ChannelFactory<T> (in your case: ProjectWcfServiceFactory) once and cache it for as long as possible; do that heavy lifting only once
create the actual Channel (here: IProjectWcfService) as needed, before every call. That way, you don't have to worry about checking its state and recreating it as needed
UPDATE: "what about closing the channel?" asks Burt ;-) Good point!!
The acccepted best practice for this is to wrap your service call in a try....catch....finally block. The tricky part is: upon disposing of the channel, things can do wrong, too, so you could get an exception - that's why wrapping it in a using(....) block isn't sufficient.
So basically you have:
IProjectWcfService client = ChannelFactory.CreateChannel();
try
{
client.MakeYourCall();
}
catch(CommunicationException ce)
{
// do any exception handling of your own
}
finally
{
ICommunicationObject comObj = ((ICommunicationObject)client);
if(comObj.State == CommunicationState.Faulted)
{
comObj.Abort();
}
else
{
comObj.Close();
}
}
And of course, you could definitely nicely wrap this into a method or an extension method or something in order not to have to type this out every time you make a service call.
UPDATE:
The book I always recommend to get up and running in WCF quickly is Learning WCF by Michele Leroux Bustamante. She covers all the necessary topics, and in a very understandable and approachable way. This will teach you everything - basics, intermediate topics, security, transaction control and so forth - that you need to know to write high quality, useful WCF services.
Learning WCF http://ecx.images-amazon.com/images/I/41wYa%2BNiPML._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg
The more advanced topics and more in-depth look at WCF will be covered by Programming WCF Services by Juval Lowy. He really dives into all technical details and topics and presents "the bible" for WCF programming.