Suppose we have an application (on a server) that has a set of resources: these resources are indexed by name through a dictionary, that is Dictionary<string, Resource> resources.
The client sends to the server (using WCF) the names of one or more resources (for example, it sends a List<string>). On the server there may be only a subset of the resources requested by the client, so when a server receives this list, it sends back a list containing only the names of found resources.
I would like to generalize the search criteria that the client sends to the server, so that in future it is easy to extend the application (both client-side and server-side) with a more complex search criteria.
To achieve this goal, I thought to create the ISearchCriteria interface, so the client should send an object of a class which implements this interface.
public interface ISearchCriteria
{
// the names of the resources which match with the search criteria
ICollection<string> GetCompliantResources();
}
However it seems to me that this solution is not very correct, because the GetComplianceResources method should interact with the dictionary on the server, but the client should not know anything about this dictionary… I might use the strategy pattern, associating each concrete strategy to the specific search criteria. In this way could separate the control logic from the data (ie. the search criteria).
UPDATE (strategy pattern and DTO)
// Both on the server and on the client
public interface ISearchCriteria
{
// empty
}
// Both on the server and on the client
public class DefaultSearchCriteriaDTO : ISearchCriteria
{
List<string> ResourceNames { get; set; }
List<int> OtherCriteria { get; set; }
}
// Both on the server and on the client
public class MySearchCriteriaDTO : ISearchCriteria
{
string SearchString { get; set; }
}
// On the server.
public interface IStrategy<T> : where T : ISearchCriteria
{
public List<string> Match(T criteria);
}
// On the server
public class DefaultStrategy : IStrategy<T> where T : DefaultSearchCriteriaDTO
{
public List<string> Match(T criteria)
{
// search for resources and returns those found
}
}
- Is there some design pattern for this purpose?
- Are there better alternatives?
Rather than requiring the client to send you a class that you expect to have do things, have them send you a POCO:
As you add properties to the bound POCO, people using an older version of your API may still have their code work if the binding protocol interprets the absence of a property to mean that the property should not be set.
This object that clients send you will not have any logic: it plays the role of a data-transfer object. Your server is responsible for comparing the given resource names with its internal dictionary to determine which of the provided resources are available.
Update
Looking at your intended use of the strategy pattern, I think you’re overcomplicating things. For one thing, I don’t even know if WCF can bind to different types of parameters depending on what type of object the user tries to send: there are certainly at least some bindings (JSON, e.g.) that won’t allow it. Even if it is possible, this approach feels wrong, and that empty interface is producing a serious code smell. I’d say, keep your service interface clear and simple, with well-defined methods and parameter types.
If you expect that users will be searching by a variety of different "strategies", each of which will require a different set of parameters, create a different method for each potential search algorithm (
SearchByResourceNames(List<string resourceNames),SearchByDomain(int domainId), etc.).On the other hand, if you want the user to be able to mix and match various types of criteria, just use a
SearchCriteriaDTO and let the client populate whichever properties they want to search by.