Entity objects over WCF

Posts   
 
    
netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 18-Jul-2008 15:10:00   

Hi,

I have a webservice:


[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
    public interface IClientService
    {
        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login(string username);

Which works fine.

I would like to be able to send LLBLGEN entities across the wire, so I change my interface to:


[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
    public interface IClientService
    {
        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login(UserEntity Client);

This results in weird code generation by svcutil:


// CODEGEN: Parameter 'Client' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IClientService/Login")]
    [System.ServiceModel.XmlSerializerFormatAttribute()]
    void Login(Login request);

Then I tried changing the interface to use IEntity2 objects:


[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
    public interface IClientService
    {
        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login(IEntity2 Client);

This results in a timeout on the client and nothing happens on the receiving end. The generated code by svcutil is now:


[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IClientService/Login")]
    void Login(object Client);

Can anyone help with some pointers?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 18-Jul-2008 19:33:05   

Hi netrom, I think you should add known types to the Service's contract:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
[ServiceKnownType(typeof(UserEntity))]
public interface IClientService
{
     [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
     void Login(UserEntity Client);

You don't need to use all the classes generated by svcutil. At the client you only need to specify the ServiceContract interface and the service model at your config (endpoints, hosts, bindings).

For more info, read the WCF Support subsection of this manual section

David Elizondo | LLBLGen Support Team
netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 21-Jul-2008 11:21:05   

Hi,

thanks for the answers. It doesn't seem to help though. I don't get any events on the serverside. Nothing is sent over.

I've changed my code to make conversions from LLBLGen objects to my own dataobjects marked as [DataContract] with [DataMember]'s and of course that works fine - just wish it was possible to use LLBLGen objects the same way.

Best, Morten

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 21-Jul-2008 13:14:19   

just wish it was possible to use LLBLGen objects the same way.

It is possible. I was just experimenting with this yesterday. I started with the Northwind wcf example available in the downloads.

I'm hosting in iis with an http binding, transfering a IEntity2 based UserEntity so far in my testing. Collections are next.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 21-Jul-2008 13:25:44   

From all the examples I have seen and downloaded, it seems to be possible. I have just not been able to make it work here although I've tried numerous configurations and followed many examples to the point. I am not using IIS hosting but that shouldn't matter.

I'm ditching LLBLGen objects over WCF since I don't want to bother about it anymore. I have deadlines to keep up (spent 2 days now). It should just work out of the box with the correct attributes but it doesn't. When I look at the code generated by svcutil it looks as if the LLBLGen objects are not right or don't obey the standards.

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 21-Jul-2008 16:01:05   

Did you check the WCF example post on our website (Downloads section)?

If so, then please please specify which problems are you facing? Posting some code snippets or attach some code files would be more helpful.

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 21-Jul-2008 23:44:07   

I look at the code generated by svcutil

I am not using svcutil. Are you on VS2008, DotNet 3.5 and LlblGen 2.6? I'm updating the service reference in my project.

I have deadlines to keep up (spent 2 days now). It should just work out of the box with the correct attributes but it doesn't.

Good luck, it's often best to use and get comfortible with new technology when not under urgent deadlines.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 22-Jul-2008 09:03:03   

Hi Walaa,

Yes, I looked at the code from the download example. It's quite straightforward so no surprises there. Except that you defined the interfaces using IEntity2 instead of the derived object like UserEntity in my example.

Please let me know what code you are missing from me apart from the code posted in my first post. I thought it was enough but else let me know what you miss.

What happens is that when I refer to a UserEntity in the interface, svcutil makes some weird objects and comments that it requires additional schema information. Even with the [ServiceKnownType(UserEntity)] it doesn't understand my object.

When i try to use IEntity2 objects, as all your examples, the generated code looks alright. However, when I try to pass an object from my client to the server - nothing happens. I tried using the client generated by svcutil and with the approach taken in the wcf download example.

I'll just add a small example:

Serverside:


[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
[ServiceKnownType(typeof(UserEntity))]
    public interface IClientService
    {
        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login(UserEntity user);

    }
}

//Implementation
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class ClientService : IClientService
    {
        public IClientServiceCallback callback = null;

        public ClientService()
        {
            this.callback = OperationContext.Current.GetCallbackChannel<IClientServiceCallback>();
        }

        #region IClientService Members

        public void Login(UserEntity user)
        {
           Console.WriteLine....  
        }
}

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 22-Jul-2008 09:13:30   

Hi Arschr,

I am not using svcutil. Are you on VS2008, DotNet 3.5 and LlblGen 2.6? I'm updating the service reference in my project.

I use VS2008, .Net 3.5 and LLBLGen 2.6. I don't use service references. I use app.config and objects generated by svcutil.

Good luck, it's often best to use and get comfortible with new technology when not under urgent deadlines.

And then there are those other times when one invests some time making a spike project with an interesting technology that could save my grossly understaffed software department some time in the long run. smile

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 22-Jul-2008 09:27:31   

It's quite straightforward so no surprises there. Except that you defined the interfaces using IEntity2 instead of the derived object like UserEntity in my example.

You should use IEntity2 in the service interface, rather than UserEntity. You should use interfaces in the service methods declarations.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 22-Jul-2008 10:33:54   

Alright, defining it as IEntity2 looks better in the generated code.

I expected to get a method that would then take an IEntity2 object on the client side, but instead it gives me a method that takes an object. Is that correct?

My interface looks like this:


[ServiceKnownType(typeof(UserObj))]
    [ServiceKnownType(typeof(IEntity2))]
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientServiceCallback))]
    public interface IClientService
    {
        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login(UserObj user);

        [OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
        void Login2(IEntity2 user);
        

        [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
        void Logout(string token);
    }

I have attached the generated code file to this post. Notice that it appears to generate the wrong type of object for Login2


[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IClientService/Login2")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BusinessObjects.UserObj))]
    void Login2(object user);

Attachments
Filename File size Added on Approval
ClientService.cs 5,504 22-Jul-2008 10:34.51 Approved
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 22-Jul-2008 10:59:03   

You should not generate the client side code, instead just use the same interface at the client side. And use ChannelFactory to create a channel for the service.

Please follow the WCF example, and the docs.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 22-Jul-2008 11:19:40   

Alright, I'll give it a try.

What is the reason that this feature is not supported in LLBLGen?

My goal is not as much getting something across the wire as it is creating a service to which 3 parties can interface using the WSDL document and technology of their own choice. Is there any way I can achieve this?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39866
Joined: 17-Aug-2003
# Posted on: 22-Jul-2008 12:19:05   

netrom wrote:

Alright, I'll give it a try.

What is the reason that this feature is not supported in LLBLGen?

Because it's either: 1) you have the entity classes at the client side, so you have to send over entities, which means you've to define a service contract as described in the documentation OR 2) you don't have the entity classes at the client, and you have to send over DTO classes.

My goal is not as much getting something across the wire as it is creating a service to which 3 parties can interface using the WSDL document and technology of their own choice. Is there any way I can achieve this?

If the clients don't have the entity classes available, you have to send over DTO classes, that's how distributed systems work: data is send across the wire, not objects. The data is then stored in objects of the same type the data was in when it was sent. This means that if the types of these objects aren't available, a problem arises.

Frans Bouma | Lead developer LLBLGen Pro
netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 22-Jul-2008 13:17:01   

Hi Otis,

Let me try to ask my question again. I apologize if I didn't make it so clear in my previous posts.

Situation 1: I can define my own data objects (on the server only) using the DataContract and DataMember attributes. When using these objects in a WCF interface, svcutil will extract the information necessary (also the object declaration) and create some objects and interfaces for me to interact with the service. This is really nice since I don't need to publish my interface in a class library. This makes it easier for people using other platforms and languages to interact with my service.

Situation 2: Using LLBLGen objects in the interface is not able to give me this functionality just by declaring my interface.

So I would like to know if it's possible to get to situation 1 with LLBLGen objects (not self-serving). (Sure I could insert the attributes on all my entity objects but I hope we can agree that would be a bit awkward).

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 22-Jul-2008 16:23:51   

Situation 1: I can define my own data objects (on the server only) using the DataContract and DataMember attributes. When using these objects in a WCF interface, svcutil will extract the information necessary (also the object declaration) and create some objects and interfaces for me to interact with the service.

This is valid for DTOs, but not with custom objects, like LLBLGen objects. Otherwise how could the client deserialize the data into instances of these objects, if it doesn't have the objects around to instantiate from.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 23-Jul-2008 08:58:46   

So the answer is "no, it is not possible". I appreciate the help. Thanks.

This is valid for DTOs, but not with custom objects, like LLBLGen objects. Otherwise how could the client deserialize the data into instances of these objects, if it doesn't have the objects around to instantiate from.

Of course. but I'm asking since I wanted to make sure I hadn't missed some settings in the designer that could have generated some DTO's for me or enabled DTO capabilities in entity objects. This is so fundamental I can't be the only one missing such functionality.

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 23-Jul-2008 09:51:17   

Please search the forum for DTO, and you will find many good threads, some have templates to generate DTOs for you.

netrom
User
Posts: 15
Joined: 03-Jul-2008
# Posted on: 23-Jul-2008 10:34:33   

Thanks - the template stuff will solve my problem.