locked
Dsshost.exe.config MessageCapture value corrects/causes DsspForwarder:InboundFailure RRS feed

  • Question

  • I have been struggling with trying to figure out why a set of services would run fine on one pc but not on another. In my flailing around looking for a solution or anything that would help me debug I found that the MessageCapture setting in the Dsshost.exe.config file was the trigger for the problem.

     

    If I make the value empty (to turn it off):

    <add key="Microsoft.Dss.Services.Forwarders.MessageCapture" value="" />

     

    I end up with the following error on the first message sent to one of my services:

    ### DsspForwarder:InboundFailureHandler. Exception:Body type not expected:com.ara.ned.ris.Contracts.Messaging.Proxy.OpenRequest Action:http://schemas.microsoft.com/xw/2004/10/dssp.html:InsertRequest Body Type:com.ara.ned.ris.Contracts.Messaging.Proxy.OpenRequest Target ServiceBig Smilessp.tcp://ned-2b1dfg1.ara.wan:50001/roboteqcontroller/serialport/messaging Source ServiceBig Smilessp.tcp://ned-2b1dfg1.ara.wan:50001/roboteqcontroller

     

    When I set the value to any one of the three possible strings no error is produced and my services run fine?

    <add key="Microsoft.Dss.Services.Forwarders.MessageCapture" value="CaptureInbound" />

     

    Can one of you MS folks shed some light on what might be going on here?

     

    Note that the error only occurs for one message type. I have subscription messages (Reliable Subscribes) that are successful regardless of the setting. Also, the messages that fail (there are always 2 message failures) are being sent to 2 instances of the same service implementation (one message to each instance).

     

    Thanks

    Bryan

     

     

    Friday, November 14, 2008 8:48 PM

