3

我们通过 WCF 提供服务。我们在 SQL Server 中的数据是使用实体框架、Automapper 和 DTO 公开的。

我们很乐意在 DTO 中提供属性,但不确定如何实现我们希望在类库中保存的其他方法。

我们不想将整个服务的所有方法都放在一个 WCF 服务实现中,而是只引用在类库中实现的方法。

我们如何通过类库实现业务逻辑层,通过 WCF 暴露给表示层并使用 DTO 传递数据?

公开的类方法是否引用了 DTO?类库应该按层拆分吗?

服务元素

[服务合同]

public interface Interface1
{
    [OperationContract]
    Class1 GetClass1(int id);

    [OperationContract]
    Class2 GetClass2(int id);
}

类库元素

public class Class1 : Interface1
{
    public Class1 GetClass1(int id) { 
        // implementation

    }
}

public class Class2 : Interface1
{
    public Class2 GetClass2(int id)
    {
        // implementation

    }

}

DTO

[DataContract]
public class Class1
{
    [DataMember]
    public int x { get; set;}
}

[DataContract]
public class Class2
{
    [DataMember]
    public int y { get; set;}
}
4

3 回答 3

1

让我首先澄清一下(我认为)你想要做什么:

您有一些希望通过 WCF 公开的业务逻辑,最终将由您的表示层使用。业务逻辑涉及访问数据库和使用 ORM 和 AutoMapper。出于您的问题的目的,我认为此实现的细节是无关紧要的。

让我们对它的外观进行第一次迭代(我会将不同的命名空间分离到不同的程序集中):

namespace Contracts
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        Data GetData(int id);
    }

    [DataContract]
    public class Data
    {
        [DataMember]
        public string PropertyValue { get; set; }
    }
}

namespace ClassLibrary
{

    public class BusinessLogicImplementation: IMyService
    {
        public Data GetData(int id)
        {
            /**
             * Do data retrieval here, which returns returnedData
             * */
            DataModel returnedData;
            return Mapper.Map<DataModel, Data>(returnedData);
        }
    }
}

namespace EntityFrameworkModel
{

    public class DataModel
    {
        public string PropertyValue { get; set; }
    }
}

Contracts 程序集包含对服务和客户端都公开的数据。客户端可以通过对程序集的二进制引用或拥有自己的本地合同实现(如 Visual Studio 服务引用)的客户端来使用它。

类库程序集包含数据检索和业务逻辑的实现。我还展示了数据模型-但仅用于额外的上下文-我认为这与您的问题无关:

到目前为止,我们已经回答了您的部分问题:

“我们如何通过类库实现业务逻辑层,通过 WCF 暴露给表示层并使用 DTO 传递数据?”

接下来让我们考虑查询的第一部分:

“我们不想将整个服务的所有方法都放在一个 WCF 服务实现中,而是只引用在类库中实现的方法。”

尽管您没有明确建议,但这表明您的 WCF 服务公开的方法多于与您的客户端相关的方法。您希望使客户看到的界面简洁且与他们想要实现的目标相关,这是非常正确的。

这是通过在由不同接口表示的服务上公开不同端点来实现的。在代码方面,我在业务逻辑的实现和通过 WCF 公开的实现之间添加了一个额外的层:

namespace Contracts
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        Data GetData(int id);
    }

    [DataContract]
    public class Data
    {
        [DataMember]
        public string PropertyValue { get; set; }
    }
}

namespace MoreContracts
{
    [ServiceContract]
    public interface IOtherService
    {
        [OperationContract]
        MoreData GetMoreData(int id);
    }

    [DataContract]
    public class MoreData
    {
        [DataMember]
        public string MorePropertyValue { get; set; }
    }
}

namespace Service
{
    /**
     * This class adds an extra layer between the exposed functionality and the implementation.
     * It effectively is used for hosting all the business logic you want to expose over the service,
     * including that contained in ClassLibrary and anywhere else.
     * */
    public class ServiceImplementation: IMyService, IOtherService
    {

