views:

302

answers:

1

As you all know creating a web service with generic methods is not possible. You have to design the message.

But I had the idea of creating a wrapper around WCF using Reflection.

public class WcfRepository<T> : IWcfRepository<T> where T : class 
    {
        public IList<T> GetList()
        {   
            Type wcfService = typeof (Service1Client);

            string entityName = typeof(T).Name;
            string methodName = String.Format("Get{0}List", entityName);

            object instance = Activator.CreateInstance(wcfService, true);

            var result = (IList<T>) wcfService.InvokeMember(methodName,
                BindingFlags.InvokeMethod | BindingFlags.Default, null, instance, null);
            return result;
        }

        public T Save(T entity)
        {
            throw new NotImplementedException();
        }

        public void Update(T entity)
        {
            throw new NotImplementedException();
        }

        public void Delete(int id)
        {
            throw new NotImplementedException();
        }
    }

You would use the wrapper like this:

var result = new WcfRepository<Employee>().GetList();

Here is the cumbersome way without the wrapper:

var customers = myWcfService.GetCustomerList();
var teams = myWcfService.GetTeamList();
var products = myWcfService.GetProductList();

So what do you think about my wrapper? What advantages and disadvantages you can see?

+2  A: 

The main problem with your implementation is that WCF proxies are not cheap. The Reflection won't hurt you that much, but creating a new proxy for every request (and not disposing it properly, by the way) definitely will.

The main problem with your design is that it assumes every type of entity supports the same CRUD contract/interface. In reality, you might have some that are read-only (bootstrap and other metadata), some that are CR-only (log or transactional data), some that are CRU-only (critical foundational data like a "store" or "account"), and some that aren't true entities at all and require additional parameters to retrieve. In addition, you will probably need several "GetByID/GetByXYZ" type methods that vary from one type to another; rarely would a consumer truly want to list every single item contained in the database without any kind of filter or projection.

By attempting to create a generic abstraction, you are hiding critical information about what the service can actually support, and allowing consumers to make assumptions that they won't know are invalid until it's too late. You've created a scenario that allows code to break in unexpected and even unpredictable ways.

The main problem with your concept is that Web Services are intended to encapsulate business or application logic, not data sources. Creating a thin veneer over a DAL adds no real value to the overall solution, just another layer of indirection that clients will be forced to deal with. Web Services are great, but they add significant development and maintenance overhead, because every schema/data update has to happen in two places instead of one. Adding a 3rd (or 4th, or 5th) tier to an application is generally only appropriate when that tier is providing some additional intelligence or at least encapsulation. Service architectures built entirely around data-access operations are a "bad architecture smell" as they merely re-implement the database with severely limited functionality.

For example, a service- or message-oriented request for "Orders" will likely allow the consumer to specify any or all of the customer, date range, and a slew of other domain-specific criteria - product types, quantities, total cost, payment method, and so on. You would want to consolidate this all into a single Service Operation; the consumer sends a single message specifying in detail what he wants, and you provide it accordingly. Of course, a similar request for "Customers" will not have any of these criteria; instead you might return results based on the sign-up date, geographic location, credit rating, etc. Every request will be completely unique in this sense; you are providing a service to consumers to allow them the flexibility that a simple CRUD layer rarely provides. You would do this in order to be able to expose it to a variety of different consumers with different needs without having to constantly change the service's contract. Your proposed architecture does not lend itself well to this ultimate goal.

This may perhaps be simply my opinion and other people may have other things to say about it; all I can add is that I base these statements upon personal experience with Web Services (which I work with daily) and not necessarily conventional wisdom - although I believe that conventional wisdom agrees with me here.

Aaronaught
"Web Services are great, but they add significant development and maintenance overhead, because every schema/data update has to happen in two places instead of one." Exactly, I encounter lots of people that don't realize this a violation of DRY.
Jason
Have to counter with "It depends." Putting a wrapper (web service) around a DAL object is useful, if it gets the data to a place that it wasn't available before (e.g., Silverlight, Flash, etc.) A smart or dynamic proxy builder takes care of the multiple updates for schema changes.
Cylon Cat
True, and I believe that was one of the main reasons why Microsoft released ADO.NET Data Services. Still, I personally question whether you'd really want to expose such low-level functionality to a Flash or Silverlight app that probably only needs a few basic functions.
Aaronaught