WCSF Application Architecture 7: Remote Logic with WCF Services


This article is part of a series;


·         WCSF Application Architecture 1: Introduction


·         WCSF Application Architecture 2: Application Controller


·         WCSF Application Architecture 3: Model View Presenter


·         WCSF Application Architecture 4: Environment Abstraction


·         WCSF Application Architecture 5: Defining Modules


·         WCSF Application Architecture 6: Structuring Modules


Unfortunately it is also the worst named post in the series J


Introduction


It is a common requirement for customers to want to split web applications across physically separate tiers, usually using some kind of services technology. This post discusses some approaches to this using the Web Client Software Factory.


Although I focus on using WCF services, many of the concepts apply to ASMX and other technologies too – I have just chosen WCF as I believe it to be the best way to write services in the current .NET Framework environment.


* Note: Chances are I’m going to use the term Web Services a lot in this post. What I really mean when I say that is any kind of remote service – pretty much anything that can be written with WCF, for example.


Food for Thought


So first things first – let’s clear up some common myths.


1: SOA != Services


Just because your application uses Web Services (or any other kind of remote service), that doesn’t make it Service Oriented. It could still be just an app that uses Web Services. The current Wikipedia definition of SOA starts with a nice succinct statement about this;


“(SOA) is ... where functionality is grouped around business processes and packaged as interoperable services ... SOA separates functions into ... services ... which are made accessible over a network in order that they can be combined and reused in the production of business applications”.


In other words, if you’re writing a Web Service and Web Application as an inextricably linked pair that make up a single system, chances are you’re not doing SOA. SOA is an Enterprise Architecture, not an Application Architecture (although some applications will be built on the Enterprise Architecture by aggregating and reusing business services, and hence some apps are validly referred to as Service Oriented).


What this means to me is two things


1.       Be pragmatic about what rules you follow when you are writing a completely isolated internal application.


2.       Ask yourself this: “Why are we using a Web Service?” If your answer is “Because our company policy is that all new apps must be Service Oriented” (or something similar) I would recommend stepping back, and thinking deeply for a short while. How is adding a Web Service making your application Service Oriented? Is it really adding any value? If so, great – there are many valid reasons... but make sure you know what they are!


2: Services cost performance


Using a remote service is expensive (in terms of processing time, for example). If you previously had a method call that looked like this;


View.Orders = myBusinessLogic.GetOrders(user, startDate, endDate);


... and you move the implementation of GetOrders to be a remote Web Service, you will notice a significant performance degradation. Raw performance and scalability are often at odds like this! Suddenly we must serialize user information and dates, locate the remote service and open a channel, pass the data across a potentially unreliable network, spin up a service instance, deserialize the information, perform the business logic call that used to exist on the client, serialize the results, pass them back across the network, deserialize the results and turn them into a .NET list, and finally close the channel to the remote service. Phew. Now all that might be pretty fast in .NET, but it will be slower than an in-process method call.


Having said that, if the logic you must execute is expensive itself, you may find that removing load from the client Web Server and scaling it out to another physical tier improves the scalability of your system. I’m not saying don’t use services here – I just want you to be realistic about it!


3: RPC != Messaging


Because services add overheads, it is important to adopt a message exchange approach rather than a remote procedure call approach. What does this mean? Basically it comes down to two things;


1.       Granularity. RPC consists of chatty, frequent calls between client and service, very quickly making it difficult to scale your system. When you think RPC, think of many systems written with Remoting or Java’s RMI. Message exchanges are courser grained and minimise the amount of calls and proportion of overheads involved.


2.       Programming Model. I tend to find that RPC encourages the sharing of concepts internal to a service with the outside world. Use a message oriented approach makes you think about defining the contracts, abstracting where necessary, and encapsulating behaviour appropriately. Watch for a future post on the Service Interface pattern when I get a chance!


Candidate Architectures


So now that we’ve thought a little about what we want to avoid, let’s see a couple of approaches and discuss their characteristics.


1: Baseline


