Skip to content

Instantly share code, notes, and snippets.

@jchapuis
Created June 6, 2014 13:26
Show Gist options
  • Save jchapuis/b94e199ce9e790f011aa to your computer and use it in GitHub Desktop.
Save jchapuis/b94e199ce9e790f011aa to your computer and use it in GitHub Desktop.
Higher order functions example
[RegisterAsImplementedInterfaces(PerOwnedType = typeof (IConnectionScope))]
internal class ResponseDispatcher : IResponseDispatcher
{
private static readonly ILog Log = LogFactory.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly IRequestsPendingResponseRepository requestsPendingResponse;
private readonly IConnectionContext context;
public ResponseDispatcher(IRequestsPendingResponseRepository requestsPendingResponse, IConnectionContext context)
{
this.requestsPendingResponse = requestsPendingResponse;
this.context = context;
}
public void DispatchResponse(Response response)
{
DispatchOperations.DispatchResponse(
response,
RetrieveAndRemoveResponseHandlerWithId,
HandleUnexpectedResponse,
LogInvalidResponse,
LogErrorResponse);
}
private Option<ResponseHandlers> RetrieveAndRemoveResponseHandlerWithId(string id)
{
return
requestsPendingResponse.RetrieveAndRemoveRequestWithId(id)
.Select(r => new ResponseHandlers
{
HandleResponse = r.Response.SetResponse,
HandleException = r.Response.SetToException
});
}
private void LogErrorResponse(Error error)
{
context.Log(Log.ErrorFormat, "Received error response: code={0}, message={1}", error.Code, error.Message);
}
private void LogInvalidResponse(string response, XmlException exception)
{
context.Log(Log.ErrorFormat,
"Received non-conforming response, parsing fails with {0}: {1}",
exception.Message,
response);
}
private void HandleUnexpectedResponse(Response response)
{
context.Log(Log.ErrorFormat,
"Received unexpected response (id {0}): {1}",
response.Id,
response.Message);
}
}
internal static class DispatchOperations
{
public static void DispatchResponse(
Response response,
Func<string, Option<ResponseHandlers>> retrieveResponseHandlersForId,
Action<Response> handleUnexpectedResponse,
Action<string, XmlException> logInvalidResponse,
Action<Error> logErrorResponse)
{
retrieveResponseHandlersForId(response.Id)
.WhenHasValue(
handlers =>
ReceiverOperations.CheckForErrorAndHandle(
response: response.Message,
handleError: error =>
{
logErrorResponse(error);
handlers.HandleException(new ErrorResponseException(error.Code, error.Message));
},
handleOther: handlers.HandleResponse,
handleException: (invalidPayload, exception) =>
{
logInvalidResponse(invalidPayload, exception);
handlers.HandleException(new InvalidResponseException(invalidPayload, exception));
})
)
.WhenEmpty(() => handleUnexpectedResponse(response));
}
}
public static class ReceiverOperations
{
public static void CheckForErrorAndHandle(
string response,
Action<Error> handleError,
Action<string> handleOther,
Action<string, XmlException> handleException)
{
CheckForXml(
response,
xmlReader =>
{
if (xmlReader.Name == "error")
{
var error = (XElement) XNode.ReadFrom(xmlReader);
handleError(
new Error
{
Code =
(string)
error.Element("code")
.AsOption()
.ValueOrThrow(() => new XmlException("Missing error code")),
Message =
(string)
error.Element("message")
.AsOption()
.ValueOrThrow(() => new XmlException("Missing error message")),
});
}
else
{
handleOther(response);
}
},
handleException);
}
private static void CheckForXml(
string message,
Action<XmlReader> handleXml,
Action<string, XmlException> handleXmlException)
{
try
{
using (var reader = XmlReader.Create(new StringReader(message)))
{
reader.Read();
handleXml(reader);
}
}
catch (XmlException e)
{
handleXmlException(message, e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment