Skip to content

Commit

Permalink
Added request handling interceptors and conventions for request/respo…
Browse files Browse the repository at this point in the history
…nse types
  • Loading branch information
bartdeleye committed Jul 4, 2011
1 parent f15d182 commit 4c9e72c
Show file tree
Hide file tree
Showing 35 changed files with 1,890 additions and 630 deletions.
8 changes: 8 additions & 0 deletions Agatha.Common/Agatha.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,20 @@
<Compile Include="Caching\Timers\TimerProvider.cs" />
<Compile Include="Caching\Timers\TimerWrapper.cs" />
<Compile Include="ClientConfiguration.cs" />
<Compile Include="Configuration\IRequestHandlerRegistry.cs" />
<Compile Include="Configuration\IRequestTypeRegistry.cs" />
<Compile Include="Configuration\WcfKnownTypesBasedRequestTypeRegistry.cs" />
<Compile Include="Conventions\BasicConventions.cs" />
<Compile Include="Conventions\IConventions.cs" />
<Compile Include="Disposable.cs" />
<Compile Include="EnableClientResponseCachingAttribute.cs" />
<Compile Include="EnableServiceResponseCachingAttribute.cs" />
<Compile Include="ExceptionInfo.cs" />
<Compile Include="ExceptionType.cs" />
<Compile Include="IAsyncRequestProcessor.cs" />
<Compile Include="IEnableResponseCachingAttribute.cs" />
<Compile Include="Interceptors\ConventionBasedInterceptor.cs" />
<Compile Include="Interceptors\IRequestHandlerInterceptor.cs" />
<Compile Include="InversionOfControl\IContainer.cs" />
<Compile Include="InversionOfControl\IoC.cs" />
<Compile Include="InversionOfControl\Lifestyle.cs" />
Expand All @@ -108,6 +115,7 @@
<Compile Include="RequestDispatcherFactory.cs" />
<Compile Include="RequestDispatcherFactoryStub.cs" />
<Compile Include="RequestDispatcherStub.cs" />
<Compile Include="RequestProcessingContext.cs" />
<Compile Include="ResponseReceiver.cs" />
<Compile Include="WCF\AsyncRequestProcessorProxy.cs" />
<Compile Include="WCF\IAsyncWcfRequestProcessor.cs" />
Expand Down
26 changes: 26 additions & 0 deletions Agatha.Common/Configuration/IRequestHandlerRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;