First up is our baseline architecture; this is what future examples will evolve from, and represents a basic WCSF application (ignoring splits across modules) without any kind of service layer.



Note that I’ve decided to expose my business logic here using a WCSF application service (not a web service). This communicates with my “model” (basically the business logic), which in turns talks to various data access classes (e.g. DbAccess). I hope that’s pretty straightforward.


2: Split Tiers


I nearly named this “RPC approach” because I feel that it encourages an RPC style of programming. Components above the dotted line are in my WCSF Web Application, and those below it are in the WCF Web Service.



What we have done here is just move the logic into a Web Service, and then change the WCSF application service that previously exposed business logic to purely act as a facade to the remote Web Service – in other words, it is a Service Agent or Service Proxy. This is a key concept – a Web Service is a resource, so if you are communicating with a Web Service directly in a class, you’re writing a resource (or data) access component.


The problem with this approach, in my opinion, is that this encourages developers to just call methods as though they were local to the web application, potentially leading to an RPC style system with very chatty communications and a serious scalability problem. Often people don’t realise that they are effectively writing an application that has no business logic layer (the Web Application)!! This is obviously contrary to well understood wisdom nowadays, and looking at the diagram above, I hope you see how unnatural it looks.


This lack of separation can also lead to changes in the service contracts affecting the UI. This is by no means ideal.


3: Remote Services


My preferred approach is shown below;


 


Here you can see that our missing logic layer has made a triumphant return! This might seem subtle but I think it completely changes class responsibilities and how your developers perceive the system. The logic in the Web Application is responsible for deciding when to go to a web service, or when to use a local cache, how to co-ordinate calls between different resources (you might have multiple web services!), when to enforce security or other policy, and so on. This then leaves your Resource Access layer able to dedicate itself to providing a real shield from the inner workings of the service calls.


As I’m sure regular readers have noticed, I’m a big fan of talking in concrete examples, so let’s see some (simplified) code that demonstrates this approach. Firstly, the Presenter and implied View;


public class MyPresenter<IMyView>


{


    private ILogicService _logicService;


 


    public MyPresenter([ServiceDependency] ILogicService logicService)


    {


        _logicService = logicService;


    }


 


    public void OnRetrieveOrders()


    {


        List<OrderEntity> results =


                _logicService.FetchOpenOrdersForCurrentUser(


                        View.StartDate, View.EndDate);


        View.Orders = results;


    }


}


The key here is that the presenter is using a WCSF service (badly named as ILogicService) to fetch orders for display to the user. These orders are represented by an “OrderEntity” entity. Next, let’s see an example of an ILogicService implementation;


public class LogicService : ILogicService


{


    private IAuthenticationService _authenticationService;


    private IEntityTranslatorService _entityTranslatorService;


 


    public LogicService(


        [ServiceDependency] IAuthenticationService


                authenticationService,


        [ServiceDependency] IEntityTranslatorService


                entityTranslatorService)


    {


        _authenticationService = authenticationService;


        _entityTranslatorService = entityTranslatorService;


    }


 


    public List<OrderEntity> FetchOpenOrdersForCurrentUser(


        DateTime startDate,


        DateTime endDate)


    {


        OrderServiceProxy proxy = null;


 


        try


        {


            proxy = new OrderServiceProxy();


            proxy.Open();


            proxy.LogOnService(CERTIFICATE_DETAILS);


 


            string orderStatusCode =


                proxy.GetOrderStatusCode(OrderStatus.Open);


 


            List<Order> orders = proxy.GetOrders(


                _authenticationService.CurrentUserName,


                orderStatusCode,


                startDate,


                endDate);


 


            List<OrderEntity> results =


                _entityTranslatorService.Translate<Order, OrderEntity>(orders);


 


            proxy.Close();


 


            return results;


        }


        catch (Exception)


        {


            if (proxy != null)


                proxy.Abort();


            throw;


        }


    }


}


There are a few really important points to make here;


1.       I have chosen to abstract environmental issues, such as authentication, away into a framework service. See my previous post on Environment Abstraction for more information on this.


