/// <summary> /// Gets data about a service implementation. /// </summary> /// <param name="value"> /// The constructor string passed in to the service host factory /// that is used to determine which type to host/use as a service /// implementation. /// </param> /// <returns> /// A <see cref="ServiceImplementationData"/> /// object containing information about which type to use in /// the service host and how to resolve the implementation. /// </returns> /// <remarks> /// <para> /// This method returns a dynamic proxy object as the type to host /// and resolves the implementation type as a dynamic proxy that proxies /// to a tenant-specific implementation. This is necessary since /// WCF will only allow hosting of concrete classes and we need it to, /// effectively, host an 'interface' - in this case, a dynamic proxy type /// rather than an actual implementation type. /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="value" /> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentException"> /// Thrown if <paramref name="value" /> is empty. /// </exception> /// <exception cref="InvalidOperationException"> /// Thrown if <paramref name="value" /> does not resolve into /// a known type, resolves to a type that is not an interface, or the /// interface it resolves to is not marked with a <see cref="ServiceContractAttribute"/>. /// </exception> public ServiceImplementationData GetServiceImplementationData(string value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (value.Length == 0) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.ArgumentException_StringEmpty, nameof(value))); } Type serviceInterfaceType = Type.GetType(value, false); if (serviceInterfaceType == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.MultitenantServiceImplementationDataProvider_ServiceInterfaceTypeNotResolvable, value)); } if (!serviceInterfaceType.IsInterface) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.MultitenantServiceImplementationDataProvider_ServiceInterfaceTypeNotInterface, value, serviceInterfaceType)); } if (serviceInterfaceType.GetCustomAttributes(typeof(ServiceContractAttribute), false).Length == 0) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.MultitenantServiceImplementationDataProvider_ServiceInterfaceTypeNotServiceContract, value, serviceInterfaceType)); } // To create the actual proxy object type that will be used to sub-in // tenant-specific instances, we need to create a dummy implementation // (which is an empty proxy without a target) and then a real proxy // (which will use that dummy as a target). The reason is that Castle // generates two different proxy types when this happens - the first // proxy type - the dummy object - will be something like "Castle.Proxies.ProxyType" // and the second proxy type - the one with a target - will be // something like "Castle.Proxies.ProxyType_1". Subsequent proxies // created for the same interface type that have a target will be // of the same type as the original - "Castle.Proxies.ProxyType_1" // (or whatever) because Castle caches the various proxy type definitions. var dummyHostProxyObject = _generator.CreateInterfaceProxyWithoutTarget(serviceInterfaceType); var actualHostProxyObject = _generator.CreateWcfProxy(serviceInterfaceType, dummyHostProxyObject); return(new ServiceImplementationData { ConstructorString = value, ServiceTypeToHost = actualHostProxyObject.GetType(), ImplementationResolver = l => { var implementation = l.Resolve(serviceInterfaceType); // The wrapped implementation will be of the same proxy // type as "actualHostProxyObject" above. var implementationProxy = _generator.CreateWcfProxy(serviceInterfaceType, implementation); return implementationProxy; }, }); }
public void CreateWcfProxy_TargetDoesNotImplementInterface() { var generator = new ServiceHostProxyGenerator(); object target = new NotAServiceImplementation(); Type interfaceToProxy = typeof(IServiceContract); Assert.Throws <ArgumentException>(() => generator.CreateWcfProxy(interfaceToProxy, target)); }
public void CreateWcfProxy_NullTarget() { var generator = new ServiceHostProxyGenerator(); object target = null; Type interfaceToProxy = typeof(IServiceContract); Assert.Throws <ArgumentNullException>(() => generator.CreateWcfProxy(interfaceToProxy, target)); }
public void CreateWcfProxy_NullInterface() { var generator = new ServiceHostProxyGenerator(); object target = new ServiceImplementation(); Type interfaceToProxy = null; Assert.Throws <ArgumentNullException>(() => generator.CreateWcfProxy(interfaceToProxy, target)); }
public void CreateWcfProxy_CustomProxyTypeCanBeHosted() { var generator = new ServiceHostProxyGenerator(); object target = new ServiceImplementation(); Type interfaceToProxy = typeof(IServiceContract); var proxy = generator.CreateWcfProxy(interfaceToProxy, target); // XUnit does not have "Assert.DoesNotThrow". new ServiceHost(proxy.GetType(), new Uri("http://localhost:22111/Foo.svc")); }