private static RequestAsyncHandler BuildAsyncHandler(
Type targetType, Type invokePayloadType, Type returnPayloadType, MethodInfo method, FilterChain filterChain)
{
var isAsyncMethod = method.ReturnType.Name.StartsWith("Task");
var handler = isAsyncMethod
? RequestHandlerAsyncBuilder.Build(targetType, invokePayloadType, returnPayloadType, method)
: RequestHandlerSyncToAsyncBuilder.Build(targetType, invokePayloadType, returnPayloadType, method);
// TODO: Optimize this function when without async filter
return async delegate(object self, RequestMessage request, Action<ResponseMessage, Exception> onCompleted)
{
var filterPerInstanceProvider = filterChain.PerInstanceFilterExists ? (IFilterPerInstanceProvider)self : null;
// Create PerRequest filters
IFilter[] filterPerRequests = null;
if (filterChain.PerInvokeFilterFactories.Length > 0)
{
filterPerRequests = new IFilter[filterChain.PerInvokeFilterFactories.Length];
for (var i = 0; i < filterChain.PerInvokeFilterFactories.Length; i++)
{
filterPerRequests[i] = filterChain.PerInvokeFilterFactories[i].CreateInstance(self, request);
}
}
// Call PreFilters
ResponseMessage response = null;
Exception exception = null;
if (filterChain.PreFilterAccessors.Length > 0)
{
var context = new PreRequestFilterContext
{
Actor = self,
Request = request
};
foreach (var filterAccessor in filterChain.PreFilterAccessors)
{
try
{
var filter = filterAccessor(filterPerInstanceProvider, filterPerRequests);
var preFilter = filter as IPreRequestFilter;
if (preFilter != null)
preFilter.OnPreRequest(context);
else
await ((IPreRequestAsyncFilter)filter).OnPreRequestAsync(context);
}
catch (Exception e)
{
context.Exception = e;
}
}
response = context.Response;
exception = context.Exception;
}
// Call Handler
var intercepted = response != null || exception != null;
if (intercepted == false)
{
try
{
var returnPayload = await handler(self, request.InvokePayload);
response = new ResponseMessage
{
RequestId = request.RequestId,
ReturnPayload = returnPayload
};
}
catch (ResponsiveException e)
{
response = new ResponseMessage
{
RequestId = request.RequestId,
Exception = e.InnerException
};
}
catch (Exception e)
{
exception = e;
}
}
// Call PostFilters
if (filterChain.PostFilterAccessors.Length > 0)
{
var context = new PostRequestFilterContext
{
Actor = self,
Request = request,
Response = response,
Exception = exception,
Intercepted = intercepted
};
foreach (var filterAccessor in filterChain.PostFilterAccessors)
{
try
{
var filter = filterAccessor(filterPerInstanceProvider, filterPerRequests);
var postFilter = filter as IPostRequestFilter;
if (postFilter != null)
postFilter.OnPostRequest(context);
else
await ((IPostRequestAsyncFilter)filter).OnPostRequestAsync(context);
}
catch (Exception e)
{
context.Exception = e;
}
}
response = context.Response;
exception = context.Exception;
}
// Build response for a thrown exception
if (exception != null && response == null)
{
response = new ResponseMessage
{
RequestId = request.RequestId,
Exception = new RequestFaultException("", exception)
};
}
// Callback
onCompleted?.Invoke(response, exception);
return response;
};
}