2.       All the management of the interaction with the service proxy is kept out of the Presenter, and instead is handled by our WCSF application service.


3.       I am performing Entity Translation between the “Order” and “OrderEntity” objects. The former is actually part of the definition of the Order Service’s Service Contract, in that it defines how the remote service is communicated with. The latter is a Business Entity defined by my WCSF module. Therefore it is important that I expose the Business Entity not the proxy communication entity further up my architecture.


4.       The service performs some limited Orchestration – it calls a number of methods on the service to achieve what is seen by the Presenter as a single business operation. Obviously I would prefer a very course grained service design, but I’ve done this to illustrate that this is the right place to perform any required orchestration (potentially across multiple services) and workflow.


5.       The disposal of the proxy is done correctly. A “using” block is not the best way to deal with WCF proxies – see Avoiding Problems with the Using Statement.


6.       This is also the right place for rich error handling, publishing, and compensation – please don’t follow my poor example in this respect J


7.       I haven’t used the rich implementation of the Service Interface pattern I would usually, because constructing the messages would increase the volume of sample code and detract from the point. I’ll probably post about Service Interfaces soon, so watch this space!


The final important point is that this separation of business logic, resource access, entity translation, etc is likely to be repeated by the Order Service.


Potential Gotchas


When using WCF proxies there are a number of things worth knowing about. The first is the best way to use a “using” block, mentioned above.


Secondly, remember that a WCSF service is a singleton – so if you cache the WCF proxy you will be using the same one for every call, no matter which end user is browsing your site. No probs... oh, hang on! But what if you’re using a session-full binding? That would mean all your WCF calls would be using the same session, no matter which end user the call was for! This could certainly be a problem – so be very careful about this.


Thirdly, if you are caching your WCF proxy remember that a faulted proxy cannot be used again. So if your backend service fails and then comes back up, and you’re caching the proxy forever and for every user, your web application will be unusable until you cause it to flush the cache (e.g. by restarting the App Pool). The correct way to handle a faulted proxy is by adding the following code when creating it;


proxy = new OrderServiceProxy();


((IOrderServiceChannel)proxy).Faulted +=


    new EventHandler(OrderService_Faulted);


 In the event handler you can then react in some way – perhaps by Aborting the proxy and replacing it with a fresh one. This is obviously pretty academic for my example code above, but if you are caching proxies, consider this carefully. Also, if you don’t have a business logic layer, you might find it more difficult to deal with this kind of situation!


Finally, I’ve used the class generated by “Add Service Reference” in Visual Studio. It is actually pretty slow to new up one of these for every business operation when compared to using a cached ChannelFactory. In .NET 3.5 this is less true, but I’d recommend this post comparing the two approaches.


Summary


There are many issues I’ve not covered here – security architecture, for example (Trusted Subsystem versus Delegation), and many, many, many, more. But I hope this has gotten you started on how to structure your code, freeing you up to investigate some of the more subtle complexities. Good luck!


And finally... a Summary of Summaries


This is the last post in my series on Web Client Software Factory Application Architecture. That doesn’t mean I’ll not post about WCSF again of course, just that we have now covered plenty, from the basic patterns involved to some more “fluffy” concepts of designing modules or service layers. I hate television series that have no end (wow, it is seriously difficult not to name and shame here, that’s how much I hate it!), so I’ll take my own advice and finish on a high J


Remember how much I haven’t covered – there is plenty of information out there, from the WCSF community site, landing page, other bloggers, obviously in the factory documentation, and so on. And if you’re blogging about it, do let me know!


 

