WCF-共享类型的不同实现

WCF - different implementation of shared types
2020-11-25
  •  译文(汉语)
  •  原文(英语)

我正在尝试设计客户端/服务器应用程序,它将能够交换"命令".事实是,该服务器应用程序正在处理一些东西,我希望客户端能够例如向服务器发送命令"pause".

经理建议,最好的方法是创建接口(例如ICommand),然后为将从ICommand继承的每个命令(暂停,恢复)分类.之后,我们可以简单地使用[DataContract]属性创建一个对象Pause,该对象将被发送到服务器.为此,我尝试使用共享类型,因此我创建了分离的程序集,在其中设计了所有[DataContracts],以便服务器和客户端都可以使用它们(它们具有指向它们的引用).

在服务器上,我们将有[OperationContract],它将[DataContract]作为参数并同样返回[DataContract],如下所示:

[ServiceKnownType(typeof(PauseServer))]
[ServiceKnownType(typeof(Resume))]
[ServiceContract]
public interface ITestService
{
     [OperationContract]
    ICommand DoCommand(ICommand command);
}

问题是,除了某些属性之外,我们还想使用例如"Execute(param1,param2)"方法,该方法将执行某些操作-该方法将在服务器上执行不同的操作(暂停进程),并在服务器上执行不同的操作客户端(例如,更改状态并启用"恢复"按钮).像这样:

[DataContract(Namespace="PauseContract")]
public class Pause
{
    string _param1;
    int _param2;

    public void Execute()
    {
       // DO SOMETHING HERE
    }

    [DataMember]
    public string Param1
    {
        get
        {
            return _param1;
        }
        set
        {
            this._param1 = value;
        }
    }

    [DataMember]
    public int Param2
    {
        get
        {
            return _param2;
        }
        set
        {
            this._param2 = value;
        }
    }
}

最后,整个过程将是这样的:1)客户希望暂停该过程,因此它创建了对象"Pause",其中将包含例如该过程的ID.2)该对象传递给DoCommand()方法,该方法在服务器端创建对象"Pause",并使用给定参数运行其"Execute()"方法.3)如果Pause进程结束得很好,Pause对象将返回给客户端(带有进程ID和其他属性)4)如果客户端收到此响应,它将知道该进程已经暂停并运行自己的"Execute()"方法在其自己的Pause对象上,这将更改GUI等.

所以我的问题是-是否有可能以不同的方式在服务器/客户端双方的公共库中存储合同的实现?还是这种方法通常是错误的?据我所知,不建议将行为(方法)包括在[DataContracts]中,但是我认为如果不使用[DataMember]属性对其进行标记,那就可以了.

谢谢你,雅库布.

速聊1:
是的,将行为放置在DataContracts中是不好的做法,因为它们的目的只是为了包含数据.暂停,恢复等的行为/实现也由服务器完成,与客户端无关(关注点分离).因此,您不想与客户端共享实现,因为如果要对实现进行更改,则还需要将共享程序集重新部署到客户端.使用WCF,您应该将公开的服务引用从服务器链接到客户端.这将使用WSDL生成代理以与服务器进行通信.
解决过程1

老实说,我认为带有ServiceKnownType属性的ICommand不适用于命令.

ServiceKnownType旨在在类型属性而非行为的上下文中跨服务边界支持多态.

通过交换两个不同的请求/响应DataContract定义,可以非常轻松地实现您的"暂停/恢复"方案.

速聊1:
你好汤姆.因此,您的建议是,我应该创建2个数据协定,然后创建OperationContract方法,该方法如下所示:"Response DoCommand(Request request)",而请求将执行Pause / Resume操作?
速聊2:
是的,尽管您的操作合同应明确命名,例如:-PauseResponse PauseProcessing(PauseCommand command);在这种情况下,无需使事物通用
速聊3:
我懂了.我只是以为如果我有更多的命令,那么如果我坚持泛型声明,然后使用Activator或类似的东西创建对象,可能会更加清楚.但是我想我现在可以坚持简单的操作合同.感谢您的建议:).
速聊4:
即使实现了通用处理程序并且需要添加新型命令,也很难避免必须重新编译.

