tags:

views:

533

answers:

3

I'm running a WCF service, and calling ServiceHost's Open() method will raise an AddressAlreadyInUseException if the adress is ..err .. already in use !

Is there a way to test whether the address is available without raising an exception?

+2  A: 

The addresses being used by the ServiceHost are listed in ServiceHost.BaseAddresses. You could potentially check there, prior to making your call.

Alternatively, just try to open the service, and catch and handle the AddressAlreadyInUseException gracefully. If you receive that, you know it's in use, and you can move on to your secondary logic.

Reed Copsey
in my scenario, another instance of the server is using the address. If I understand correctly, ServiceHost.BaseAddresses only contains the addresses that will be used by the current process if I call Open on the ServiceHost. Your alternate solution is what I do right now, but I'd rather avoid raising unnecessary exceptions if I can...
Brann
If it's a separate server using the address, then handling the exception IS the best option.
Reed Copsey
handling the reception forces me to recreate a new ServiceHost object, as the current one is in the Faulted state and cannot be used anymore.
Brann
Unfortunately, that's the only truly failsafe way to do this. Kyoru's answer is actually correct, in this case, since you're not locking on a resource you control (it's a separate server using the address), so no sync. concept will work. Your only true, failsafe option, is to try to acquire the resource (connection), and catch the exceptional cases. I agree that it's not convenient to deal with this, and exceptions should avoided when not necessary, but this is one of the good use cases for exceptions.
Reed Copsey
in some cases, it's possible to lock a resource directly using the OS. I could also use interprocess mutexes (provided I own the other process, which is the case). And even without synchronization, I could test the availability, and handle the one-in-a-million race condition when it occurs. This would definitely duplicate some logic, but that's a trade-off that can be worth considering in some cases.
Brann
If you control the other process, then yes, you can handle this via a named mutex on the system. If the other process is run on another system, you may not be able to do this, even if you control it. If you're controlling both processes, I'd use a named mutex, and hold it while you're using the server adress. This gives you a single point you can check cross process. Then, you're just trying to acquire a mutex lock instead of doing your network call, and no exceptional case processing required.
Reed Copsey
+1  A: 

You might try a little known feature of WCF endpoint configurations: ListenUriMode.Unique. Skonnard has a really good write-up about this: http://www.pluralsight.com/community/blogs/aaron/archive/2006/04/24/22610.aspx

I don't know if this will handle your current scenario (I don't know if it will detect the collision and whether or not you are ok with it spooling up on a different address), but it just might.

This also might not be a feasible solution if you have no central way of communicating endpoint addresses to your clients (database, etc). WS-Discovery will have a way of getting around this limitation, but you'd have to wait till .NET 4.0 or use one of the open source implementations for WCF 3.5.

Anderson Imes
A: 

You can't.

Consider the code:

        if( AddressIsFree( addr ) )
        {
            OpenServiceOn( addr );
        }

What happens if something else registers the port in that fraction of a second between your check, and when you open the service? It's a race condition.

The correct way to handle this is to just try to open the port, and catch the exception if it fails, and do something to compensate. Exceptions aren't bad. They exist, in part, for this exact reason. There's no reason to try and do lots of checking to make sure than an exception will not be thrown - in most cases, just try the operation, and catch the exception if it occurs.

They're usually not even much more code.

kyoryu
Race conditions can be addressed by proper use of a synchronization mechanism. There are a lot of reason to avoid exceptions (see http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control for example). Or are you advocating using double.parse instead of double.tryparse ?
Brann
This is a race condition with the environment, much like creating a file only if it doesn't exist. So, just like we have file open with exclusive create, the only safe way to do this is to try and catch the exception if it fails. You can't lock the environment. The major reason to avoid exceptions is performance, for instance if you're potentially throwing 100s of exceptions per second. Since in this scenario that's unlikely, my recommendation stands :)
kyoryu