Using Remoting with CAB

Anyone who has ttried to add a service implemented through Remoting to the WorkItem's services collection was sadly surprised that it can't be done.

But why?

When we use the following code:

WorkItem.Services.Add<IServiceContract>(serviceInstance);

It comes to something like this:

if (!typeof(IServiceContract).IsAssignableFrom(serviceInstance.GetType())
	throw new ArgumentException();

And how do we solve this problem?

easy: generics.

All we need to do is make some changes to the ServiceCollection class.

We change the Add<TService>(TService serviceInstance) method to look like this:

public void Add<TService>(TService serviceInstance) 
{ 
	Guard.ArgumentNotNull(serviceInstance, "serviceInstance"); 

	Build<TService>(serviceInstance); 
} 

At this point we need to refactor the Build(Type typeToBuild, Type typeToRegisterAs, object serviceInstance) method to have two entry points to the common its logic:

private object Build(Type typeToBuild, Type typeToRegisterAs, object serviceInstance) 
{ 
	Guard.TypeIsAssignableFromType(typeToBuild, typeToRegisterAs, "typeToBuild"); 

	return BuildImplementation(typeToBuild, typeToRegisterAs, serviceInstance); 
} 

private TService Build<TService>(TService serviceInstance) 
{ 
	return (TService)BuildImplementation(serviceInstance.GetType(), typeof(TService), serviceInstance); 
} 

private object BuildImplementation(Type typeToBuild, Type typeToRegisterAs, object serviceInstance) 
{ 
	if (locator.Contains(new DependencyResolutionLocatorKey(typeToRegisterAs, null), SearchMode.Local)) 
		throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Properties.Resources.DuplicateService, typeToRegisterAs.FullName)); if (serviceInstance == null) serviceInstance = BuildFirstTimeItem(typeToBuild, typeToRegisterAs, null); else if (!container.Contains(serviceInstance)) serviceInstance = BuildFirstTimeItem(typeToBuild, typeToRegisterAs, serviceInstance); else BuildRepeatedItem(typeToRegisterAs, serviceInstance); return serviceInstance; }

Easy, isn't it? And I suspect that that's not the only improvement like this that we can get into CAB.

Oh! And why would we wanto to use Remoting? To use NMock2 in the unit tests, of course!

Updated: November 14th, 2006

Changed:

private TService Build<TService>(object serviceInstance)
{
	Guard.TypeIsCompatibleType<TService>(serviceInstance, "typeToBuild");
return (TService)BuildImplementation(serviceInstance.GetType(), typeof(TService), serviceInstance); }

Removed:

And add the TypeIsCompatibleType<T>(object providedInstance, string argumentName) method to the Guard class:

public static void TypeIsCompatibleType<T>(object providedInstance, string argumentName) 
{ 
	if (!(providedInstance is T)) 
		throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Properties.Resources.TypeNotCompatible, typeof(T), providedInstance.GetType()),
argumentName); }

2 Responses to Using Remoting with CAB

  • Nikolay says:

    Paulo, this resolves problem in Add<TService>(TService), but in other places CAB calls method Equals of remote object and fails… How to workaround this? Wrapping all remote services with local objects could help but is quite ugly solution.

  • I ran across this when using NMock and this solved my unit testing problems at the moment.

    In which CAB method are you having problems?