I am trying to design client/server application, that would be able to exchange "commands". The thing is, that server application is processing some stuff and I would like the client to be able to for example send command "pause" to the server.

The thing is, that my manager suggested, that best approach would be to create interface (ICommand for example) and then class for each command (Pause, Resume) that would inherit from the ICommand. After that, we could simply create an object Pause with [DataContract] attribute, that would be sent over to server. For that purpouse, I tried to use shared-types, so I created seprated assembly in which I designed all the [DataContracts], so that both server and client can use them (they have reference leading to them).

On the server, we would then have [OperationContract], that would take the [DataContract] as parameter and return [DataContract] as well, like this:

[ServiceKnownType(typeof(PauseServer))]
[ServiceKnownType(typeof(Resume))]
[ServiceContract]
public interface ITestService
{
     [OperationContract]
    ICommand DoCommand(ICommand command);
}

The problem is, that apart from some properties, we would like to have for example method "Execute(param1,param2)", that would do certain operation - this method would do different operation on server (pause the process) and different operation on client side (change the status and enable "Resume" button for example). Like this:

[DataContract(Namespace="PauseContract")]
public class Pause
{
    string _param1;
    int _param2;

    public void Execute()
    {
       // DO SOMETHING HERE
    }

    [DataMember]
    public string Param1
    {
        get
        {
            return _param1;
        }
        set
        {
            this._param1 = value;
        }
    }

    [DataMember]
    public int Param2
    {
        get
        {
            return _param2;
        }
        set
        {
            this._param2 = value;
        }
    }
}

In the end, the whole process would like this: 1) Client wants to pause the process, so it creates object "Pause", that would contain for example ID of the process. 2) This object is passed to the DoCommand() method, which creates object "Pause" on server side and run its "Execute()" method with the given parameters. 3) If the Pausing process ended well, the Pause object is returned back to client (with process ID and other attributes) 4) If client gets this response, it will know that the process has eben paused and run its own "Execute()" method on its own Pause object, that would change the GUI and so on.

So my question is - is it somehow possible, to have different implementation of contracts stored in common library on both server/client side? Or is this approach wrong in general? From what I have heards, it is not advised to include behaviour (methods) to [DataContracts], but I thought it would be ok, if I dont mark them with [DataMember] attribute.

Thank You, Jakub.

Talk1:
Yes, it is bad practice to place behavior in DataContracts for their purpose is only to contain data. Also the behavior/implementation of Pause, Resume etc. is done by the server and is no concern to the client (separation of concerns). Ergo, you don't want to share the implementation with the client for if changes are to be made to the implementation, you would need to redeploy the shared assembly to the client as well. Using WCF,you should rather link the exposed service reference from the server to your client. This will use the WSDL to generate your proxies to communicate with the server.
Solutions1

To be honest, I don't think the ICommand with ServiceKnownType attribute idea works well for commands.

ServiceKnownType is designed to support polymorphism across service boundaries in the context of type properties and not behavior.

Your Pause/Resume scenario would be very easily implement with the exchange of two distinct request/response DataContract definitions.

Talk1:
Hello Tom. So what you suggest is that I should create 2 data contracts and then OperationContract method, that would look like this: "Response DoCommand(Request request)", while the request would execute Pause/Resume operation?
Talk2:
Yes, though your operation contract should be explicitly named, like: - PauseResponse PauseProcessing(PauseCommand command); There is no need to make things generic in this instance
Talk3:
I see. I just thought that in case I have more commands, it would be maybe more clear if I stick to generic declaration and after that, create objects using Activator or something. But I Guess I can stick with simple operation contracts for now. Thank for your advice :).
Talk4:
Even if you implemented a generic handler and you needed to add a new type of command it would be difficult to avoid having to recompile.
转载于:https://stackoverflow.com/questions/28028462/wcf-different-implementation-of-shared-types

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入