Skip to content

Building a WCF architecture using OpenAccess – handling the scope

December 3, 2009

Howdy,

In my last post I was setting the scene for the WCF architecture.. now it’s time to do some code that actually does what the many words in my previous post talked about. But before I do that…let’s take a look on how the final solution will look like in terms of layers:

WCF services

This layer is the top most and will contain the endpoints for my services. Each service method will invoke a method in the Business services layer just below.

Business services

This layer contains all (ok, there not much to it yet, but it will be there later…trust me) business logic. A method within this layer also serves as a transaction demarcation. What I called “business transaction” in my previous post. So this is where the transaction handled by ObjectScope will get started and commited or rolled back. A business service method might invoke several repository methods in the Data access layer just below.

Data access

This layer contains all access to persistent objects. This is where LINQ queries will be executed and other CRUD like methods. So this is methods that uses and manipulates the persistence model.

All of the above layers have access to infrastructure services.. Huh? What is that!!..  Right now think of it as an assembly where you can put cross-cutting concerns for your layers. The first one of those concerns is the ContextManager.

The ContextManager

Remember the previous post ended up by concluding we needed a mechanism to make sure that during a service request we had an object scope (the same no matter how and where we referenced it) and also a clear transaction demarcation?  Lets deal with the object scope first.

I decided to create the ContextManager which essentially implements the following interface:

    public interface IContextManager
    {
        /// <summary>
        /// Attach a context
        /// </summary>
        void Attach();

        /// <summary>
        /// Detach a previously attached context
        /// </summary>
        void Detach();

        /// <summary>
        /// Readonly property to return the current context
        /// </summary>
        IManagedContext Current
        {
            get;
        }
    }

A full working solution including source is available at Teleriks Code Library.

In short an implementation of this interface can manage objects that implements the IManagedContext interface. I did one implementation of this interface called the WcfContextManager. When Attach is called it creates a new ObjectScopeContext which implements the IManagedContext interface. During creation of the context the object scope is created. Thus the ObjectScopeContext wraps the object scope and exposes it using a public property. Like:

    public class ObjectScopeContext : IManagedContext
    {
        private IObjectScope scope;

        public IObjectScope ObjectScope
        {
            get { return scope; }
            set { scope = value; }
        }

        public ObjectScopeContext()
        {
            ObjectScopeProvider.AdjustForDynamicLoad();
            scope = ObjectScopeProvider.GetNewObjectScope();
        }
    }

The created ObjectScopeContext instance is when put into a dictionary managed by the WcfContextManager using a string key that is known to the currently executing WCF service request. I chose to use the message id like:

    public class WcfContextManager : BaseContextManager
    {
        #region BaseContextManager Members

        /// <summary>
        /// Retrieve the key for the
        /// </summary>
        /// <returns></returns>
        protected override string GetContextKey()
        {
            return System.ServiceModel.OperationContext.Current.
IncomingMessageHeaders.MessageId.ToString();
        }

        protected override IManagedContext CreateManagedContext()
        {
            return new ObjectScopeContext();
        }

        #endregion
    }

So, to summarize: The WcfContextManager can manage ObjectScopeContext instances…each of those is “bound” to the currently executing Wcf request using the MessageId

So where do I perform the Attach and Detach.. in an WCF Behavior Extension naturally..

Attaching and detaching contexts

To start attaching and detaching contexts I will need a place to so..preferably then the request has been received and just before the reply is sent back. Lucky me WCF is flexible. I wrote a WCF endpoint behavior extension, that applies a dispatch behavior to the endpoint, like:

        public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
        {
            if (Enabled)
            {
                ContextBehaviorMessageInspector inspector = new ContextBehaviorMessageInspector();
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
            }
        }

The ContextBehaviorMessageInspector is added to the WCF request pipeline, so I can inspect (among other things) the message received from the client.. Let’s dive into the inspector. It implements the IDispatchMessageInspector and I implemented this interface in my ContextBehaviorMessageInspector like:

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // Attach context using the default context manager
            ContextManagerFactory.Default.Attach();

            return Guid.NewGuid();
        }

        /// <summary>
        /// Perform action before sending the reply to the client
        /// </summary>
        /// <param name="reply"></param>
        /// <param name="correlationState">
        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            ContextManagerFactory.Default.Detach();
        }

And now I reached my goal:
Whenever I WCF request comes in a ObjectScopeContext is attached to the message Id of the request using the WcfContextManager presented earlier in the post. Just before the reply is sent to the client, the context is detached again.. and during the detach the object scope is actually disposed, too.