        public Data GetData(int id)
        {
            return new BusinessLogicImplementation().GetData(id);
        }

        public MoreData GetMoreData(int id)
        {
            //Implementation of logic not in class library
        }
    }
}

namespace ClassLibrary
{
    public class BusinessLogicImplementation : IMyService
    {
        public Data GetData(int id)
        {
            /**
             * Do data retrieval here, which returns returnedData
             * */
            DataModel returnedData;
            return Mapper.Map<DataModel, Data>(returnedData);
        }
    }
}

在线快速搜索将向您展示在托管方案中托管具有多个 endoint 的服务所需的操作。例如,对于自托管,请参阅Run WCF ServiceHost with multiple contract

于 2013-09-25T11:18:07.160 回答
1

是的,您可以将类库用于 WCF 服务(在 Visual Studio 中的 WCF 下有一个用于 WCF 类库的项目)。这个类库将保存服务契约的实现——服务契约也可以在类库中定义,或者可以在类库引用的另一个程序集中。

然后需要托管此类库(IIS、自托管或 Windows 服务)。我们在工作中这样做 - 我们有一个 n 层应用程序,它使用 WCF 在各层之间进行通信,并且所有服务本身都在类库中实现并托管(通常在 IIS 中,在一种情况下在 Windows 服务中) .

采用您发布的代码的修改版本(您应该为实现类和 DTO 使用不同的名称),您可以执行以下操作:

类库

[ServiceContract]
public interface Interface1
{
    [OperationContract]
    Class1 GetClass1(int id);

    [OperationContract]
    Class2 GetClass2(int id);
}


public class Service1 : Interface1
{
    public Class1 GetClass1(int id) 
    { 
        // implementation
    }

    public Class2 GetClass2(int id)
    {
        // implementation
    }
}

请注意,有一个服务类,它实现了服务定义 ( Interface1) 中定义的两个操作契约。您发布的代码不会编译,因为这两个类都没有实现接口中定义的两种方法(由于它们的返回类型,您至少还会收到关于类名的警告)。

然后,您可以将对该类库的引用添加到您拥有 DTO(Class1Class2)的程序集中。

要在自托管方案或 Windows 服务中托管它,您需要对类库(Service1在我的示例中)的引用以及对 DTO 程序集的引用。然后您将为该服务实例化一个服务主机,如下所示:

baseAddress = new Uri("some address");

ServiceHost myHost = new ServiceHost(typeof(Service1), baseAddress);

myHost.Open();

要在 IIS 中托管,您需要修改 .svc 文件标记,如下所示:

<%@ ServiceHost Language="C#"
                Service="MyCompany.Service1"
                Factory="System.ServiceModel.Activation.ServiceHostFactory" %>

您需要使用完整的命名空间来完全限定服务名称,因此假设命名空间 forService1MyCompany完全限定的名称将是MyCompany.Service1.

最后,您需要将相关system.serviceModel部分放在相应托管应用程序的 app.config 或 web.config 文件中,因为库使用其消费应用程序的配置文件,而不是它们自己的。

这个主题有许多微妙的变化(在我们的例子中,我们使用自定义服务主机和自定义服务主机工厂,并且接口 - 服务合同 - 位于单独的程序集中,这允许我们通过ChannelFactory<T>.

要回答您的最后一个问题,如果类库要使用它们,则必须引用包含您的 DTO 的程序集,并且您可以拆分您的服务类库,但您认为适合您的要求 - 我肯定会拆分如果您有多个应用程序,它们至少按层,也可能按垂直堆栈。

于 2013-09-24T03:32:14.403 回答
1

如果我正确理解你的问题。您不希望所有自动公开的方法。如果您只想抽象少数方法,那么您在服务和类服务中也共享通用 DTO。

于 2013-09-20T16:02:47.830 回答