Answers

  • More on this:

    My initial intent was to create an abstract base class for a set of common services (so it inherited from DsspServiceBase) and put that base class in the same assembly as a generic contract definition that it was going to implement. (There were specific reasons I chose this direction but that's not important here) The generic contract was implemented in the base class as an Alternate Contract. Individual concrete implementations of this base class were created in different assemblies. In the subclass the main service contract would be defined and implemented for the specifics of that implemntation.

    For example, a serial port generic contract is created because I might have several serial port services, each supporting its own protocol. So the Generic Serial Port contract is simply for the common serial port settings (PortName, BaudRate, DataBits, etc) and is defined as an alternate contract in the base class. Now a specifc implementation of the base class would be created to deal with say GPS NMEA sentences, and as such the main service contract for the service would be implemented around the specifics of NMEA sentences. This would have been created in a seperate assembly.

    Under these circumstances the reported error conditions would occur. I suspect its because the implementation of the service was in its own assembly and therefore it was confused about what transforms should occur for the types being dealt with in the base class. However, I don't quite understand why it wouldn't work since there are transforms created to move the contract types back and forth between both the proxy and implementation message types.

    Anyway, the solution was to strip the generic contract out into its own dll and push the implementation of the base class into its own dll which strictly enforced the reference the generic contract proxy dll. This corrected the problem.

    So I guess the comments above are not correct as I wasn't making a strict Service Declaration in the same dll as the generic contract, (The base class was not decorated with the ContractAttribute) it was a base class with a alternate contract implemenation.

    Bryan

    • Marked as answer by Bryan Roth Thursday, December 18, 2008 1:46 PM
    Thursday, December 18, 2008 1:46 PM

All replies

  • In this post George says :
    "Using the CaptureInbound flag, all messages received by a service, are serialized to XML, and saved to disk."

    Maybe, when you enable message capture, messages between services are serialized in XML and not with the default dssp binary serialization.
    So maybe your messages can be serialized in XML but not in binary. It's only a supposition but check if you see anything weird in proxy Serialize/Deserialize generated code (in .\Proxy folder of your service project folder)

    Vincent
    • Proposed as answer by nescio16 Saturday, June 23, 2012 3:55 AM
    • Unproposed as answer by nescio16 Saturday, June 23, 2012 3:55 AM
    Monday, November 17, 2008 11:45 AM
  • I looked over the post you reference and noted that the log files that are generated during execution look like XML but are filled with lots of binary data (random non text characters) and hence look nothing like the log files posted by George. However, George did post that up almost 2 yrs ago now so they may have changed the format of the log files between then and now.

    I also looked through the .proxy.cs file and nothing looks out of place or odd but then again I have very little context so it would be tough to see a problem unless it were glaring.

    The only other thing I can think of (and am currently looking over) is the execution path through the DsspForwarder with capture enabled/disabled. I am using reflector but I have the same problem as above, I can only make assumptions about why things are done the way they are.

    Thanks
    Bryan
    Monday, November 17, 2008 2:10 PM
  • Does your message class use "complex" types ? Or just basic things like string, bool, ect ... ? Does dssproxy.exe produce warning during compilation (like "use lower case for service contract") ?

    The error message you get says "Body type not expected". When a service receive a message, it search for an operation on main port that matches the basic operation (i.e Get, Replace,Insert, Update, ...) and the body type.

    Your "/roboteqcontroller/serialport/messaging" service main port supports a Insert operation with a "OpenRequest" as body ?


    Maybe there is a problem with your message class (maybe a dss bug ?).
    Does your message class use "complex" types ? Or just basic things like string, bool, ect ... ? Does dssproxy.exe produce warning during compilation ?


    You should post the message class declaration and maybe the beginning of service implementation (main port declaration) if you can.

    Vincent



    Monday, November 17, 2008 4:13 PM
  • No its all simple types. Ill post the classes below. No errors/warnings from the proxy transform generation.

     

    Yes, the service port has the message type included.

     

    Recall that the messages work just fine if I change the config file setting.

     

    Here are the classes in question:

    Code Snippet

    [ServicePort]

    public class MessagingOperations : PortSet

    <DsspDefaultLookup,

    DsspDefaultDrop,

    HttpGet,

    Get,

    ReliableSubscribe,

    Subscribe,

    Open,

    Close,

    Transaction,

    Send,

    Received,

    Error>

    {}

     

    public class Open : Insert<OpenRequest, PortSet<DefaultInsertResponseType, Fault>>

    {

    /// <summary>

    /// Creates a new instance of Open

    /// </summary>

    public Open()

    {}

    /// <summary>

    /// Creates a new instance of Open

    /// </summary>

    /// <param name="body">the request message body</param>

    public Open(OpenRequest body)

    : base(body)

    {}

    /// <summary>

    /// Creates a new instance of Open

    /// </summary>

    /// <param name="body">the request message body</param>

    /// <param name="responsePort">the response port for the request</param>

    public Open(OpenRequest body, PortSet<DefaultInsertResponseType, Fault> responsePort)

    : base(body, responsePort)

    {}

    }

     

    [DataContract]

    public class OpenRequest : Event

    {

    /// <summary>

    /// The fully qualified name of the assembly that contains the protocol

    /// to use on the messaging device.

    /// </summary>

    [DataMember(IsRequired = true)]

    public string ProtocolAssemblyName { get; set; }

     

    #region Overrides of Event

    public override LogEntry LogEntry

    {

    get

    {

    return new LogEntry(this)

    {

    Data = this.ProtocolAssemblyName

    };

    }

    }

    #endregion

    }

     

    [DataContract]

    public abstract class Event : TimeStamped

    {

    /// <summary>

    /// A string identifing the source of the operation. Typically this

    /// is the originating service's URI.

    /// </summary>

    [DataMember]

    [DataMemberConstructor(Order = 1)]

    public string Source { get; set; }

     

    /// <summary>

    /// Overload this property to return a LogEntry that is

    /// populated for this event.

    /// </summary>

    public abstract LogEntry LogEntry { get; }

    }

     

    [DataContract]

    public abstract class TimeStamped

    {

    protected TimeStamped()

    {

    this.TimeStamp = DateTime.Now;

    }

     

    /// <summary>

    /// Timestamp of operation.

    /// </summary>

    [DataMember]

    public DateTime TimeStamp { get; set; }

    }

     

     

     

     

     

    Monday, November 17, 2008 5:38 PM
  • Bryan, turning Messagecapture on, by default will binary serialize the messages. If you are getting errors, itmeans that its exposing serialization issues that wuld have popped up if you tried to talk between machines. We regularly turn on full message capture to validate our services and make sure that they can serialize all messages.

     

    verify your types have data contract AND data member annotations, that they have a Contract class per namespace, and the the generated proxy types look ok.

     

    thanx

    g

     

    Wednesday, November 19, 2008 3:18 AM
  • George

    I am confused. I believe you are saying that if I set MessageCapture to
    CaptureInboundOutbound this should cause serialization errors to become apparent.

    My problem is the exact opposite - I must turn on message capture in order to make the error go away.

    Bryan

    Wednesday, November 19, 2008 1:24 PM
  • So maybe you have an error when messages are not serialized, i.e the object instance is sent directly to the service (and "Transform" is called).
    In "client" service, do you use the proxy OpenRequest type ?
    You can also check if there is any problem in "Transform_XXX_TO_XXX" generated method (Proxy\MyServce.Transform.cs)

    Vincent
    Wednesday, November 19, 2008 1:46 PM
  • Vincent

    Yes, I use the Proxy.OpenRequest type in the client.

    I don't see any problems in the transform method using reflector. There is a transform method both to and from the Proxy type. And both are identical except for the types of the "target" and "from" local variables.

    Bryan
    Wednesday, November 19, 2008 2:27 PM
  • I really think the problem is that the service receive a proxy.OpenRequest as body and doesn't find the associated operation (and handler). It should receive a non proxy OpenRequest. When message are serialized, it's ok because non proxy and proxy OpenRequest have the same serialization format. But when the object instance is sent, it seems there is no transformation and the service receive the proxy type.

    How do you post the Open request and on what port ?


    Vincent
    Thursday, November 20, 2008 8:04 AM
  • Vincent

    I would expect the service to receive a Proxy type as any Client that is talking to the service will compile against the Proxy and will transmit a proxy type to the service. I don't follow how it should get a normal type? And since there is conversion both ways in the transform dll why should it matter?

    I post the message through a partner port in the client using a proxy type. The partnership is established using a manifest.xml file.

    I have found what I believe is the line of code that throws using reflector:

    Microsoft.Dss.Services.Forwarders.Dssp.DsspForwarder.InboundHandler(ForwarderEnvelope) calls (at bottom of method)
    Microsoft.Dss.Services.Forwarders.Dssp.DsspForwarder.ConvertSoapEnvelopeToDsspOperation(PortWithConfiguration,  String, ForwaredeEnvelope, IPort) that throws new Exception("Body type not expected:" + body); in the bottom third of the message.
    This is caught back in the InboundHandler method and logged using
    Microsoft.Dss.Services.Forwarders.Dssp.DsspForwarder.InboundFailureHandler(...)

    I can figure out what is going on up to the point where they start looking up types in their conversion dictionaries inside of
    ConvertSoapEnvelopeToDsspOperation. I can't reliably infer what the dictionary contents are from the limited amount of investigation time I have had.

    I also can't see where the Binary serialization occurs but it isn't a strech to infer it occurs before DsspForwarder gets the Envelope.

    Its interesting to note that it seems that every blue moon or so it fails to throw the body type not expected error, (the code works) but never more than a single time and never 2 times in a row. Always seems that it occurs after I make some big edits. This got me to thinking the Monitor.Enter/Exit might have something to do with it since the "type discovery" occurs inside that. But then again I don't have a whole lot of insight as to what is really spinning under the hood.

    I am still dinking around with a few things and trying stuff but I only want to make one change at a time to see if there is a trigger.

    Bryan

    Thursday, November 20, 2008 2:01 PM
  •  Bryan Roth wrote:

    I would expect the service to receive a Proxy type as any Client that is talking to the service will compile against the Proxy and will transmit a proxy type to the service. I don't follow how it should get a normal type? And since there is conversion both ways in the transform dll why should it matter?

    I mean that clients send proxy types, then they are  serialized, transformed to non-proxy types and passed to service handlers. The error message indicates that Proxy.OpenRequest is not expected as body type. I don't know if it's raised before or after the transformation, but if it's raised after, it is not normal to have a proxy type here

    Vincent.

    Thursday, November 20, 2008 4:21 PM
  • The error only occurs when the MessageCapture setting is off. So no serialization occurs and in that case I would expect to see the Proxy type.

    All of this is occurring within a single node. So the only time serialization is going to occur is when its sent externally to a different node or if the MessageCapture option is on.


    Thursday, November 20, 2008 5:16 PM
  • I think you should test with more simple message (for exemple, remove inheritance) to make sure that the error is linked (or not) with the message class


    Vincent.
    Thursday, November 20, 2008 5:44 PM
  • Thanks for the suggestion but I have already tried simplification of the classes - removal of inheritance and eliminating data members. I have moved all the types to the same assembly as well with no luck.

    I am using inheritance to implement some base class functionality of the Services that are receiving the messages and have not yet had the chance to try to monkey around with removing that to see what happens.

    Bryan
    Thursday, November 20, 2008 5:58 PM
  • Does your service have multiple ports or implement a generic contract ?
    Maybe dss searches a handler for OpenRequest on a wrong port.

    It's my last guess. If you code is "open source", you should post a link to download it or send it to robotic studio team

    Vincent.
    Friday, November 21, 2008 7:19 AM
  • Yes the service has multiple ports. One Service and one Alternate. The alternate port is experiencing the error and is also defined in a base class.

    I had thought about the wrong port but can't think of how I might figure that out?

    If they offered I could send them the code but as they have not offered I don't want to make any assumptions about the time they have or do not have as the case may be. No need to be pushy, they have jobs too.

    I have a few things I need to try here first anyhow. Just need to clear out some of the todo list.

    Bryan
    Friday, November 21, 2008 7:39 PM
  • When your service has an alternate port, you should see 2 services in service directory : /myservice and /myservice/alternateservice. Alternate message must be sent to the "alternate" service. Check that the partner URI in client services is the right one (once the service in launched, you can check ServiceInfo property to get partners)

    Vincent
    Monday, November 24, 2008 7:24 AM
  • My partnerships are established using the manifest file.

    I am not sure I understand your suggestion, but I think you are saying that I should be sure I am sending the message to the proper port, the alternate service port? I am sending it to the proper port as all works just fine with the MessageCapture setting turned on.


    Monday, November 24, 2008 1:10 PM
  • Myabe there is a mechanism in Dss runtime that fails to find the right port when message isn't serialized. Could you post your main and alternate port declaration in service implementation ? And is there any inheritance between port type ?
    Tuesday, November 25, 2008 9:51 AM
  • Well I finally found some time to play around with the code. It seems I have a problem placing a service implementation into an assembly that also contains a generic contract definition. If I move the service definition to its own assembly (project) it runs fine.

     

    The documentation suggests this is possible:

    It is possible to have both generic contract declarations as well as service implementations within a single assembly as long as they are defined in different CLR namespaces. You can indicate this using the ServiceDeclaration attribute by doing a bit-wise OR between the arguments DssServiceDeclaration.ServiceBehavior and DssServiceDeclaration.DataContract as follows:

    [assembly: ServiceDeclaration(DssServiceDeclaration.ServiceBehavior | DssServiceDeclaration.DataContract)]

     

    I have both ServiceDeclarationAttribute in the Assembly.cs file and the service def in a different namespace within the project/assembly. DssProxy doesn't produce any errors or warnings on the assembly. Note that the service that is defined implements the generic contract, though I would have thought that this would be the most common case for this situation.

     

    Can someone post an example of this that works so I can compare to what I have? The documentation seems awfly simple so I must be missing something ovbious.

     

    Thanks

    Bryan 

     

     

    Wednesday, November 26, 2008 6:48 PM
  • More on this:

    My initial intent was to create an abstract base class for a set of common services (so it inherited from DsspServiceBase) and put that base class in the same assembly as a generic contract definition that it was going to implement. (There were specific reasons I chose this direction but that's not important here) The generic contract was implemented in the base class as an Alternate Contract. Individual concrete implementations of this base class were created in different assemblies. In the subclass the main service contract would be defined and implemented for the specifics of that implemntation.

    For example, a serial port generic contract is created because I might have several serial port services, each supporting its own protocol. So the Generic Serial Port contract is simply for the common serial port settings (PortName, BaudRate, DataBits, etc) and is defined as an alternate contract in the base class. Now a specifc implementation of the base class would be created to deal with say GPS NMEA sentences, and as such the main service contract for the service would be implemented around the specifics of NMEA sentences. This would have been created in a seperate assembly.

    Under these circumstances the reported error conditions would occur. I suspect its because the implementation of the service was in its own assembly and therefore it was confused about what transforms should occur for the types being dealt with in the base class. However, I don't quite understand why it wouldn't work since there are transforms created to move the contract types back and forth between both the proxy and implementation message types.

    Anyway, the solution was to strip the generic contract out into its own dll and push the implementation of the base class into its own dll which strictly enforced the reference the generic contract proxy dll. This corrected the problem.

    So I guess the comments above are not correct as I wasn't making a strict Service Declaration in the same dll as the generic contract, (The base class was not decorated with the ContractAttribute) it was a base class with a alternate contract implemenation.

    Bryan

    • Marked as answer by Bryan Roth Thursday, December 18, 2008 1:46 PM
    Thursday, December 18, 2008 1:46 PM