Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to use PresentationRequestor over WCF

0.00/5 (No votes)
12 Jun 2015 1  
This tip explains how we can use PresentationRequestor to query presentation objects over WCF.

Introduction

PresentationRequestor is a library that helps implementing in the service layer by offering a generic class capable of querying business data with Linq expression based on presentation data.

For more information on this library, please read this article.

Now, we will talk about how it is possible to use this library over WCF (or any other similar means of communication).

Background

This biggest issue was to transfer the Linq queries over the network since they are not natively serializable. With the new release of PresentationRequestor, the request is transferred under a special object "RequestDTO". Additionally, one new class "ReaderServiceDTO" will be used on the server side to read the request object and execute the request, and another class called "ClientReaderService" will be used on the client side to create the requests and send them to WCF.

The Presentation Objects

At first, we need the contract objects (presentation objects). For this tutorial, we will use these classes:

   [DataContract(IsReference=true)]
    public class PresentationClass
    {
        [DataMember]
        public virtual int Key { get; set; }
        [DataMember]
        public virtual string PresentationName { get; set; }
        [DataMember]
        public virtual PresentationClass2[] Class2s { get; set; }
    }

    [DataContract]
    public class PresentationClass2
    {
        [DataMember]
        public int SomeInt { get; set; }
        [DataMember]
        public bool? SomeBool { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public PresentationClass Parent { get; set; }
    }

In this tutorial, we have decided to put them in a separate assembly called "PresentationRequestorDataContractTest". We will see why later.

The Server Side

We need to create a WCF service application, that we call "PresentationRequestorWCFTest". We need to reference the presentation objects library (right-click on the project, then Add Reference).

We need to create the business objects that match the presentation objects:

    [Presentation(typeof(PresentationClass))]
    public class BusinessClass
    {
        [Key]
        public virtual int Key { get; set; }
        [LinkTo("PresentationName")]
        public virtual string BusinessName { get; set; }
        public virtual IList<BusinessClass2> Class2s { get; set; }
    }

    [Presentation(typeof(PresentationClass2))]
    public class BusinessClass2
    {
        [Key]
        public int SomeInt { get; set; }
        public string Name { get; set; }
        public bool? SomeBool { get; set; }
        public BusinessClass Parent { get; set; }        
    }

And the data context for Entity Framework:

    public class DbTestContext : DbContext
    {
        public DbSet<BusinessClass> MyClasses { get; set; }
        public DbSet<BusinessClass2> MyClasses2 { get; set; }
    } 

During startup, by default, the mapping between presentation objects and business objects are discovered by looking recursively at all the files in the current base directory of the application. For a WCF application, the base directory is the root folder of the application (/bin/debug for other types). In this case, many instances of the .dll can be found (/bin, /obj), which causes the application to throw an exception when we try to resolve a presentation type by its name. This problem occurs only for WCF application with attribute mapping mode.

The workaround is to call the initializer in a class that we place in the App_Code folder of the application (called only once at the first call of the server).

   public class Initializer
    {
        public static void AppInitialize()
        {
            MapContext.InitializeAttributeMapping("bin\\PresentationRequestorWCFTest.dll");            
        }
    }

This method indicates the libraries that contain the business objects that map the presentation objects.

Let's now create the interface IService1 that will be used to create the WCF service:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GenericReaderService(RequestDTO request);
    }

This interface will expose one method GenericReaderService that the client will use to query his objects. RequestDTO is a serializable object that will contain the user request.

Let's now create its implementation Service1.svc and Service1.svc.cs (Add WCF Service).

    public class Service1 : IService1
    {
        public string GenericReaderService(RequestDTO request)
        {
            using (var context = new DbTestContext())
            {
                return ReaderServiceDTO.Proceed(request, context);
            }
            
        }
    }

The implementation of the service is fairly simple. All we need to do is call the Proceed static method of the ReaderServiceDTO class and pass the RequestDTO object as well as the data context. The returned string will contain the desired objects (serialized).

The Client Side

Now, we can create the console application that will consume the service. Let's call it "PresentationRequestorConsoleTest".

First, we need to add a service reference (Add Service Reference), but we need to make sure that "Reuse types in referenced assemblies" is checked. We can choose between "Reuse types in all referenced assemblies" or "Reuse types in specified referenced assemblies" as long as PresentationRequestor and the assemblies containing the data contract (PresentationRequestorDataContractTest in our tutorial) are selected.

Actually, only PresentationRequestor is mandatory because we need to reference the RequestDTO contained in this assembly and not a new object created by the proxy generator. Having a separate assembly containing the data contract that is referenced by both the server side and the client side has many benefits. One of them is that we can use the objects directly on the client side without having to expose the presentation objects in a service (they won't appear as proxy classes otherwise).

Once the service reference is added (let's call it ServiceReference1), we need to create a method that calls the service given a RequestDTO object.

static string CallService(RequestDTO request)
{
    return new ServiceReference1.Service1Client().GenericReaderService(request);
}

This method will then be passed to the constructor of ClientReaderService:

var reader = new PresentationRequestor.ClientReaderService<PresentationClass>(
         invoke: CallService,
         serializerType: PresentationRequestor.RequestDTO.SerializerType.DataContractSerializer
);

Note that we also have to pass the type of serializer that will be used to deserialized the result. In this tutorial, we will pass DataContractSerializer because our presentation objects have a bidirectionnal relation and we need to use the "IsReference" property of the DataContract attribute. The other possible choice is the standard XML serializer.

Now that everything is setup, we can use the reader object to request our data:

var result = reader.Where(x => x.Key > 1).OrderBy
(x => x.PresentationName).Include(x => x.Class2s).ToList();

History

  • 12th June, 2015: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here