Could I please get some clarification on a complex WCF service that exposes my business objects. Let's say I have 4 objects: contact, organisation, project and letter.
Is the best way to create my service:
Make 4 contracts as 'service objects' and pass the object and the intended operation as values/parameters in the 'service object'? or
Create contracts for all of the objects and their functions (which could be many)?
Many Thanks,
Chris
According to the Interface Segregation Principle, you might want to think about splitting those things up.
One typical approach is to have one interface (e.g. one "service") per object type - e.g. one interface for Contact with all the operations needed and useful for contacts, etc.
Of course, you might also have methods that deal with multiple different types of objects - those are a bit tricky to place in a specific service contract.
Also, with WCF, you can easily have a single service implementation class that then in turn implements multiple of those interfaces at once - e.g. to use common code or common patterns.
But I guess it would be a good idea to rethink your service contract and convert it into smaller, more manageable chunks.
Update:
if your service implementation class implements four service contracts, then you'd have to configure it like this:
<services>
<service name="YourNamespace.YourServiceImplementation">
<host>
<baseAddresses>
<add baseAddress="http://YourServer/MyServices/" />
</baseAddresses>
</host>
<endpoint name="Contact"
address="Contact"
binding="basicHttpBinding"
contract="YourNamespace.IContactService" />
<endpoint name="Letter"
address="Letter"
binding="basicHttpBinding"
contract="YourNamespace.ILetterService" />
<endpoint name="Organisation"
address="Organisation"
binding="basicHttpBinding"
contract="YourNamespace.IOrganisationService" />
<endpoint name="Project"
address="Project"
binding="basicHttpBinding"
contract="YourNamespace.IProjectService" />
<endpoint name="mex"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
Now, each of your services is available at a specific endpoint:
your IContractService is reachable at http://YourServer/MyServices/Contact
your ILetterService is reachable at http://YourServer/MyServices/Letter
and so on....
For each of those addresses, you can now add service references from a client - add only those you really need. One app might need only a single of those services, another might need two or three etc.
Just to add to the very helpful answer by Marc, the interfaces need to be decorated as below and then only we get the chance to add an independent reference to each contract implemented by the service separately.
[ServiceContract(Name="Contact", Namespace="YourNamespace.IContactService")]
public interface IContractService
{
...
}
Similarly for other interfaces
[ServiceContract(Name="Letter", Namespace="YourNamespace.ILetterService")]
public interface ILetterService
{
...
}
Without adding these attributes, I was unable to add separate service refernce to each of the contracts implemented by the common service.
Related
Currently I'm building a central place to do some common tasks, which a bunch of projects should use and it would be extremely nice to have this (mostly for convenience, I'll admit):
I just can't seem to do that. I've tried implementing multiple interfaces, but that doesn't work the way I want. It exposes too much in the same place.
I have a pseudo thing going on right now where I have three services, but on three different addresses (/ReportingService.svc, /QueueService.scv, and /TicketService.svc) and thus the above doesn't happen (ideally just one /Services.svc).
The way the dialog is constructed seems to support this way of exposing services (namely it says "1 service(s) found at[...]"), but I just can't find a way to do it.
I suppose this could be helpful, but I haven't been able to make it work either. I just get a 404 when trying to open the listenUri.
Does anyone have any good ideas?
You need to create your methods in the interface (and obviously implement those methods in your service class).
[ServiceContract]
public interface IService
{
[OperationContract]
string method1(int code);
[OperationContract]
int method2(String id);
}
So, now you have just one service and multiple methods inside of it.
Or if you want to keep your methods organized, you could include services in your Web.config file.
<services>
<service name="ServicioWeb.IService1">
<endpoint binding="webHttpBinding"
contract="ServicioWeb.IService1"
behaviorConfiguration="WebBehavior"
/>
</service>
<service name="ServicioWeb.IService2">
<endpoint binding="webHttpBinding"
contract="ServicioWeb.IService2"
behaviorConfiguration="WebBehavior"
/>
</service>
</services>
And your URL would change a bit. Something like this:
http://localhost:8080/Service1.svc/...
http://localhost:8080/Service2.svc/...
We came across a god object in our system. The system consists of public service exposed to our clients, middle office service and back office service.
The flow is the following: user registers some transaction in public service, then manager from middle office service checks the transaction and approves or declines the transaction and finally manager from back office service finalizes or declines the transaction.
I'am using the word transaction, but in reality those are different types of operations like CRUD on entity1, CRUD on entiny2... Not only CRUD operations but many other operations like approve/send/decline entity1, make entity1 parent/child of entity2 etc etc...
Now WCF service contracts are just separated according to those parts of the system. So we have 3 service contracts:
PublicService.cs
MiddleOfficeService.cs
BackOfficeService.cs
and huge amount of operation contracts in each:
public interface IBackOfficeService
{
[OperationContract]
void AddEntity1(Entity1 item);
[OperationContract]
void DeleteEntity1(Entity1 item);
....
[OperationContract]
void SendEntity2(Entity2 item);
....
}
The number of those operation contracts are already 2000 across all 3 services and approximately 600 per each service contract. It is not just breaking the best practices, it is a huge pain to just update service references as it takes ages. And the system is growing each day and more and more operations are added to those services in each iteration.
And now we are facing dilemma as how can we split those god services into logical parts. One says that a service should not contain more then 12~20 operations. Others say some different things. I realize that there is no golden rule, but I just would wish to hear some recommendations about this.
For example if I just split those services per entity type then I can get about 50 service endpoints and 50 service reference in projects. What is about maintainability in this case?
One more thing to consider. Suppose I choose the approach to split those services per entity. For example:
public interface IEntity1Service
{
[OperationContract]
void AddEntity1(Entity1 item);
[OperationContract]
void ApproveEntity1(Entity1 item);
[OperationContract]
void SendEntity1(Entity1 item);
[OperationContract]
void DeleteEntity1(Entity1 item);
....
[OperationContract]
void FinalizeEntity1(Entity1 item);
[OperationContract]
void DeclineEntity1(Entity1 item);
}
Now what happens is that I should add reference to this service both in public client and back office client. But back office needs only FinalizeEntity1 and DeclineEntity1 operations. So here is a classic violation of Interface segregation principle in SOLID. So I have to split that further may be to 3 distinct services like IEntity1FrontService, IEntity1MiddleService, IEntity1BackService.
The challenge here is to refactor your code without changing large portions of it to avoid potential regressions.
One solution to avoid large business code with thousands of lines would be to split your interfaces/implementations into multiple parts, each part representing a given business domain.
For instance, your IPublicService interface could be written as follows (using interface inheritance, one interface for each business domain):
IPublicService.cs:
[ServiceContract]
public interface IPublicService : IPublicServiceDomain1, IPublicServiceDomain2
{
}
IPublicServiceDomain1.cs:
[ServiceContract]
public interface IPublicServiceDomain1
{
[OperationContract]
string GetEntity1(int value);
}
IPublicServiceDomain2.cs:
[ServiceContract]
public interface IPublicServiceDomain2
{
[OperationContract]
string GetEntity2(int value);
}
Now for the service implementation, you could split it into multiple parts using partial classes (one partial class for each business domain):
Service.cs:
public partial class Service : IPublicService
{
}
Service.Domain1.cs:
public partial class Service : IPublicServiceDomain1
{
public string GetEntity1(int value)
{
// Some implementation
}
}
Service.Domain2.cs:
public partial class Service : IPublicServiceDomain2
{
public string GetEntity2(int value)
{
// Some implementation
}
}
For the server configuration, there is still only one endpoint:
<system.serviceModel>
<services>
<service name="WcfServiceLibrary2.Service">
<endpoint address="" binding="basicHttpBinding" contract="WcfServiceLibrary2.IPublicService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary2/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Same for the client: still one service reference:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IPublicService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary2/Service1/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPublicService"
contract="ServiceReference1.IPublicService" name="BasicHttpBinding_IPublicService" />
</client>
</system.serviceModel>
This allows to refactor your server side by splitting your huge services into multiple logical parts (each part associated with a given business domain).
This doesn't change the fact each of your 3 services still has 600 operations, so the client proxy generation would still take ages. At least your code would be better organized server-side, and the refactoring would be cheap and not-so-risky.
There is no silver-bullet here, that is just code reorganization for better readability/maintenance.
200 services with 10 operations for each vs 20 services with 100 operations for each is another topic, but what is sure is that the refactoring would require way more time, and you would still have 2000 operations. Unless you refactor your whole application and reduce this number (for instance by providing services that are more "high-level" (not always possible)).
Having too many operation contracts doesn't make sense in a given service as it will leads to maintenance issues. Having said that if operations like Add(), Delete, Update(), AddChildItem(), RemoveChildItem(), etc are supposed to be together, then don't worry about operation contract going up to 30-40 in number. Because things that should be together should come out from a single interface (cohesion).
But 600 operations in a given service contract is really overwhelming number. You can start identifying the operations:-
That are required to be together
And that are not required to be together in a given service.
Based on this you can split the operations into different services.
If some of the methods are not used by client directly, then consider exposing the method based on the BUSSINESS logic (as also suggested by "Matthias Bäßler").
Say you want to expose the MoneyTransfer functionality. Then you are not required to expose
SendEmail()
DebitAccount()
CreditAccount(), etc in the service used by your web application.
So here you can expose just an aggregate service to your web application. In this case it may be IAccountService with methods like just
TransferMoney()
GetBalance(),
Internally in your implementation you can create other service which provides related operation like:-
SendEmail()
DebitAccount()
CreditAccount(), etc. required for IAccountService. MoneyTransfer() method.
This way, the number of methods in a given service will come down to a maintainable level.
I don't have experience with WCF but I think god classes and overloaded interfaces seem to be a general OOD problem.
When designing a system you should look for behaviour (or business logic) instead of data structures and operations. Don't look at how you're going to implement it but how the client would use it and how he would name it. In my experience, having the right names for the methods usually provides a lot of clues about the objects an their coupling.
For me the eye-opener was the design of the Mark IV coffee maker, an excerpt from "UML for Java Programmers" by Robert C. Martin. For meaningful names I recommend his book "Clean Code".
So, instead of building an interface of discrete operations like:
GetClientByName(string name);
AddOrder(PartNumber p, ContactInformation i);
SendOrder(Order o);
Do something like:
PrepareNewOrderForApproval(PartNumber p, string clientName);
Once you've done this, you also might refactor into separate objects.
Your problem is not so much a god object problem, as it is a service composition problem. God objects are problematic for different reasons than huge, crud-based service interfaces are problematic.
I would certainly agree that the 3 service contracts you have described are reaching the point where they are effectively unmanageable. The pain associated with refactoring will be disproportionately higher than if this was in-process code, so it's very important you take the correct approach, hence your question.
Unfortunately, service composability in soa is such a huge topic it's unlikely you'll receive massively useful answers here; though obviously useful, the experiences of others will unlikely apply to your situation.
I have written about this on SO before, so for what it's worth I'll include my thoughts:
I find that it's best if service operations can exist at a level where
they have business meaning.
What this means is that if a business person was told the operation
name, they would understand roughly what calling that operation would
do, and could make a guess at what data it would require to be passed
to it.
For this to happen your operations should fulfill in full or in part
some business process.
For example, the following operation signatures have business meaning:
void SolicitQuote(int brokerId, int userId, DateTime quoteRequiredBy);
int BindPolicyDocument(byte[] document, SomeType documentMetadata);
Guid BeginOnboardEmployee(string employeeName, DateTime employeeDateOfBirth);
If you use this principal when thinking about service composition then
the benefit is that you will rarely stray far from the optimal path;
you know what each operation does and you know when an operation is no
longer needed.
An additional benefit is that because business processes change fairly
rarely you will not need to change your service contracts as much.
I am having trouble adding a service to my app.config that implements two contracts, and thus needs two endpoints.
See this question for a basic example of what I am trying to do:
WCF config for a service class implementing multiple contracts on separate endpoints
I really want to use the Service Reference in my clients to create and maintain the proxies for me, but when I try to do this with a service with two endpoints, I get the following error in the details when it tries to download the metadata:
Metadata contains a reference that cannot be resolved
Here is an example of how I have the service setup in my app.config in my wcf service library:
<service name="MyService">
<endpoint address="Address1" binding="wsDualHttpBinding" bindingConfiguration=""
name="Service1" contract="IService1" />
<endpoint address="Address2" binding="wsDualHttpBinding" bindingConfiguration=""
name="Service2" contract="IService2" />
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
name="mex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/MyService/" />
</baseAddresses>
</host>
</service>
I feel like I am missing something simple. When I remove one of the end points, everything works fine. But if I have both end points in there, it can't resolve the metadata.
I have tried removing the base address and using full addresses, and with different ports but all paths I have tried lead to the same error.
Edit:
I should clarify why I am trying to do this in the first place I guess. I have a singleton service that I would like clients to be able to connect to. But there are some methods that I do not want clients to have access to. I thought separating the admin methods and the client methods into two separate contracts would be a good start.
To be even more clear, this is a game server. I want to be able to start new instances of the game server and send it a map and things like that.
I don't want gamers to have access to methods like LoadMap() or anything like that.
I really want to separate the methods and callbacks that the game client would have versus the methods and callbacks a match making service or server admin would have.
I also would like them to be separate contracts just to make it easier to read and maintain.
However, if there is a better way to do that, I am open for suggestions.
Took me a while to figure this out. I tore down my project and started rebuilding it from the beginning until it broke.
Apparently you cannot have two callback methods with the same name in your callback contracts if you try to do this.
Example:
public interface IService1Callback
{
[OperationContract(IsOneWay = true)]
void GetDataDone();
}
public interface IService2Callback
{
[OperationContract(IsOneWay = true)]
void GetDataDone();
}
If you then set these as the callback contracts on your service contracts like this:
[ServiceContract
(Namespace = "ServiceLib",
SessionMode = SessionMode.Required, CallbackContract = typeof(IService1Callback))]
public interface IService1
{
[OperationContract(IsInitiating = true)]
string GetData(int value);
}
[ServiceContract
(Namespace = "ServiceLib",
SessionMode = SessionMode.Required, CallbackContract = typeof(IService2Callback))]
public interface IService2
{
[OperationContract(IsInitiating = true)]
string GetOtherData(int value);
}
you will end up getting the error I mentioned in my original question.
I believe this is because the end points cannot figure out which callback contract the method comes from since they have the same name, so the metadata cannot resolve the reference.
Luckily I won't have callbacks with the same name, but I was stuck on this for a while because I had just setup some dummy methods to get things going.
I have a single class that implements a set of operations that I want to be able to expose as two different WCF services. Note that I need these to be two different services rather than two different endpoints within the same service. The reason for this is that I have a behavior on one of the services to require user name authentication. That same behavior cannot be applied to the other service. There are two separate contracts, both of which have been implemented by the class that will be acting as both services.
The problem that I've run into is that when hosting the services in IIS, the name of the service must match the type. Duplicate names are not allowed on the two different services. And therefore, I cannot have two services implemented by the same class (AFAIK).
The workaround that I have in place right now is that I have two empty wrapper classes, which simply inherit from the common class that implements the actual functionality and add nothing to the base class. This allows me to create the configuration for the two services with different type names, even though the types do nothing more than alias the base class.
Here is a sample from my configuration file (with the workaround in place) to help explain...
<service behaviorConfiguration="ServicesBehavior"
name="Company.Services.ApplicationServiceWrapper">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="basicHttpBinding"
contract="Company.Contracts.IApplicationService" />
</service>
<service behaviorConfiguration="SecuredServiceBehavior"
name="Company.Services.SecuredApplicationServiceWrapper">
<endpoint address="secure"
binding="wsHttpBinding"
bindingConfiguration="secureAuthorizedBinding"
contract="Company.Contracts.ISecuredApplicationService" />
</service>
And the basic implementation of the contracts and wrappers...
/// <summary>
/// These two classes are in place only so that WCF can differentiate between
/// two types, apply a different contract to each and host them in IIS.
/// </summary>
public class ApplicationServiceWrapper : ApplicationService { }
public class SecuredApplicationServiceWrapper : ApplicationService { }
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall
, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ApplicationService : IApplicationService
, ISecuredApplicationService
{
// Implementation.
}
Any Ideas?
We have an application where we wish to expose an large number of database entities and some business logic. Each entity will require the ability to Read , Add, and Update. at this point we do not expect to allow deletion.
the software we build is used in a wide range of business, so of which are multi tenanted operations Bureau services, also some of our clients use this approach to have separate databases for financial reasons.
We wish to be able to minimize the number of endpoints that need to be maintained. At the moment there are only 3 tables be exposed as WCF interfaces each with 6 attached methods. this is manageable but if operation has 50 databases that suddenly becomes 150 endpoints. worse if we have 50 tables exposed that becomes 2500 endpoints.
Does anyone have a suggestion on how we could design out system that we still have a simple entity model of Job.add (var1) or iList jobs = Job.GetSelected("sql type read").
without all these endpoints
WCF Data Services allows you to expose your data in a RESTful manner using the Open Data protocal (OData). This was formally called ADO.Net data services and before that Astoria. Any IQueryable collection can be exposed. The way shown in most of the examples is to use the Entity Framework, however there are examples showing usage with NHibernate and other Data Access technologies. OData is a self describing API based on Atom-Pub with some custom extensions. With a minimal amount of code you can expose you're entire database in a well defined format. That's the easy part.
In order to implement multi-tenency, you can create query interceptors in the WCF Data Services application to implement that logic. The number of interceptors and the complexity of the code you write will depend upon your security model and requirements. Looking at something like T4 templates or CodeSmith to generate the interceptor methods based on your database schema may be a way to prevent lots of repetitive manual coding.
The link I provided has a lot of information and tutorials on WCF Data Services and would provide a good place to start to see if it would meet your needs. I have been looking at WCF Data Services for a similar problem (Multi-tenancy), and would love to hear how you evently implement your solution.
It seems like you could pass the "identity" to every query and take that into account. This would mean that every record on your "Job" table would need to have a reference to the owner "identity" but that should not be much of a problem.
Just make sure that every query validates the "identity", and you should be OK.
If I understand your question correctly, I think you need unique endpoints but you can have a single service behavior that your end points reference.
Create a default endpoint:
<behaviors>
<serviceBehaviors>
<behavior name="MyService.DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
Set your default binding:
<bindings>
<wsHttpBinding>
<binding name="DefaultBinding">
<security mode="None">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Have all service reference point to the default behavior and binding:
<service behaviorConfiguration="MyService.DefaultBehavior"
name="MyService.Customer">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="DefaultBinding"
contract="MyService.ICustomer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
Each time you add a service, its a simple config entry.
With Apache you can use a fairly simple set of URL rewriting rules to map an arbitrary set of DB table tables and their corresponding endpoints to a single endpoint with a parameter.
For example, to map $ROOT/table_name/column_name to $ROOT/index.php?tn=table_name&cn=column_name, you could add a rule like this to $ROOT/.htaccess:
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/?$ index.php?tn=$1&cn=$2 [QSA,L]
Then you only need to maintain $ROOT/index.php (which of course can generate the appropriate HTTP status codes for nonexistent tables and/or columns).
Providing Multi-Tenancy, Without A Bazillion End Points
One way is to go with a REST-style WCF service that can use username/passwords to distinguish which client you are working with, and thus be able to select internally which DB to connect to. WCF gives you the the UriTemplate which allows you to map part's of the URL to the param's in your web methods:
HTTP GET Request: http://www.mysite.com/table1/(row Id)
HTTP PUT Request: http://www.mysite.com/table1/(row Id)/(field1)/(field2)
HTTP POST Request: http://www.mysite.com/table1/(row Id)/(field1)/(field2)
HTTP DELETE Request: http://www.mysite.com/table1/(row Id)
You can add other Uri Templates for more tasks as well, such as the following:
HTTP GET Request: http://www.mysite.com/table1/recentitems/(number of most recent items)
HTTP GET Request: http://www.mysite.com/table1/cancelPendingOrders/(user Id)
Who's Using My Service?
By requiring clients to supply a username and password, you can map that to specific DB. And by using the UriTemplate of /{tableName}/{operation}/{params...} you could then use code in your web service to execute the DB procedures given the table, operation, and params.
Wrapping It Up
Your web configuration wouldn't need to be altered much at all even. The following web article series is a great place to learn about REST-style web services, which I believe fits what you need: http://www.robbagby.com/rest/rest-in-wcf-blog-series-index/