namespace Agatha.Common.Configuration
{
public interface IRequestHandlerRegistry
{
IEnumerable<Type> GetTypedRequestHandlers();
void Register(Type handlerType);
}

public class RequestHandlerRegistry : IRequestHandlerRegistry
{
private readonly List<Type> requestHandlerTypes = new List<Type>();

public IEnumerable<Type> GetTypedRequestHandlers()
{
return requestHandlerTypes;
}

public void Register(Type handlerType)
{
requestHandlerTypes.Add(handlerType);
}
}
}
10 changes: 10 additions & 0 deletions Agatha.Common/Configuration/IRequestTypeRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace Agatha.Common.Configuration
{
public interface IRequestTypeRegistry
{
IEnumerable<Type> GetRegisteredRequestTypes();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using Agatha.Common.WCF;

namespace Agatha.Common.Configuration
{
public class WcfKnownTypesBasedRequestTypeRegistry : IRequestTypeRegistry
{
public IEnumerable<Type> GetRegisteredRequestTypes()
{
return KnownTypeProvider.GetKnownTypes(null);
}
}
}
47 changes: 47 additions & 0 deletions Agatha.Common/Conventions/BasicConventions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Agatha.Common.Configuration;

namespace Agatha.Common.Conventions
{
public class BasicConventions : IConventions
{
private readonly IDictionary<Type, Type> requestResponseMappings = new Dictionary<Type, Type>();

public BasicConventions(IRequestTypeRegistry configuration)
{
BuildRequestReponseMappings(configuration.GetRegisteredRequestTypes());
}

private void BuildRequestReponseMappings(IEnumerable<Type> requestTypes)
{
foreach (var requestType in requestTypes.Where(t => t.Name.EndsWith("Request")))
{
requestResponseMappings.Add(requestType, DetermineResponseType(requestType));
}
}

private static Type DetermineResponseType(Type requestType)
{
var requestTypeName = requestType.FullName;
var responseTypeName = ReplaceRequestSuffix(requestTypeName);
var reponseType = requestType.Assembly.GetType(responseTypeName);
if (reponseType == null) throw new InvalidOperationException("Could not determine response type by convention for request of type " + requestTypeName);
return reponseType;
}

private static string ReplaceRequestSuffix(string requestTypeName)
{
var index = requestTypeName.LastIndexOf("Request");
return string.Concat(requestTypeName.Substring(0, index), "Response");
}

public Type GetResponseTypeFor(Request request)
{
if (request == null) throw new ArgumentNullException("request");

return requestResponseMappings[request.GetType()];
}
}
}
9 changes: 9 additions & 0 deletions Agatha.Common/Conventions/IConventions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Agatha.Common
{
public interface IConventions
{
Type GetResponseTypeFor(Request request);
}
}
23 changes: 23 additions & 0 deletions Agatha.Common/Interceptors/ConventionBasedInterceptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using Agatha.Common.InversionOfControl;

namespace Agatha.Common.Interceptors
{
public abstract class ConventionBasedInterceptor : Disposable, IRequestHandlerInterceptor
{
public abstract void BeforeHandlingRequest(RequestProcessingContext context);
public abstract void AfterHandlingRequest(RequestProcessingContext context);
protected IConventions Conventions { get; private set; }

protected ConventionBasedInterceptor()
{
Conventions = IoC.Container.Resolve<IConventions>();
}

public Response CreateDefaultResponseFor(Request request)
{
var responseType = Conventions.GetResponseTypeFor(request);
return (Response)Activator.CreateInstance(responseType);
}
}
}
10 changes: 10 additions & 0 deletions Agatha.Common/Interceptors/IRequestHandlerInterceptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Agatha.Common
{
public interface IRequestHandlerInterceptor : IDisposable
{
void BeforeHandlingRequest(RequestProcessingContext context);
void AfterHandlingRequest(RequestProcessingContext context);
}
}
24 changes: 24 additions & 0 deletions Agatha.Common/RequestProcessingContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Agatha.Common
{
public class RequestProcessingContext
{
public Request Request { get; private set; }
public Response Response { get; private set; }

public RequestProcessingContext(Request request)
{
Request = request;
}

public void MarkAsProcessed(Response response)
{
if (response == null) throw new ArgumentNullException("response");
Response = response;
IsProcessed = true;
}

public bool IsProcessed { get; private set; }
}
}
1 change: 0 additions & 1 deletion Agatha.Common/WCF/KnownTypeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public static void RegisterDerivedTypesOf(Type type, IEnumerable<Type> types)
{
List<Type> derivedTypes = GetDerivedTypesOf(type, types);
knownTypes = Union(knownTypes, derivedTypes);
knownTypes.Union(types);
}

public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
Expand Down
1 change: 1 addition & 0 deletions Agatha.ServiceLayer/Agatha.ServiceLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<Link>CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AsyncRequestProcessor.cs" />
<Compile Include="Conventions\RequestHandlerBasedConventions.cs" />
<Compile Include="ServiceLayerAndClientConfiguration.cs" />
<Compile Include="ServiceLayerConfiguration.cs" />
<Compile Include="PerformanceLoggingRequestProcessor.cs" />
Expand Down
65 changes: 65 additions & 0 deletions Agatha.ServiceLayer/Conventions/RequestHandlerBasedConventions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using Agatha.Common;
using Agatha.Common.Configuration;

namespace Agatha.ServiceLayer.Conventions
{
public class RequestHandlerBasedConventions : IConventions
{
private readonly IDictionary<Type, Type> requestResponseMappings = new Dictionary<Type, Type>();

public RequestHandlerBasedConventions(IRequestHandlerRegistry configuration)
{
BuildRequestReponseMappings(configuration.GetTypedRequestHandlers());
}

private void BuildRequestReponseMappings(IEnumerable<Type> typedRequestHandlers)
{
foreach (var handlerType in typedRequestHandlers)
{
BuildRequestResponseMapping(handlerType);
}
}

private void BuildRequestResponseMapping(Type handlerType)
{
var handlerBase = FindHandlerBase(handlerType);
if (handlerBase == null) return;

var genericArguments = handlerBase.GetGenericArguments();
if (genericArguments.Length < 2) return;

var requestType = genericArguments[0];
var responseType = genericArguments[1];

if (requestResponseMappings.ContainsKey(requestType))
return;

requestResponseMappings.Add(requestType, responseType);
}

private Type FindHandlerBase(Type handlerType)
{
while (!handlerType.IsGenericType && handlerType != typeof(object))
{
if(handlerType.BaseType.IsGenericType)
{
return handlerType.BaseType;
}
handlerType = handlerType.BaseType;
}
return null;
}

public Type GetResponseTypeFor(Request request)
{
if (request == null) throw new ArgumentNullException("request");
var requestType = request.GetType();
if(!requestResponseMappings.ContainsKey(requestType))
throw new Exception("No response type found by convention for request type " + requestType);

return requestResponseMappings[requestType];
}
}
}
9 changes: 8 additions & 1 deletion Agatha.ServiceLayer/RequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public virtual void AfterHandle(TRequest request) { }
public abstract void Handle(TRequest request);
}

public abstract class RequestHandler<TRequest, TResponse> : RequestHandler, IRequestHandler<TRequest>
public abstract class RequestHandler<TRequest, TResponse> : RequestHandler, IRequestHandler<TRequest>, ITypedRequestHandler
where TRequest : Request
where TResponse : Response
{
Expand Down Expand Up @@ -89,4 +89,11 @@ public TResponse CreateTypedResponse()
return (TResponse)Activator.CreateInstance(typeof(TResponse));
}
}

/// <summary>
/// This is just a marker interface to indicate that the request handler specifies a response type
/// </summary>
public interface ITypedRequestHandler
{
}
}
Loading

0 comments on commit 4c9e72c

Please sign in to comment.