创建通用 WCF 服务的模式






4.27/5 (3投票s)
一种创建泛型 WCF 服务的方法。
引言
我正在开发一个大量使用泛型的解决方案。我们刚刚开始向该解决方案添加 Silverlight 控件,并使用 WCF 与现有的代码库进行通信。
我一直在寻找一种解决方案,以便我们可以拥有利用现有泛型模型的泛型服务。我没有找到我想要的东西,所以我创建了一个测试项目,展示了一种泛型服务的模式,并希望听听大家的意见。
Using the Code
该项目包含一个基本服务类和一个对应的泛型契约类。
[ServiceContract]
interface IBaseService<T> where T : class, INumber
{
[OperationContract]
string GetData(int value);
}
public class BaseService<T> : IBaseService<T>
where T : class, INumber
{
private T _num;
public BaseService(INumberFactory<t> numberFactory)
{
_num = numberFactory.Create();
}
public string GetData(int value)
{
var ret = value * _num.Get();
return ret.ToString();
}
}
这个基本服务类还具有一个依赖项,该依赖项将根据 T
的类型来解析。这只是一个基本的工厂类,它将为我们的不同类型类创建实例。
这是接口 INumber
以及几个基本的实现。
public class NumberOne : INumber
{
public int Get()
{
return 1;
}
}
public class NumberTwo : INumber
{
public int Get()
{
return 2;
}
}
public interface INumber
{
int Get();
}
下一步是声明一些 .svc 文件,每个我们希望服务使用的类型一个;在本例中,一个用于 NumberOne
,一个用于 NumberTwo
。在这里,我们需要指定类型类的完整程序集详细信息。
ServiceOne.svc
<%@ ServiceHost Language="C#" Debug="true"
Service="Service.BaseService`1[[Service.NumberOne, Service,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
Factory="Service.Host.Factory" %>
ServiceTwo.svc
<%@ ServiceHost Language="C#" Debug="true"
Service="Service.BaseService`1[[Service.NumberTwo, Service,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
Factory="Service.Host.Factory" %>
如你所见,这里我们使用一个 Factory
类来创建服务主机的实例。这允许我们使用自定义 ServiceHost
类。
public class Factory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = new UnityServiceHost(serviceType, baseAddresses);
return host;
}
}
我们自定义的服务主机类将添加一个新的行为,允许我们操作服务的端点。
public class UnityServiceHost : ServiceHost
{
private IUnityContainer _unityContainer;
public UnityServiceHost(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
base.OnOpening();
if (this.Description.Behaviors.Find<unityservicebehavior>() == null)
this.Description.Behaviors.Add(new UnityServiceBehavior());
}
}
对于服务上的每个端点,我们现在都应用一个自定义实例提供程序。
public class UnityServiceBehavior : IServiceBehavior
{
private readonly IUnityContainer container;
public UnityServiceBehavior()
{
}
public void Validate(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase, Collection<serviceendpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
string contractName = endpointDispatcher.ContractName;
if (contractName != "IMetadataExchange" &&
contractName != "IHttpGetHelpPageAndMetadataContract")
{
ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(
e => e.Contract.Name == contractName);
endpointDispatcher.DispatchRuntime.InstanceProvider =
new UnityInstanceProvider(serviceEndpoint.Contract.ContractType);
}
}
}
}
}
这个实例提供程序现在将使用 Unity 来创建服务及其所有依赖项。
public class UnityInstanceProvider : IInstanceProvider
{
private readonly Type contractType;
public UnityInstanceProvider(Type contractType)
{
this.contractType = contractType;
}
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return IocManager.Container.Resolve(contractType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
IocManager.Container.Teardown(instance);
}
}
最后,我们有 IocManager
,它包含我们依赖项的配置。
public class IocManager
{
private static IUnityContainer _container;
private static object _syncRoot = new object();
public static IUnityContainer Container
{
get
{
if (_container == null)
lock (_syncRoot)
{
_container = GetIocContainer();
}
return _container;
}
}
private static IUnityContainer GetIocContainer()
{
IUnityContainer container = new UnityContainer();
ConfigureUnityContainer(container);
return container;
}
private static void ConfigureUnityContainer(IUnityContainer container)
{
container.RegisterType<ibaseservice<numberone>,
BaseService<numberone>>();
container.RegisterType<ibaseservice<numbertwo>,
BaseService<numbertwo>>();
container.RegisterType<inumberfactory<numberone>, NumberFactoryOne>();
container.RegisterType<inumberfactory<numbertwo>, NumberFactoryTwo>();
}
}
关注点
我认为这是一种创建泛型服务的好方法。我不太喜欢的是,我需要在 .svc 类中包含类型声明的所有程序集信息,因为这可能会变成一个维护噩梦。
但我很乐意听听其他人对这个设计的想法。