tags:

views:

282

answers:

1

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...

+1  A: 

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

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.

Programming WCF Services

marc_s
What about closing the channel?
Burt
Thanks, this has cleared things up a bit, I really need to buy a WCF book (any recommendations would be welcome).
Burt
Why is the catch and finally essentially doing the same things i.e. comObj.Abort?Is there any need for abort in the catch?
Burt
@Burt: you're right - since the finally block really handles this all, the catch block doesn't need to do a call to .Abort() itself. Also added my book recommendations
marc_s