All my services end up in Common proj!

Topics: CAB & Smart Client Software Factory
Aug 3, 2006 at 9:31 AM
originally posted by: sklett

This keeps happening to me; I create a module to perform different work items, create the services to assist the workitems then I find that another module also needs to use the service I just created. So I move the service to common, which also brings with it my constants file, resource settings, etc.

This can't be good.

fictitious example:

- has CustomerManagementService
- CustomerCollection GetCustomers()
- void EditCustomerDetails(int customerID)
- Customer CreateNewCustomer()

* needs to get a collection of Customers. Rather than add a GetCustomers() method to the OrdersModuleService, I want to use the CustomerManagementService I created in my CustomerManagementModule module.

I don't want to couple my modules to one another so I don't add a reference to CustomerManagementModule in OrdersModule.

I instead move CustomerManagementService to my common project. This keeps happening, common now owns most of my services and the other files they require.

One interesting point is that usually only a small portion of the methods in a service are needed by other modules. For example, my other modules won't need access to; EditCustomerDetails() and CreateNewCustomer(). One possible solution would be to break the service down into two services, but I'm struggling with what to call them and how to arrange them.

I could use inheritance and have;
class CustomerManagementBasicService;
class CustomerManagementService : CustomerManagementBasicService;

What do you all think of that?

Assuming my long post actually makes sense, I would really like to hear how you guys would deal with something like this?

Suggestions? Ideas? Experience? It's all welcome!

Thanks for reading,
Aug 3, 2006 at 10:02 AM
originally posted by: ChrisHolmes

"I instead move CustomerManagementService to my common project. This keeps happening, common now owns most of my services and the other files they require."

I keep my Services in a separate library from other common stuff. I keep the interface definitions to those services in a separate library as well. Common Library is only for things like Constants and Enums (at least that is how I use it).

I could use inheritance and have;
class CustomerManagementBasicService;
class CustomerManagementService : CustomerManagementBasicService;

What do you all think of that?

My opinion on anything labelled as a "Service" is that it is just that: a service. As such, it needs to be available to anyone who needs it. it may have method calls you don't need at the moment, but that's fine. I like to think of Services like Burger King - there's a lot of food BK can provide me. I'm probably only interested in a small portion of the menu today. BK doesn't need to create a separate "Chris Menu" just for me. I just use the service and get what I want from it :-)

The whole point of having a CustomerManagement service is so anywhere you need to grab Customer information you can just use that service. If two or more modules need to use that Service that's great! That's code reuse right there. Have your modules reference a Services.Interfaces library and fetch it from the WorkItem.Services collection.

If you find yourself in a situation where several modules need a particular service a lot, it might be best to create the Service a the Shell level and add it to the ServiceCollection at that point.
Aug 3, 2006 at 10:33 AM
originally posted by: sklett

Yo Chris!

Thanks for the reply.

I had always thought of services as being "owned" or part of a module. I don't know exactly why I thought this and considering you have a much more in depth understanding and generally grasp the concepts of the CAB better than I do... I believe your approach to be the better of the two.

So if I could just play your suggestion back to you to make sure I have it correct;

I would have the following projects:

shell needs a reference to 'Services' and 'Servicesinterfaces'
module needs a reference to 'ServicesInterfaces'

I like it. Will take some time to refactor everything, but I like it.

Thanks Chris!

I will let you know how it works out for me.
Aug 3, 2006 at 12:10 PM
originally posted by: ChrisHolmes

For the most part, that's how I do it. Now, there is a distinction here that can be drawn between a local service and a WCF/Indigo service, and that can make things more complicated.

In my project I have two kinds of Services: (1) WFC Services (which reside on a server somewhere on the network) and what I call (2) ClientServices.

ClientServices are classes that do something. In other words, they don't rely on an external data source (like a database) or other network device. They just perform a "service" - store some data that needs to be shared, perform some calculation or manipulation of data, etc. Usually they perform some "service" that multiple WorkItems may need to make use of, thus they become a part of the ClientService library and available to anyone in the Service hieararchy (through their Interface, of course).

When it comes to ClientServices, I reference that .dll in the Shell and create the concrete services in the AddServices() override. The Modules only need to include the Services.Interfaces file then to get access to them via the Services collection (and thus the whole thing is easy to mock in unit testing).

WCF Services... are a bit different. They are defined via Interfaces, just like ClientServices (using the same Services.Interfaces library), but because the actual concrete implementation resides across a network and some Open() & Close() magic has to happen in order to establish a connection to the Server, I have a local client library compiled called ServiceProxies. ServiceProxies implement the same interface as the real Service on the other end of the network (hence they can be mocked in unit testing and treated like the real service being called), but they wrap their calls to the service Interfaces with Open() & Close() magic so that they can actually perform the network call.

So, ServiceProxies gets included in the Shell just like ClientServices, and then the concrete Services are created there and made available via the Service collection. Meanwhile, the Modules only need the reference to the Services.Interfaces Library.

Now, occasionally I will want a ServiceProxy to only be available to a particular Module. If that happens, I have to include the ServiceProxy reference in that Module and create the concrete ServiceProxy class and add it to the Service collection in the ModuleController. But the ServiceProxy implementations of the Interfaces are very lightweight - they just have Open() & Close() calls to the real Services and some Try/Catch/Finally to trap errors and perform logging on the client end, so referencing that file is not a big deal, I don't think.

"I had always thought of services as being "owned" or part of a module. "

Yeah, and they're really not. Services exist (or should exist, in my opinion) to serve anything that needs to use them. If I need something locally in a Module that is just a class to do something (not a WCF service) then I add it to a subfolder in the Module called HelperClasses, and it performs that work just for that one place in that Module that needs it. But most of the time anything that is that specific is probably specific to a particular WorkItem, so it's a method.
Aug 3, 2006 at 1:14 PM
originally posted by: aras03k

"I had always thought of services as being "owned" or part of a module. "

I think of a service as first and foremost a broker between the shell and its modules. Neither are directly aware of eachothers presence. A module can of course still have private services to support it self and so can the shell.

If you want to communicate between modules using services I see nothing wrong with that. I would just lean on the SCSF implementation and use the Interface projects as a placeholder for your service interface. Anything that's named library has no business being referenced from inside a module. Couldn't you just leave the implementation inside the module and let the module instantiate the service and add it to the workitem hierachy? If your OrdersModule needs to use the Customer management service it just needs to handle the case where it is not present in the service collection (ie. the module isnt loaded for some reason). My reason for saying that is that it sometimes probably doesnt make sense to even use that service if the customer module is missing!

If we're talking about services that wraps around web service proxies, I have created a ServiceAgent project and a Proxy project where all my Service Agents reside. I simply see no reason to implement service agents inside modules. Instead, all my modules would have a reference to my service agent project (and the proxy for the data contracts). This also gives me the ability to "swap out" my communication protocol with something else, should the need arise. By replacing the service agent and proxy projects. Like if a client were unable to run .NET 3 on his machine we could deploy a version with a WS 1.1 service agent.

I would also give thought to using the EventBroker in some of the cases where you need "something" from module X.

The wonderful thing about the CAB is that it leaves you with so many options to solve a problem. I suppose thats also the hard part sometimes :)

Best regards,
Aug 9, 2006 at 2:51 PM
originally posted by: sklett

Hi Alan,

Thanks for the reply, you make some good points.

I'm just now getting around to refactoring my services and moving them out of my common project and into my (new) Services and Services.Interfaces projects.

I had a cyclical dependency error, but I've fixed that by abstracting a ton of classes to interfaces. It's good, I needed to do it anway.