Developing a wrapper around a WCF web service to use common CRUD methods is a good solution?

As you all know, creating a web service using common methods is not possible. You must develop a message.

But I had the idea to create 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 a wrapper as follows:

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

Here is the cumbersome way without a shell:

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

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

+4
source share
2 answers

The main problem with your implementation is that WCF proxies are not cheap. Reflection will not hurt you so much, but creating a new proxy for each request (and not getting rid of it properly, by the way) will definitely be.

The main problem with your design is that it assumes that each type of object supports the same CRUD contract / interface. In fact, you may have some read-only ones (bootstrap and other metadata), some of which relate only to the CR protocol (log data or transactions), some of which relate only to CRU (critical underlying data, such as "repository" or "account" ") and some that are not at all true entities and require additional parameters to retrieve. In addition, you will probably need several methods like GetByID / GetByXYZ, which vary from one type to another; p caustically, the consumer really would like to list each element contained in the database, without any filter or projection.

When you try to create a general abstraction, you hide critical information that the service can actually support, and letting consumers make assumptions that they don’t know is unacceptable until it is too late. You created a script that allows code breaking in unexpected and even unpredictable ways.

The main problem with your concept Web services are designed to encapsulate business logic or an application, not data sources . Creating thin veneers over DAL adds no real value to the overall solution, but just another layer of indirection that customers will be forced to deal with. Web services are great, but they add significant development and maintenance costs because each schema / data update must take place in two places instead of one. Adding a third (or 4th or 5th) level to an application, as a rule, is advisable only when this level provides additional intelligence, or at least encapsulation. Service architectures, built entirely around data access operations, are a "bad architectural smell" because they simply reimplement a database with very limited functions.

For example, a service-oriented request or message for "Orders" is likely to allow the consumer to specify any or all customers, a date range and many other criteria related to a specific domain - product types, quantities, total cost, payment method etc. You would like to combine all this into a single Service Operation; the consumer sends a single message with a detailed description of what he wants, and you provide it accordingly. Of course, a similar request for "Clients" will not have any of these criteria; instead, you can return results based on registration date, geographic location, credit rating, etc. Each request will be completely unique in this sense; you provide services to consumers to provide them with the flexibility that a simple CRUD level rarely provides. You would do this in order to be able to expose it to different consumers with different needs without constantly changing the service contract. Your proposed architecture does not lend itself to this ultimate goal.

It may just be my opinion, and other people may have other things to say about it; all I can add is that I base these statements on personal experience with web services (with which I work daily) and not necessarily with generally accepted wisdom, although I believe that traditional wisdom agrees with me here.

+3
source

I accidentally found this topic, but it is curious that I work in my free time to solve the same problem as here as a hobie, because now we have about 300 services at work, and this is growing, and there are basic operations (CRUD) that have the same structure and only modify EntityType, and there are also many custom methods, and I don’t like to repeat this, so I think this is not a bad idea, but I want to take care of some of the problems explained - in my opinion Aaronagut is very good, because now I will think about how to respond to these eschi. also.

Thus, in principle, the concept is the same, only one service (given that a complete solution can be more, but now only one), which processes all types of requests.

So, about the different parameters, I have a method in a service called Execute (Request Request) that receives the request, this request can be a general request object or a user request object, for example CreateRequest or DeleteRequest. A custom request has the properties necessary for this operation, so I can create an ApproveRequest as well. This request contains information about EntityType, the name of the operation declared in the BusinessComponent, and there are other parameters (the request acts like a property bag or dictionary), and the methods of business components are defined as follows: Update (BusinessEntity object) or Approve (Guid orderId, bool anotherParameterHere )

When the call is made, I process the request and extract the information that I mainly need EntityType and OperationName, and then I compare the input parameters in the request object with the expected method parameters, which I get this using reflection too ... and in BaseBusinessComponent I can create a strict BusinessEntity object that the Client will tell, this client inherits from BusinessEntity.

Another important thing is the response, which is processed in the same way as the request, if the request has an appropriate response class (just replace Request by Response), then I create an object of this request and add the values ​​returned by the method in the business component so that I can return property package and copy all the properties into Response, or if it is not a property bag, I assign a value (if the method is not empty) to the general property "Result", and this result can be in my CustomResponse I could override it and read the value and assign every individual the ideal property known in the CustomResponse class (but I haven't done it yet).

Here is an example of code that I can write right now, this is something very important:

  AppService service = new AppService(); //Create an order BusinessEntity order = new BusinessEntity("Order"); order["OrderId"] = Guid.NewGuid(); order["CustomerName"] = "Greivin Britton"; CreateRequest request = new CreateRequest(); request.Entity = order; CreateResponse response = (CreateResponse)service.Execute(request); //Create a customer Customer customer = new Customer(); customer.FirstName = "Greivin"; customer.LastName = "Britton"; Request request2 = new Request(); request2.MessageName = "Create"; request.Entity = customer; Response response2 = service.Execute(request2); 

To get data using different filters, I may have to create an ExpressionBuilder class or something like that ...

+1
source

All Articles