Comments (14)

  1. Eloy says:

    Sorry for my bad english, congratulations for articles, but I would like you to publish a functional example, using the alternatives that you feel best. thanks

  2. Simon J Ince says:

    Thanks!

    It is difficult for me to present a full example as the idea behind these posts is to present options – each may apply under different circumstances.

    I would recommend looking at the reference implementations provided by the patterns and practices team though – they cover using some of the approaches I’ve discussed.

    Hope that helps!

    Simon

  3. Eloy says:

    Thanks for your answer, I reviewed the reference implementations, but I do interested in the approach of "Page Flow Slave" for the Application controler, the problem I am having is that the controler left with very little code, only redirects to pages, if you could give some reference of examples to implement "Page Flow Slave" for the Application controler, thank you very much again for sharing your knowledge. Greetings from Cusco – Peru.

  4. Simon J Ince says:

    Eloy;

    that sounds about right – when using the Page Flow application block much of your controller code becomes redundant (for controllers that deal with a single flow), and therefore I would expect there to be a limited amount of code there. In many ways this is because the Page Flow block does most of what a Controller is there for – the only reason I would still keep a controller in fact is because it keeps the separation of concerns correct, and means you can replace your page flow implementation more easily without impacting all your Views & Presenters. Hope that makes sense!

    I guess if you chose a different approach to the one I like – so if you always called to your Model through the Controller – then you would see more code in your controllers left… but I see no need for this!

    I’ll see if I get a chance to put a quick page flow demo together – but don’t hold your breath; it could take me a while as I’m really busy right now.

    Thanks for the feedback!

    Simon

  5. Ola says:

    Hi Simon,please ,i would appreciate if you could post something on using ASP.NET Security couples with enterprises security application block using Sqlserver as back end.

    Thanks.

  6. Simon J Ince says:

    @ Ola;

    I’ll add it to the list of possible topics, but that’s a long list list so chances are I just won’t have time! In the mean time, try having a look here;

    http://www.pnpguidance.net/post/WCSFSecurityScreencastASPNET2WebsiteSecurityFeatures.aspx

    and here;

    http://msdn.microsoft.com/en-us/library/cc309508.aspx

    I hope that helps! Was there any specific area you were struggling with?

    Simon

  7. hongliangqiang says:

    Thanks a lot for the great series! WCSF is so huge to me and I finally start to make sense of it only after reading through this series.

    I wonder if you could enlighten me a bit on the exact reason architecture candidate #3 will promote message exchange approach over RPC (chatty) approach via moving business logic into the web application tier. My intuition is if you hide whole business logic behind WCF contract (below the dotted line) as in candidate #2, you only need to send the end result of business logic across the wire, thus will achieve a less chatty WCF communication.

    The following code segment in the example in the post seems to confirm my assumption:

          proxy.LogOnService(CERTIFICATE_DETAILS);

    string orderStatusCode =

          proxy.GetOrderStatusCode(OrderStatus.Open);

    List<Order> orders =

          proxy.GetOrders(

            _authenticationService.CurrentUserName,  

            orderStatusCode,

            startDate,

            endDate

    );

    By having part of the business on the Web application side, you made three calls on proxy. If I move the whole FetchOpenOrdersForCurrentUser() method into behind WCF service contract, I would think I only need to make one call to proxy.FetchOpenOrdersForCurrentUser() instead…

    Most likely I am missing something fundamental here. Would really appreciate your help to figure out where.

    Thanks again!

    Hongliang

  8. hongliangqiang says:

    Does anybody else like to share thoughts on my question above? Thanks.

  9. Simon J Ince says:

    @honglianggiang;

    Sorry for the late reply! I saw your comment arrive and read it, but completely forgot to reply once I got home.

    I think the key thing to notice here is that the "business logic" in candidate 2 is not logic that I’ve moved from behind the service calls, but rather logic whose only responsibility is orchestrating service calls. Part of the issue is probably my badly contrived example code! I have demonstrated how you might need to do a little orchestration, but you’re right, ideally you’d want to limit the number of calls.

    I guess the issue I’m trying to communicate is that if your UI is directly bound to a web service, developers don’t tend to think about what is happening, so you end up with a screen that has a repeater within which some data is bound to a call to a "GetPerson" web service… so you end up with many many web service calls per page render.

    On the other hand, if you have logic that is mediating between the UI and the service, it might get all Person records at the same time as whatever the repeater is bound to itself. It just encourages people to think about what data they need at once. Think of it in a similar way to how your business logic mediates UI requirements on the database.

    I hope that adds some clarity!

    Simon

  10. hongliangqiang says:

    Hi Simon,

    Thanks a lot for your reply! It sure clarifies things greatly for me.

    I have another question related to layered applications in general:

    I am trying to use both WCSF and MS Entity Framework (EF)– for dataaccess layer, as well as WCF in a new web app project, and would like to follow the candidate #3 structure. Once I started working, I found myself spending much of the time duplicating almost the same class code on each layer, for every tiny element I need on the page. For example, if I have a customers dropdown list on the page which populates its list from database, I will have a Customer class generated from EF, then in business layer, then in service layer, then in service proxy, and finally in service logic, before it is bound to the dropdown list. If I want to add interface also in some places, there will be even more duplications.

    I would like to convince myself those "duplications" are not real duplications since each serves its unique purpose, and that it is the fair price to pay for the indirection and flexibility and testability of the layered architecture. But still, I ended up with lot more classes and lot more lines of code. As I have been a big believer of "what is not there will not break" principal, I hope to find more justification for the extra codes.

    I understand it is probably too broad a topic to give specific advice on. I guess what I am really unsure about is whether this is a problem other people also face, what is the common practice, and particularly where to draw the line between engineering and "over-engineering".

    Any comments, or point to the right direction from you will be greatly appreciated — whenever you have time. 🙂

    Hongliang

  11. Simon J Ince says:

    @ Hongliang;

    I think what you’re describing is felt by every developer at some point or another!

    You’re absolutely right that this can be a significant development overhead, which is why approaches like "Entity Translation" have evolved, to try and automate some of the pain.

    I guess the key is to understand why we do it… and the answer is to enable each physical tier and/or logical layer to evolve without too much impact on it’s neighbours.

    In reality you might choose to compromise on some of those things… for example if you always deploy a web service and web client simultaenously, and are happy to update the code at both ends with changes, you might choose to loosen your model and compromise a little. It moves more pain to later (i.e. during app maintenance and further releases) but can be a worthwhile trade-off.

    The time when you really don’t want to compromise is when you’re talking about the interface with external systems.

    Also, last point – if you’re displaying lots of drop-down lists you might be able to reuse the same entity with ID and Description properties to carry the data (I often call it a LookupItem for some reason). That reduces your code signifcantly…

    Hope that helps!

    Simon

  12. hongliangqiang says:

    Hi Simon,

    Thank you very much for the advices. They are most helpful! I will try out each of the recommendations in the project and expect to gain more appreciation of them.

    Hongliang

  13. Galilyou says:

    Simon,

    I know this is too late, almost 2 years after you wrote the article! But, anyways, I have a question, I’m currently working on a system that should be modular in terms of UI (by UI, i mean ASPX pages and ASCX user controls, not only presenters). What we wish to do, is to be able to copy a dll and some aspx/ascx files to my project’s bin folder, change a configuration entry and get new functionality injected into my system. How much help can WCSF provide for such a scenario? What approach would you recommend for tackling this problem?

    Any help much appreciated. Thanks for your awesome series!

  14. Simon J Ince says:

    @ Galilyou;

    2 years already? Time flies 🙂

    This is absolutely a concept that the WCSF targets – the idea is that a Module can be dropped into a Web Application and start to function (it usually needs an app pool recycle though). Have a look at this screencast and read up on the modularity guidance in the WCSF docs;

    http://www.pnpguidance.net/Post/ModularityBundleScreencastWCSFCreateModularASPNETWebApplications.aspx

    What I would also point out though is that p&p have since done some work on a "leaner" and simpler bit of modularity guidance which is found here;

    http://webclientguidance.codeplex.com/

    By default it doesn’t dynamically load modules when they’re dropped into a folder but it could very easily if you override the "GetInitializers" and similar methods (or provide your own IAssembliesProvider) on the Bootstrapper class. This extensibility point is by design.

    Hope that helps.

    Simon

Skip to main content