Request/Response Service Layer: Requests And Responses
Posted by Davy Brion on November 8th, 2009
Note: This post is part of a series. Be sure to read the introduction here.
In a typical WCF service, you’ll have one or more Service Contracts, and each Service Contract will define one or more Service Operations. These operations are just methods that you can call on the service. An operation can have parameters and it can have a return value. Most people typically expose multiple operations on their services for each piece of functionality they want their service to offer to consumers.
The Request/Response Service Layer (RRSL) takes a different approach. It has one service contract, with only one operation defined:
public interface IRequestProcessor : IDisposable
{
Response[] Process(params Request[] requests);
}
Notice the lack of the typical WCF attributes such as ServiceContract and OperationContract. The RRSL is actually completely independent from WCF and only uses WCF as a transport medium. That’s the topic of another post though, so let’s get back to the topic at hand: requests and responses.
As you can see, the Process method receives an array of Request objects and returns an array of Response objects. So what exactly is a Request and what is a Response? This is what they look like:
public class Request
{
}
public class Response
{
public ExceptionInfo Exception { get; set; }
public ExceptionType ExceptionType { get; set; }
}
Both are classes that you should derive specific Request and Response types from. The Response class automatically comes with an ExceptionInfo class (which is pretty much identical to WCF’s ExceptionDetail class and only exists because Silverlight 2 did not support ExceptionDetail) and an ExceptionType enum:
public enum ExceptionType
{
None,
Business,
Security,
EarlierRequestAlreadyFailed,
Unknown
}
The ExceptionInfo class (or ExceptionDetail if you would prefer to use that) does not contain the original Exception object, so the ExceptionType enumeration can be used to handle each type of exception differently on the client-side. Obviously, if a Request was handled without problems, the ExceptionInfo property of its Response will be null, and the ExceptionType property will be set to ExceptionType.None.
The idea is basically that instead of defining operations on your services, you create a specific Request class and a corresponding Response class for each operation that you would normally expose on your service. The request type is the operation, its properties are the operation’s parameters and the Response type is the operation’s return value. Note that you can define multiple properties on your Response types, effectively giving you the ability to support multiple return values for an operation without having to use out parameters.
A simple example of a Request and its Response can look like this:
public class GetProductOverviewsRequest : Request
{
public string NamePattern { get; set; }
public int? CategoryId { get; set; }
public int? SupplierId { get; set; }
}
public class GetProductOverviewsResponse : Response
{
public ProductOverviewDto[] Products { get; set; }
}
Note that by default, if you’re using at least .NET 3.5 SP1, you do not need to mark your Request/Response types as Serializable or apply the DataContract/DataMember attributes on them if the assembly containing the Request/Response types can be shared between both your service and your clients. If your service needs to be interoperable with other platforms or you can’t share the assembly containing the types, then you obviously do need to use the DataContract/DataMember attributes but if you’re only communicating with .NET clients and you can share the assembly, it’s not needed. Provided that all of the clients also use at least .NET 3.5 SP1 obviously.
At this point you might be wondering: “what exactly is the benefit of doing this?”. Well, at this point in the series there is only one benefit that you can see already: the fact that the Process method of the service receives an array of requests and returns an array of corresponding responses. That means that you can easily send multiple requests to the service with only one roundtrip, which can greatly reduce the network communication overhead that you can otherwise suffer with typical Service Contracts, especially if their interface is too chatty.
There are many more benefits to using the RRSL, but you’ll have to read the rest of the posts in the series to learn about those
November 9th, 2009 at 2:08 am
Why pass the exception parameters in every response? Since you have OO, you can return a strongly typed ErrorResponse.
November 9th, 2009 at 9:22 am
@Aaron
that would work if the client would retrieve its response based on the index of the corresponding request, but you’ll see in a future post that we retrieve the response based on its expected type, not the index.
November 9th, 2009 at 11:57 am
How does the client of the (WCF) service generate a proxy for all the different message types?
In other words how does the client know about the structure of ‘GetProductOverviewsRequest’ when it is not explicitly exposed\declared on the interface.
November 9th, 2009 at 12:00 pm
DOH!
Ignore my last comment…
November 9th, 2009 at 12:33 pm
‘If your service needs to be interoperable with other platforms or you can’t share the assembly containing the types, then you obviously do need to use the DataContract/DataMember attributes…’
Should mention you need to use the ‘KnownType’ attributes on the base ‘Request’ & ‘Response’ types to include all derived types in the client side proxy.
November 9th, 2009 at 1:22 pm
no i have a better solution for that, which you’ll see in the Exposing Through WCF post
(which is currently scheduled for wednesday)
November 9th, 2009 at 5:24 pm
Fetching by response means one request type to one response type, I am not sure in the long term that’s good. It does interfere with generic entity requests/responses for example.
November 9th, 2009 at 5:26 pm
You can add multiple requests of the same type, but then you’d have to add them with a specific key value, and retrieve the responses of that type with the correct key value
that’s also covered in a future post
what exactly do you mean with generic entity requests/responses?
November 9th, 2009 at 5:53 pm
let me guess you’re going to expose the message schemas via the actual service…
November 9th, 2009 at 5:55 pm
generic like
EntityListRequest : Request
{
Criteria{get;set}
Id{get;set}
}
EntityListResponse : Response
{
IList Entities
}
November 9th, 2009 at 6:03 pm
@Aaron
oh that would work with the keyed adding/retrieving of the requests/responses… guess you have to wait on the posts about client-side usage
@Awkward Coder
Instead of using the KnownType attribute all over the place, we just register them once before the service starts up and then use WCF’s ServiceKnownType to dynamically fetch the list of known types once before the service is first used.