Request clarification on Decentralized Software Services design

Dec 17, 2012 at 12:46 AM
Edited Dec 17, 2012 at 12:48 AM

I am trying to understand the internal design of DSS with respect to passing messages back and forth. From what I have seen and used, the DSS proxy dll is used at both the client and service ends. At the client end, it is used to serialize the messages and pass it on to the service. At the service end, it is used to deserialze and get the original message. However, I see that for every type I define in the service (be it a request or a DSS operation or a service state or a service port), there is a new type with the same name that is defined in the proxy that is the generated code from this original message. Please find below an example that defines the types defined in the service

[DataContract]
public class TestMessageRequest
{
    public string StringMember;

    public int IntMember;

    public float FloatMember;
}

public class TestMessage : Update<TestMessageRequest, PortSet<DefaultUpdateResponseType, Fault> >
{
}
I see that when I compile the service, it generates a proxy file which contains the following types which are equivalents of the above types.
    [global::Microsoft.Dss.Core.Attributes.DataContractAttribute(Namespace="http://schemas.tempuri.org/2012/09/testcomponentdssservice.html")]    [global::System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.tempuri.org/2012/09/testcomponentdssservice.html", ElementName="TestMessageRequest")]
    public class TestMessageRequest : global::Microsoft.Dss.Core.IDssSerializable, global::System.ICloneable {
        public TestMessageRequest() {
        }

    /// <summary>
    ///Copies the data member values of the current TestMessageRequest to the specified target object
    ///</summary>
    ///<param name="target">target object (must be an instance of)</param>
    public virtual void CopyTo(Microsoft.Dss.Core.IDssSerializable target) {
        global::TestComponentNs.Proxy.TestMessageRequest typedTarget = ((global::TestComponentNs.Proxy.TestMessageRequest)(target));
    }

    /// <summary>
    ///Clones TestMessageRequest
    ///</summary>
    ///<returns>cloned value</returns>
    public virtual object Clone() {
        global::TestComponentNs.Proxy.TestMessageRequest target0 = new global::TestComponentNs.Proxy.TestMessageRequest();
        this.CopyTo(target0);
        return target0;
    }

    /// <summary>
    ///Serializes the data member values of the current TestMessageRequest to the specified writer
    ///</summary>
    ///<param name="writer">the writer to which to serialize</param>
    public virtual void Serialize(System.IO.BinaryWriter writer) {
    }

    /// <summary>
    ///Deserializes TestMessageRequest
    ///</summary>
    ///<param name="reader">the reader from which to deserialize</param>
    ///<returns>deserialized TestMessageRequest</returns>
    public virtual object Deserialize(System.IO.BinaryReader reader) {
        return this;
    }
}

[global::System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema=false)]
public class TestMessage : global::Microsoft.Dss.ServiceModel.Dssp.Update<global::TestComponentNs.Proxy.TestMessageRequest, global:: Microsoft.Ccr.Core.PortSet<global::Microsoft.Dss.ServiceModel.Dssp.DefaultUpdateResponseType, global:: W3C.Soap.Fault>> {

    public TestMessage() {
    }

    public TestMessage(global::TestComponentNs.Proxy.TestMessageRequest body) : 
            base(body) {
    }

    public TestMessage(global::TestComponentNs.Proxy.TestMessageRequest body, global::Microsoft.Ccr.Core.PortSet<global::Microsoft.Dss.ServiceModel.Dssp.DefaultUpdateResponseType, global:: W3C.Soap.Fault> responsePort) : 
            base(body, responsePort) {
    }
}

On compliation, both the service and the proxy dll have different message types. I see that the service dll references the original message and the proxy dll references the generated code message. I believe this is by design. I see some advantages of it (like having methods in the messages that can be used at the server end but not in the client because of the separate of data and logic). However, I am really not sure what is the actual reason behind this approach rather than having an approach that makes use of the same type in both the proxy and service. Can you please help me understand.

Thanks,

Venkat

Dec 17, 2012 at 12:54 PM

Hi Venkat,

Again I have to say that my knowledge of the DSS isn't that deep, so I don't know if my answer is helpful.

I can see some reasons why they would choose to generate proxies this way. One may be, as you say, to prevent having methods on the client side that actually cannot be used there. Another one is certainly the cloning /serialization mechanism which uses generated code - as you can see, the TestMessageRequest class has been extended with several methods und interface implementations. Also, in this way all messaging classes are contained in a single assembly that can be referenced by the client, with no unnecessary things in it.

This is in some way similar to the client proxy generation in WCF. With WCF you can alternatively choose to not generate the message types in the proxy, but use your own assembly on both sides. Perhaps implementing such an option would have been to complicated with DSS (and also not necessary), and so they chose not to do that.

The reason why on the server side the original assembly is used and not the proxy, may just be that it would be strange to write some code that you don't actually use directly, but use the proxy instead. Also, you would always need to compile the code first before the proxy gets updated.

Actually, when testing the DSS we also found that this code generation mechanism was one of the things that were very hard to understand and led to unnecessary complications. So this was something we wanted to avoid with the appspace, and we are simply using shared contract assemblies without code generation instead.

I assume from your post that you are using DSS in a production scenario. I would be interested if you have considered using the appspace alternatively, and/or what the reasons were that you decided to use DSS.

Best Regards
Thomas

Jan 14, 2013 at 2:06 AM
Edited Jan 14, 2013 at 10:42 PM

Hi Thomas,

Thank you once again for your time and reply. I agree with your reasoning on the proxy, in particular the fact that all messaging classes can be contained in the same assembly and also extending the request classes to implement DSS interfaces and also to add serialization methods. Also, as you said, for the service to use the proxy, it needs to have the proxy and the proxy is dependent on the service itself.

I too agree with you that DSS, and in particular the code generation part of DSS, was extremely hard to figure and use. Just like you and your team experienced. we found DSS very hard to customize to our needs and hence we use DSS only as a transport mechanism. Even to get that work needed a lot of analysis and understanding of the internal working of DSS. In our current design, the transport is tied (although not so strongly) to the messages that are communicated to and from the component. In essence, our transport is message aware.

In the the next version of our framework, we are trying to make the transport completely isolated from the messages that are transmitted. In essence, the transport will be responsible for transmitting byte arrays from one end to another. We will either use binary formatter serialization and mark our messages as [serializable] or we can also use other forms of serialization (such as Google protocol buffers) wherein the serialization code is generated. The former one seems to be relatively easier to implement compared to the later. This will ensure that no extra code gets written for making components remote (in particular so if we mark the messages as [Serializable]). We had tried out developing sample code using appspace and found it to be extremely easy to use but at the same time very powerful. We will try and see if appspace could be used as a transport for our new design. We are also considering raw TCP and WCF as other choices for transport.

Thanks,

Venkat