Furthermore, I can reference my ObjectScope everywhere in my code (the business services and repository layers above) by doing a ContextManagerFactory.Default.Current and I am guaranteed that I will get the same object scope each time I asked for it during a service request. Like:

        public void CreateCustomer(string name)
        {
            // Start the transaction on the scope if not already done
            if (!Context.ObjectScope.Transaction.IsActive)
                Context.ObjectScope.Transaction.Begin();

            try
            {
                // Perform the business work flow using the repositories
                customerRepository.CreateCustomer(name);

                // Commit the transaction if it is still active
                if (Context.ObjectScope.Transaction.IsActive)
                    Context.ObjectScope.Transaction.Commit();
            }
            catch (Exception e)
            {
                // Rollback the transaction if it is still active
                if (Context.ObjectScope.Transaction.IsActive)
                    Context.ObjectScope.Transaction.Rollback();
                throw e;
            }

        }

Note: In the above code I implemented a read only property on the BaseBusinessService class called Context that actually performs the type casting from IManagedContext to ObjectScopeContext

And even better: It has no dependencies whatsoever on how you host your WCF service. It can be self hosting (like in my example), hosted by WAS, hosted by IIS… whatever.. it will still work since I used no host-dependent mechanism (like HttpContext) to “bind” the ObjectScope to the request.

With these things setup, we can start coding the business stuff we need. In my next post I’ll cover how to use a common abstract base class for all my entities… among other things..

Stay tuned.

