I'm working on a project that relies extensively on Exchange Web Services. As of now I'm wrapping all of my service calls on try/catch. While this isn't a problem per say it does clutter code quite a bit by having one line turn into 10~.
Here are the options I see:
Create a function such as bool TryExecute(Action action, Action failCallback)
Interface all of my service calls and use an interceptor to wrap my calls
Are these any alternatives that I'm missing?
that depends on your implementation. I would place the try/catch as near to the point where failure is expected (and can be gracefully handeled) as possible.
For example wrapping those calls into a interface (for testing) and using only a common exception-type otherwise (for example handle EndpointNotFound and wrap any unexpected failure into a ExchangeCommunication-Exception you created yourself).
Both of your options seems to handle every kind of error, and I would not advise this but aside from that it's surely better than going against DRY
Related
We are creating a new .Net Core Library, an application service that resides within a Clean Architecture.
The new service will read new customer details via the RepositoryService layer and Post them via a RestApiService Layer to multiple systems including : CreditCheck system, Billing system etc..
Within the new Application Service we want a consistent way of handling responses from RestAPi service. Response data includes:
- Return values: entities returned by restAPI service
- Exceptions like an error 500, time outs.. that have bubbled up from the RestAPi.
- Data Errors messages such as Customer already exists, bank details invalid
- Warning messages ... "Processing continues as normal, but order is flagged"
It is the last two that are foxing us, because this is different to the interaction with the Repository layer which has no business logic, so basically returns a success or an exception.
Microsoft and SOLID virtually state that the use of exceptions handling is the way to go , whether it be exceptions, errors or warnings.
But in this scenario not clear how this will work ..
a. We loose the option of handling and forwarding on the return values.
We really don't fancy storing all this in the exception message
- Whilst not a show stopper, we fear the code will be more difficult to read than it needs to be.
- Exception handling is expensive,but not worried too much on this score with number of transactions.
We are drawn to some how using FluentValidation or a hybrid version, it will need to work with Logging and RepositoryService as we will need log and decode stuff .
We really don't fancy repeating the RestAPi Service layer approach i.e. handling HTTP exceptions separately, then processing return values which are basically extended entities with Errors Status , Error codes and messages.
We are not expecting the above to be specific to our company. The issue seems to be around handling messages from a 3rd Party Business logic layer , within our Application Service.
So our question is how can we best handle Errors warnings along side data in the application service layer and still have SOLID testable and maintainable code ?
Microsoft and SOLID are right.
The correct way to go are Exceptions as per standard practices (and c#), independently of another considerations, like performance for instance.
Generally speaking there are two different types of "Errors", technical, and business logic related.
Failing to Connect to a DB, receiving a 500 from a REST Service, etc... are technical, and as they could be transient you can try to recover from this situation, sometimes without success, what finally causes the Business Orchestration/Process failure.
Business Logic errors, like 'Customer already exists', 'Bank details invalid','Input data is not in the valid format' are non-transient, and determined solely by Business Rules (some implicit, other explicit) and will stop stop your process as well without possibility to recover, simply because something is not in the proper/expected state.
There is a reason we use Exceptions (as technical artifacts) and is to handle these hard-stops 'properly'.
Every time you throw an Exception the application traverse back the stack up to the first available Exception Handler able to handle such Exception, returning the control to you and to a known location where something will happen (telemetry, rethrow, show a dialog to the user...)
Any mechanism trying to substitute this propagation (Error) must rely, for instance, on hijacking the return value of the methods to provide back a status, or forcibly include an out parameter to all your methods signatures, which will have awful collateral effects in your implementation.
Yes, sometimes your current design look 'too flat' that you are tempted to hijack the return value here and there, creating a highly coupled component, but you never can tell how the system complexity will grow, meaning that at some point you will extend your system with additional layers, and most likely the 'substituting mechanism' approach will not fit , and you are forced to support them, the regular way and the imaginative one.
So, trying to implement a custom solution will create a tightly-coupled technical requirement that must be supported all across the board, what in architecture terms is simply 'not good' (not a good practice)
IF any Service you are consuming is not able to produce a meaningful 'error' information, well structured, then, the Service is not well designed, and the problem flips to the Client side (Talking in SOA terms).
The only 'most correct' solution left to not introduce chaos in your Client is by creating a Proxy to the Service RESPECTING the rules required by your implementation approach.
My recommendation about Error Handling is very simple, stick to the rules that are well know and have been in place for decades and do not try workaround this by yourself, or you are going to face too many issues, create a Proxy for each service and integrate them properly in your code base (unit testing and such)
In regards to warnings, there is no recommendation from anybody to handle this by using Exceptions, those 'warnings' in your question is a normal output when interacting to the Service/a logical state supported by the Business Logic, thus, the place to handle this state is in the Data Contract coming back from the Service, again, if the Service is so horribly designed that is replying you with just a text string containing the word 'warning', and you are forced to parse this string to notice the situation, then your Proxy to the Service should check for it and provide a meaningful and well structured output to the Client.
I'd like to be able to add a couple of behaviors without having to call a method forcing them to be to used. A typical example is via an [InvokeErrorSupport] attribute whose purpose would be to fire off a test e-mail when deploying a service to ensure the error e-mails are coming through okay. Thus saving magic strings in a request Parameter Object, one or more non-business logic related [OperationContract] methods etc dirtying up the contract (with single responsibility in mind). We are more than happy to potentially invoke a method in other case such as our [Heartbeat] behavior and similar.
I have no problem writing the behaviors. It's a great feature of WCF but right now its looking like I'm going to have to add some method to the contract which I call such as Initialize which I'd lock down after start-up. Since, in this instance and more, the services are often external facing so we wish to avoid DoS attacks etc.
I've poked about client-side and can't see anyway and to be honest it kinda makes a degree of sense this functionality doesn't exist.
Can anybody offer any advice?
I would like to make the retry logic transparent, ideally utilizing Microsoft's Transient Fault Handling Application Block, instead of wrapping every database-accessing piece of my code into a function that retries.
What I can do is creating a custom IDbConnectionFactory
that produces custom IDbConnection objects of type MySqlAzureConnection:
MySqlAzureConnection dbConn = myConnFactory.OpenDbConnection();
dbConn.Insert(new Employee { ... });
I have two choices:
Add an .Insert() method to MySqlAzureConnection to hide
the same extension method of OrmLite, to provide my retry logic.
Actually my .Insert() will contain exactly the same source code
as in OrmLite: call dbConn.Exec(), but that .Exec() will be
my implementation that provides the retry logic.
The problem is that (in order to be sure that queries and writes
in my program always use the retry logic) this way I will end up
with copy&pasting all the 120+ methods in the
[OrmLite][Read|Write]ConnectionExtensions static classes,
just to extend the behaviour of the very single dbConn.Exec().
Not sounds too good.
Omit using ServiceStack.OrmLite; to make sure that the non-retrying
implementations of OrmLite won't get called. In this case how can I use
OrmLite? I'll have to write full namespace-qualified names all the time.
Sounds terrible, too.
EDIT:
I realized that there's a third choice: giving up the requirement of
the retry logic being 'transparent'. In other words, admit the explicit use
of a wrapper function at every piece of code that uses OrmLite, and
implement the retry logic in that wrapper function. In fact, the Transient Fault Handling Application Block
does the very same thing: introduces ExecuteCommand(), a new method
(non-standard in an IDbConnection) and makes the developer responsible
for using it as a high-level wrapper around any database-accessing code.
Whilst this solution sounds better than the first two, I'm still not
satisfied with it. The Entity Framework (6.0) has managed to make
this resiliency transparent, and I'm looking forward to a similiar
solution here. (It would be easy to wire into OrmLite's
ReadConnectionExtensions.Exec() method – if it weren't a static extension
method. Even better is an injectable module, as done in the Entity Framework)
.
Did some further research on this and it turns out that transient error handling is now built into SqlConnection under the hood from .Net 4.6.1 onwards. Therefore as a raw Ado.net SqlConnection underpins Ormlite any custom approach should be rendered unnecessary.
Dan
In IDesign WCF coding standard it says :
"Do not duplicate proxy code. If two or more clients use the same contract, factor the proxy to a separate class library."
I would like to know what is the advantage of the above state ?
Apart from the general principle of DRY (don't repeat yourself), it avoids the potential confusion of having multiple types with the same names and members.
Of course if your two or more clients are totally independent (separate Visual Studio solutions), it's OK for each to have its own proxy.
To me it means that if you use a proxy method in more than one place, don't duplicate that code, instead move it to a separate class. For example, if you regenerate the proxy because an operation has been changed, you have to change your code everywhere you've used that operation. If that operation is only used in one spot, your code is much more maintainable.
This is also a good approach to encapsulate proxy usage and ensure the proxy is being used properly (channel is closed when finished, exceptions handled properly, channel aborted if exception caught, etc).
I recommend that if you are going to use the proxy approach that you do not use Visual Studio Add Service Reference to generate that proxy. If possible, consider using a ChannelFactory implementation.
I'm using OpenRasta 2.0 to build a REST API and its extensibility is fantastic - we've managed for instance to plug-in OAuth authentication using DotNetOpenAuth fairly painlessly.
However I've come to the point now where I need to define our responses for error conditions. We're adopting the standards regarding HTTP error codes - but I'm concious of returning meaningful responses as well, pretty much like Twitter (the perennial example of REST) does:
{
"error":"This method requires authentication.",
"request":"\/1\/statuses\/followers.json"
}
Is the best way to return an OperationResult from all of our handlers, manually capture exceptions and map to a ResponseResource? This seems to me to be a fair amount of overhead compared with how the rest of OpenRasta functions.
Or should we write some kind of contributor to capture exceptions thrown in the pipeline and globally handle the issues? Perhaps translating only exceptions of particular types (RestException?).
Basically I'm after a feeling for what the best practice for this would be and how others have handled it.
Thanks.
EDIT:
After looking at this for some time today I'm having trouble figuring out how to wrap the handler call - I've declared myself a OperationInterceptor derived class and have hooked that into the pipeline with ResourceSpace.Uses.PipelineContributor<OperationInterceptorContributor>() and set a custom dependency up ResourceSpace.Uses.CustomDependency<IOperationInterceptor, ExceptionHandlerInterceptor>(DependencyLifetime.PerRequest) but no matter in which of the methods I try and wrap in a try-catch, the exception still bubbles.
Is it RewriteOperation, BeforeExecute or AfterExecute that is the most appropriate place to trap - and if so can you give me a clue as to how to start?
Thanks.
There's a couple of things you can do to achieve what you want.
First, you can build an IOperationInterceptor that wraps the call to your handler in a try/catch block, and assign the correct OperationResult on the ICommunicationContext.
Then if you want this to be serialized in json, you'll want to assign the ResponseResource property of your operationresult to a type that describes your error (let's call it "TitsUpResource" for now).
Finally, register that type as a resource with no URI, so you can add the json codec to it
ResourceSpace.Has.ResourcesOfType().WithoutUri.TranscodedBy or whatever else you may want.