简体   繁体   English

如何序列化WCF绑定和端点

[英]How to Serialize WCF Bindings and Endpoints

Edit: consider using the information from this post . 编辑:考虑使用此帖子中的信息。

I have a unique client-server configuration that is presenting an interesting problem. 我有一个独特的客户端 - 服务器配置,提出了一个有趣的问题。 The bottom-line question is: 底线问题是:

How can I serialize binding and endpoint configurations for a WCF service? 如何为WCF服务序列化绑定和端点配置?

The Server 服务器
The server consists of a "cloud" of WCF services (call them Alice and Bob) running in their own app domains possibly but not necessary on different machines. 服务器由在他们自己的应用程序域中运行的WCF服务(称为Alice和Bob)的“云”组成,但可能在不同的机器上不必要。 Each service may or may not be able to communicate with another service in the cloud depending on networking constraints and access privileges. 根据网络约束和访问权限,每个服务可能或可能不能与云中的其他服务通信。 In other words, any particular service will know nothing about which other services it can communicate with. 换句话说,任何特定服务都不知道它可以与哪些其他服务通信。 That means no connection info in any of the app.configs. 这意味着任何app.configs都没有连接信息。

The Client 客户端
The client is only able to communicate with exactly one service, Alice, via WCF. 客户端只能通过WCF与一个服务Alice进行通信。 However, the client needs to communicate with other services in the cloud. 但是,客户端需要与云中的其他服务进行通信。 This is accomplished by having Alice forward requests from the client to their intended recipients (plural in reality, but just Bob for the current example). 这是通过让Alice将来自客户端的请求转发给他们的预期接收者来实现的(实际上是复数,但是当前示例只有Bob)。 The client has full knowledge of which services are able to connect to which other services, including binding and address information. 客户端完全了解哪些服务能够连接到哪些其他服务,包括绑定和地址信息。

The Objective 目标
Now suppose the client sends a request to Alice that is intended to be delivered to Bob. 现在假设客户端向Alice发送了一个旨在传递给Bob的请求。 Alice analyzes the request and determines that the message needs to be forwarded to Bob somehow. Alice分析该请求并确定该消息需要以某种方式转发给Bob。 Alice must now construct a channel to Bob using an appropriate binding and endpoint. Alice现在必须使用适当的绑定和端点为Bob构建一个通道。 If Alice had an app.config with all the info, this would not be a problem. 如果Alice有一个包含所有信息的app.config,这不会有问题。 However, as I described above, no such information is available in the app.config. 但是,如上所述,app.config中没有此类信息。 Instead, Alice must use information contained in the original request to construct the channel. 相反,Alice必须使用原始请求中包含的信息来构建通道。

Failed Attempts 尝试失败
I first naively added Binding and EndpointAddress properties to my data contract: 我首先天真地将BindingEndpointAddress属性添加到我的数据协定中:

[DataContract]
public class ConnectivityGraph
{
    [DataMember]
    public string FromNode = "Alice";

    [DataMember]
    public string ToNode = "Bob";

    [DataMember]
    public Binding BobsBinding { get; set; }

    [DataMember]
    public EndpointAddress BobsEndpoint { get; set; }
}

Then the client calls Alice's WCF method like this: 然后客户端调用Alice的WCF方法,如下所示:

private void btnToBobViaAlice_Click(object sender, EventArgs e)
{
    try
    {
        var alice = new HyperNode("Alice");

        // Build the node graph

        var msg = new HyperNodeMessage("HyperNodeTestClient")
        {
            CommandName = "ValidCommand",
            IntendedRecipientNodes = new List<string>
            {
                "Bob"
            },
            HyperNodeConnectivityGraph = new HyperNodeConnectivityGraph
            {
                BobsBinding = new NetHttpBinding(),
                BobsEndpoint = new EndpointAddress("net.tcp://localhost:8001/HyperNode/Bob")
            }
        };

        var result = alice.ProcessMessage(msg);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

However, this resulted in an ungodly exception on the call to alice.ProcessMessage(msg) : 但是,这导致对alice.ProcessMessage(msg)的调用产生了一个不敬虔的异常:

System.ServiceModel.CommunicationException was caught
  HResult=-2146233087
  Message=There was an error while trying to serialize parameter http://tempuri.org/:message. The InnerException message was 'Type 'System.ServiceModel.NetHttpBinding' with data contract name 'NetHttpBinding:http://schemas.datacontract.org/2004/07/System.ServiceModel' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameters(XmlDictionaryWriter writer, PartInfo[] parts, Object[] parameters)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
       at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
       at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.Message.WriteMessage(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
       at System.ServiceModel.Channels.BinaryMessageEncoderFactory.BinaryMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
       at System.ServiceModel.Channels.FramingDuplexSessionChannel.EncodeMessage(Message message)
       at System.ServiceModel.Channels.FramingDuplexSessionChannel.OnSendCore(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.TransportDuplexSessionChannel.OnSend(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.OutputChannel.Send(Message message, TimeSpan timeout)
       at System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at Hyper.Applications.NodeContracts.IHyperNodeService.ProcessMessage(HyperNodeMessage message)
       at Hyper.Applications.NodeProxies.HyperNode.ProcessMessage(HyperNodeMessage message) in c:\GitRoot\Hyper\Hyper.Applications.NodeProxies\HyperNode.cs:line 28
       at HyperNodeTestClient.MainForm.btnToBobViaAlice_Click(Object sender, EventArgs e) in c:\GitRoot\Hyper\HyperNodeTestClient\MainForm.cs:line 72
  InnerException: System.Runtime.Serialization.SerializationException
       HResult=-2146233076
       Message=Type 'System.ServiceModel.NetHttpBinding' with data contract name 'NetHttpBinding:http://schemas.datacontract.org/2004/07/System.ServiceModel' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
       Source=System.Runtime.Serialization
       StackTrace:
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
            at WriteHyperNodeConnectivityGraphToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
            at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
            at WriteHyperNodeMessageToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
            at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
            at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
            at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
            at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
       InnerException: 

Unfortunately, adding KnownType attributes didn't work (for the first 6 attempts) because there arose an endless string of exceptions spanning many, many, many types. 不幸的是,添加KnownType属性不起作用(对于前6次尝试),因为出现了许多,许多,多种类型的无穷无尽的异常串。 Furthermore, this wouldn't even account for all the possible bindings since anyone can create a custom binding using types that I have not explicitly listed in this way. 此外,这甚至不会考虑所有可能的绑定,因为任何人都可以使用我没有以这种方式明确列出的类型创建自定义绑定。

At this point, I realized that the XML for generating binding and address info in the app.config file is actually pretty simple. 此时,我意识到用于在app.config文件中生成绑定和地址信息的XML实际上非常简单。 It seems like all I should have to do is piggy back off of the Configuration class somehow. 看起来我应该做的就是以某种方式从配置类中退回。 Can anyone tell me what I'm missing in what should be a relatively simple serialization problem? 任何人都可以告诉我在什么应该是一个相对简单的序列化问题中我缺少什么?

First of all , I don't think you can serialize Binding and EndpointAddress classes. 首先,我认为您不能序列化BindingEndpointAddress类。 (You may not know all the knownTypes, it being a framework class) (您可能不知道所有knownTypes,它是一个框架类)

You might try passing necessary information as string and at Bob side , parse the string and create the instances of Binding and EndpointAddress to connect to other services . 您可以尝试将必要的信息作为string传递,在Bob side ,解析字符串并创建BindingEndpointAddress的实例以连接到其他services

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM