This is a migrated thread and some comments may be shown as answers.

Doubts about OpenAccess and WCF

1 Answer 116 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Vicente Cartas Espinel
Top achievements
Rank 1
Vicente Cartas Espinel asked on 24 Mar 2011, 01:28 AM
Hello,

I'm evaluating OpenAccess as our ORM for a client-server scenario and I have some doubts on how things should be approached. I have a DB in SQlite with some tables, for this example I have a table called Projects and another called Sites. A Project can contain many Sites and a Site can only be part of a single Project. Both tables also have a Description field for adding text information.

I created a Class Library project where I created an OpenAccess Domain Model with my entities (I used attributes for the mappings).

Then I created a WCF Service Application (to get around the limitation of the Data Services Wizard when selecting projects). I told the wizard to generate the service on a new class library called Service. The Data Services Type is WCF EndPoints Service (our client and server will run in the same machine, using named pipes to communicate).

I run the wizard, deleted the WFC Service Application and created two console apps, one called Server and another called Client. The server is pretty simple:

namespace Server
{
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using Service;
 
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(DataService)))
            {
                var binding = new NetNamedPipeBinding();
                string address = "net.pipe://localhost/DataService";
                ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(IDataService), binding, address);
                ServiceMetadataBehavior metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
                if (metadataBehavior == null)
                {
                    metadataBehavior = new ServiceMetadataBehavior();
                    metadataBehavior.HttpGetEnabled = true;
                    metadataBehavior.HttpGetUrl = new Uri("http://localhost:8888");
 
                    host.Description.Behaviors.Add(metadataBehavior);
                }           
                host.Open();
                Console.WriteLine("Server running. Press ENTER to end it.");
                Console.ReadLine();
            }
        }
    }
}

I then run the Server, and added a Service Reference in my Client, autogenerating everything thanks to the metadata. My Client can connect to the Server and add simple entities like this.

DataServiceClient client = new DataServiceClient(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/DataService"));
client.Open();
 
// Create things
Project p = new Project();
p.Description = "Added by the client";
string result = client.CreateProject(p);

And things work fine. But, I have no idea on how to add new Sites to the Project. I have tried this approach:

Project p = new Project();
p.Description = "Added by the client";
 
Site s = new Site();
s.Description = "Added by the client too";
 
p.Sites = new List<Site>();
p.Sites.Add(s);
 
string result = client.CreateProject(p);

And I get a FaultException in the CreateProject line saying this:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:project. The InnerException message was 'The use of type 'OpenAccessTestProject.Project' as a get-only collection is not supported with NetDataContractSerializer.  Consider marking the type with the CollectionDataContractAttribute attribute or the SerializableAttribute attribute or adding a setter to the property.'.  Please see InnerException for more details.

(nothing on the Inner Exception)

Then I tried this:

Project p = new Project();
p.Description = "Added by the client";
string result = client.CreateProject(p);
 
Project p2 = client.ReadProject(result);
 
Site s = new Site();
s.Description = "Added by the client too";
s.Project = p2;
 
string result2 = client.CreateSite(s);

And I got the same exception with the same message in the CreateSite line.

I tried also this:

Project p = new Project();
p.Description = "Added by the client";
 
Site s = new Site();
s.Description = "Added by the client too";
 
p.Sites = new List<Site>();
p.Sites.Add(s);
s.Project = p;
 
string result = client.CreateProject(p);

And got this exception in the CreateProject line:

There was an error while trying to serialize parameter http://tempuri.org/:project. The InnerException message was 'Object graph for type 'Client35.TestDataService.Site' contains cycles and cannot be serialized if reference tracking is disabled.'.  Please see InnerException for more details.

Which makes me wonder what happened as the Service interface is marked with the attribute CyclesReferencesAware(true).

I have been checking and it seems the problem is because the entities generated by the Domain Model designer only have a get accesor in the properties for the collections that represents relationships, but I haven't found a way to make the designer generate a set accesor (apart from editing the templates), nor I have any clue if that's a good idea :S

So, my question is: any guidance on this subject? What is the OpenAccess way of solving this type of situation?

Regards,

Vicente

1 Answer, 1 is accepted

Sort by
0
Alexander
Telerik team
answered on 29 Mar 2011, 04:06 PM
Hi Vicente Cartas Espinel,

In such cases we recommend using additional set of transport classes that wrap the information from the persistent classes and are used as data contracts for the service. This way the actual implementation of the data access layer is hidden to the outside world and you have better control over the data exposed by the service. Of course, writing all those proxy classes could be a heavy task if the data model is big. That is why we provide an additional code generation template, which you can use to generate the proxy classes based on your domain model. The classes this template produces have one-way navigation members, this being the collection members and not the inverse references. For example, the Category.Products property would be created but the Product.Category would not. This avoids most of the cyclic-reference errors without the need of additional attributes.
If you are interested in this approach, you can find more information and the template itself on this page. I hope that helps.

Kind regards,
Alexander
the Telerik team
Tags
General Discussions
Asked by
Vicente Cartas Espinel
Top achievements
Rank 1
Answers by
Alexander
Telerik team
Share this question
or