Advertisements
15 Comments
  1. Juan Esteban permalink

    Hi, How are you?
    I’m using this architecture and I think that It is just that I need. The problem is when I try to return an object containing another persistent entity. The message is: The ‘IObjectScope’ is already closed. I was checking the code, and I see that the event BeforeSendReply executes first before the entity returns to the presentation layer.

    Could you help me?

    Thanks a lot…

    • Hi Juan,

      I am fine, thanks.

      Well, the error you’re seeing is because you send the persistent entities on the wire from the WCF I guess. When doing so the serializer that converts your objects to plain XML traverse your object graph.. In doing so, it will also invoke the lazy loading of properties not included in the fetchplan you used to retrieve the object with. The default fetchplan retrieves only the simple properties.. References to other peristent classes and lists of those are omitted by default. Thus, if you have some of those properties in the class you are sending to the caller of your WCF service method, lazy loading will be invoked…and at that time, you don’t have the object scope any longer…that’s is the error you’re seeing..

      There are several solutions to the problem:

      1) Use a fetchplan that retrieves the entire object graph when retrieving the persistent objects.. thus.. No lazy loading will be involved. Not really a solution since it will slow down your backend loading information that you might really not need.
      2) Detach your persistent object from the object scope before sending it to the caller of the WCF service..you can you se ObjectNetworkAttacher.cs in the OpenAccess distribution as s starting point….I haven’t tried this but it should work… I didn’t use that method since I had other requirements that lead me to solution 3…next
      3) Have a clean highly navigable persistent model with no DataContract attributes in… Have more DataContract classes as return parameters and/or input parameters of your WCF servce method… thus these DataContract classes will get exposed in the WCF service contract…. the only drawback is that need to create this extra mapping to/from DataContract classes and persistent classes.. however I think it is a little price to pay for the flexibility you get:
      1) You get a clean separation of concern and your services are “real business” services not just a data access layer on top of WCF
      2) You can “shape” your DataContract classes to include only the needed information..I had security requirement where in some cases (depending on the caller) I had to emit some information from the data being processed / returned.
      3) You can design your DataContract classes, so they are not navigable in a highly manner as the persistent classes are… They have different requirements… here’s the catch… Suppose you (in the model where you put persistent classes on the wire) and these are highly navigable… the serializer will traverse the entire object model…leaving you with a payload of XML that is much higher than you really need…and this because the XML have no concept of object identity (by default anyway)… thus you will get the same object serialized over and over again….. So back to the requirements…: In your persistent model it is nice to have high navigability, because doing so you can construct your queries to be the most effective since you have more “ways” into your persistent model.. In your DataContract classes you don’t have this requirement…it is even not recommended because of the serializer-no-concept-of-object-identity problem stated earlier… Most probably you will design your DataContract classes to have forward only navigability (ie. when returning an Order, you can go from the Order to the list of OrderLine instances… but not from the OrderLine instance to the Order instance… In the persistent class model you can navigate in both directions..

      Hope all of this gives you an idea of where to go.. However… if you really only need a “data gateway” on top of WCF, maybe you should check out the Telerik Data Services on the Telerik website

  2. Juan Esteban permalink

    Hi Henrik,
    Thank you very much for taking the time to answer my questions. I appreciate your help.

    I’m going to follow your suggestions.

  3. Juan Esteban permalink

    Hi Henrik,

    I finally used the architecture proposed in the last post, and I think that is great. I just create another layer with the Data contracts (transfer objects) and I assemble the contracts with the persistence classes before to send through the wire to the presentation layer.
    I have another challenge and it is about to send to the presentation layer, an entity that has images types (Byte[]). Before, when I just had the persistences classes, the Fetch Plan retrieve this types only when the property was accessed in the code. Now, I’m sending whole the entity with images types in the wire, with the Data contract object. Which is the best recommendation to handle this case with this architecture?

    Thanks a lot again… 🙂

    • Hi Juan,
      I am really happy that you made it and think the architecture is worth it..

      I had a similar issue and used one of the two ways to solve it.

      1) Create a DataContract class say Invoice that has everything except the byte array that represents the real invoice document. Then have another DataContract class, say RealInvoice that extends the Invoice class only with the byte array to represent the PDF (or whatever…) that is the real invoice document.

      2) Create an Attachment DataContract class and have it include a property of type byte array that represents the binary data. When reference this Attachment class from whatever class needs binary data… Say Invoice.Document, where the Document is of type Attachment…. Have logic on the serverside decide whether to fill out the byte array or not.

      I guess you will have the same issue when you want to present a list of lookup values in a drop down list… To deal with this I usually use the concept of ListItem classes, which is a boiled down version of the real class… With the above Invoice example in mind it could be an InvoiceListItem, which for example have the total amount of the invoice and the name and address of the receiver of the invoice.

      Hope the answer was helpful….and thanks for reading the blog… I will update it very soon with a more complete example…

      Regards

      Henrik

  4. Juan Esteban permalink

    Hello Henrik,

    I’m agree with you, and thank you very much for all the useful advice you have given me. I tell you that right now I’m implementing a project that requires high availability. Thinking about how to satisfy this need, I am implementing a system that handles both online and offline environments. In the online environment, all operations to the database are done through WCF. In the offline environment all operations to the database are made on the local client without using WCF. So I’ve been developing a WindowsContextManeger like WcfContextManager to handle the offline environment. The question is, when I should attach or detach the ObjectScope on the local client (Offline environment)?

    Thank you very much, I appreciate your help …

    • Sounds like a great idea with the online – offline modes that an application can operate in. Regarding your question it really depends on what you use as the key in the WindowsContextManager, because the key ensures that you get the same object scope if you ask for it with the same key.. So as it is designed right now you should use a key that is accessible from the WindowsContextManager.. I believe that using a Windows client it could be the some kind of id for the current form.. so that you end up having an object scope per Windows form… I don’t know if you can get this “id” of the form from within the WindowsContextManager of yours… maybe through the current AppDomain…You will have to do some research here…

      Regards

      Henrik

  5. Teguh permalink

    Hi Hendrik,

    Thank you for this great guidance. However when I tried to implement the architecture apparently, ContextManagerFactory.Default.Current is always return null.
    Could you please advice?

    Many thanks,
    Teguh

  6. Hi Teguh,

    Thanks for your interest.
    Have you tried to download the sample in Teleriks Code Library?

    What are you using as key for the Context?

    Regards

    Henrik

    • Teguh permalink

      Hi Hendrik,

      Thank you for your fast response. I’ve tried the sample code, however, ContextManagerFactory.Default.Current also returns null.
      Could it be that I missed something?

      In regards to the second question: What are you using as key for the Context?
      My apologize, I’m not quite understand what the question is. Could you please provide some detailed guidance?
      Because I’m very new to the OpenAccess+WCF architecture.

      Many thanks,
      Teguh

  7. Hmm.. I really should work out of the box if you’re actually calling Attach.

    The key is used for the Dictionary holding holding current instances of an ObjectScope… There will be more than one instance if multiple threads/requests are running.

    You can also send me your code… I would be happy to take a look at it.. Eventually you can send it to removethishg at websolver.dk

    Remember to remove the right words from the E-mail address

  8. Teguh permalink

    Hi Hendrik,

    Thank you for the kind offer. However when I tried to send you an email to the removethishg at websolver.dk, and unfortunately the delivery’s failed 🙂

    Could you please confirm the correct email address? 🙂

    Warm regards,
    Teguh

    • Hi Teguh,

      You have remove the text “removethis” from the E-mail address. So it is: hg “at” websolver.dk

Trackbacks & Pingbacks

  1. OpenAccess – using a base class for identity and version « Websolver
  2. Building a WCF architecture using OpenAccess – setting the scene « Websolver

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: