65.9K
CodeProject 正在变化。 阅读更多。
Home

创建通用 WCF 服务的模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (3投票s)

2011年11月28日

CPOL

2分钟阅读

viewsIcon

46653

downloadIcon

1075

一种创建泛型 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 类中包含类型声明的所有程序集信息,因为这可能会变成一个维护噩梦。

但我很乐意听听其他人对这个设计的想法。

© . All rights reserved.