I'm developing an WCF Rest service that I'm going to host on an IIS.
Now I'm implementing Service Contract, and I see that I'm repeating the same code on all of my methods when I'm trying to handle exceptions.
This is one of my Service Contract method:
public void DeleteMessage(string message_id)
{
int messageId;
OutgoingWebResponseContext ctx =
WebOperationContext.Current.OutgoingResponse;
if ((message_id == null) || (!Int32.TryParse(message_id, out messageId)) || (messageId < 1))
{
ctx.StatusCode = System.Net.HttpStatusCode.BadRequest;
ctx.StatusDescription = "message_id parameter is not valid";
throw new ArgumentException("DeleteMessage: message_id is not valid", "message_id");
}
try
{
using (var context = new AdnLineContext())
{
Message message = new Message() { MessageId = messageId };
context.Entry(message).State = EntityState.Deleted;
context.SaveChanges();
ctx.StatusCode = System.Net.HttpStatusCode.OK;
}
}
catch (Exception ex)
{
ctx.StatusCode = System.Net.HttpStatusCode.InternalServerError;
ctx.StatusDescription = ex.Message;
ctx.SuppressEntityBody = true;
}
}
On all of my methods I could throw an ArgumentException or an Exception, and manage them with return a HTTP STATUS CODE.
Is there any way to catch that exceptions globally?
MS-recommended approach appears to follow FaultException pattern. The idea is to implement IErrorHandler interface. This answer explains how to set it up in WCF configuration.
Having seen an implementation of this pattern in old-style WCF service I can tell that it probably makes sense only for complex enterprise-level scenarios. For simple cases I'd stick with throwing exceptions manually.
Another alternative is to implement REST service with Web API. It has nice exception handling strategy out of the box and that's what Microsoft is actually recommends for REST development in .NET Technology Guide for Business Applications.
WCF has an excellent built-in extensibility mechanism for converting exceptions to faults. This extensibility point can be consumed through the IErrorHandler interface, which provides two methods: HandleError and ProvideFault. The HandleError method is called on a separate thread after the call has already completed, to possibly log the error and perform other operations. Below is a useful link
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.providefault.aspx
LoggingConfiguration Section in service web.config file is another option to log errors.
http://msdn.microsoft.com/en-us/library/aa303433.aspx
Related
Im creating API in .NET Core, which consumes WCF Service. Accessing WCF service is realised, by calling any method, getting an exception (Access denied), and than calling LogIn method using cookie returned in header with first call response. Than, after login i want to retry my original call. All exceptions are the same, and only message string is different. Here is my code for one method call:
public async Task<List<scheduleElement>> getSchedule(DateTime start, DateTime end)
{
bool secondTry = false;
while (true)
{
try
{
var data = await _scheduleServiceClient.getScheduleAsync(start, end);
if (data.#return == null) return new List<scheduleElement>();
return data.#return.ToList();
}
catch (Exception e)
{
if (!secondTry && e.Message.StartsWith("Access denied for WebService method:"))
{
var logged = await LogIntoSOAPServices();
if (!logged) throw;
}
else throw;
secondTry = true;
}
}
}
Im using proxies generated with WCF Web Service Reference Provider
This works, but Im looking for a way to globaly handle exceptions and retry logic like this, because im going to have to copy and paste tons of code. I have Exception handler in my API but if i catch this exceptions with it im not able to retry method i originaly called.
A common library for cases like these is Polly;
https://github.com/App-vNext/Polly
Its part of the dotnet foundation i believe and is quite commonly used.
You can handle specific exceptions or results and act on that, e.g.
// Retry once
Policy
.Handle<SomeExceptionType>()
.Retry()
The logic can get quite complex. For webApi's i usually follow this guide from msdn:
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly
Is there a way of correctly handling WebExceptions within a Data Access Layer?
Below is a method SendReceive within our DAL used to communicate with our remote server, if there is a communication issue, such as endpoint being inaccessible and therefore no data can be retrieved, I would like the user to be redirected to a View, informing the user to please try again later.
private static TResult SendReceive<TResult, TPayLoad>(string method, string route, TPayLoad payload, bool post, bool authentication, string hashedPassword)
{
var subject = "WebApplication1 - " + method + " Error";
using (var webClient = new WebClient())
{
try
{
var uri = new Uri("http://ourdomain/ourwebapicontroller/" + route);
webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
if (authentication)
{
var hashedPasswordAsBytes = Encoding.UTF8.GetBytes(hashedPassword);
webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(hashedPasswordAsBytes));
}
var response = post ? webClient.UploadString(uri, JsonConvert.SerializeObject(payload)) : webClient.DownloadString(uri);
var parsedResponse = JsonConvert.DeserializeObject<TResult>(response);
return parsedResponse;
}
catch (WebException webException)
{
SendEmail(subject, MvcApplication.To, MvcApplication.From, "<p>WebException [" + webException.Message + "]</p>");
// Issue with endpoint
}
catch (Exception exception)
{
SendEmail(subject, MvcApplication.To, MvcApplication.From, "<p>Exception [" + exception.Message + "]</p>");
}
}
return default(TResult);
}
public Models.WebApplication1.Test GetTest(int id)
{
return SendReceive<Models.WebApplication1.Test, int?>("GetTest", "get-test/" + id, null, false, false, null);
}
public int SetTest(Models.WebApplication1.Test test)
{
return SendReceive<int, Models.WebApplication1.Test>("SetTest", "set-test", test, true, false, null);
}
As the DAL is referenced from a Controller I don't believe it is possible to use throw new HttpException(), this can however be handled like so:
public ViewResult Test(int id)
{
var test = Dal.GetTest(id);
if (test == null)
{
throw new HttpException(404, "Please try again later.");
}
return View(test);
}
Would prefer to handle the communication issue within SendReceive as opposed to handling at Controller level for each method referencing SendReceive.
Everything depends on what you mean by "handle" and even "exception."
Controller
Within the controller, what do you want to do if the client requests something that doesn't exist? A 404 is a good response. But what if the DAL throws an exception? Would it make sense to return the exact same result to the client? A 500 error which tells the client something went wrong might make more sense.
That mismatch is indicated here:
throw new HttpException(404, "Please try again later.");
If the request threw an exception (for any reason, including the DAL) then returning a 500 error with "try again later" makes sense. You're communicating clearly that the problem is on your end. Sorry, hopefully it won't happen again, and if does we're working on it.
If the client requested something that doesn't exist then that may or may not ever change. Should they try again later? Why? Maybe what they've requested will never be found. That's also not an exception. Someone asking for something that doesn't exist and getting nothing means that your application is working correctly. The 404 tells them that our application is working - we just don't have what they want.
Based on that, bubbling up an actual exception to the controller probably makes sense. The DAL doesn't know about the controller or even a website. It's not in a good position to know whether or not the caller should know that there was an exception.
DAL
"Handling" an exception can mean different things. (I'll leave out my opinion about which is right because it's not relevant.)
If your DAL throws an exception, you can do a few things. Some are maybe better than others, but again, that depends on opinion and needs.
- Do nothing. Let the exception bubble up.
- Log it and rethrow it.
- Log it then wrap it in another exception that provides some context, and throw the new exception. (Whether to wrap an exception or not is a whole discussion.)
Some would say that "handling" an exception is something different that involves somehow reacting to the exception in a way that solves a problem, something we're less likely to do. For example, if our application retrieves a daily Chuck Norris joke from an API but it throws an exception, we might log it so we know something went wrong but then replace it with a backup Chuck Norris joke.
The most important thing I wouldn't do is "hide" the exception so that, to the caller, an exception and "nothing found" look the same. If something has gone wrong, the controller needs to know that - even if it doesn't understand the specifics - so it (not the DAL) - can determine what should be communicated to the caller.
The relationship between the controller and the DAL is similar to that between the browser client and the controller. If it's not just working, we communicate that. If there's no data, we communicate that.
I don't recommend putting writing code in the DAL that sends an email. That's very specific, and it couples all of your code to that decision and possibly to an implementation of sending mail.
An alternative is defining an interface like this:
public interface ILog
{
void LogException(Exception ex);
void LogMessage(string message);
}
...and injecting into the DAL class. When an exception occurs, call _log.LogException(ex);. Your DAL doesn't know what the implementation is. You could log it or even send an email if you want to.
Many of our current controllers look like this:
[HttpPost]
public List<Foo> Post([FromBody]Bar model)
{
if (model == null)
{
throw new ArgumentNullException();
}
try
{
// business logic
}
catch (Exception ex)
{
// logging
}
return dto;
}
A lot of code is being repeated here though. What I'd like to do is implement a base controller that handles exceptions so I can return a standardized response with fields like Payload, Success, Error, etc.
Prior to .net core this was possible by providing an override of OnException however this doesn't appear to work with a .net core api controller. How do I go about consolidating this exception logic to return a custom response when things go awry in my controller bodies?
I'd like this, as a starting point:
[HttpPost]
public StandardFoo Post([FromBody]Bar model)
{
if (model == null)
{
throw new ArgumentNullException();
}
// business logic
return new StandardFoo(){Payload: dto};
}
Where exceptions thrown by model validation or business logic bubble up to some piece of logic that returns a new StandardFoo with a property containing the exception details.
If shortly, you should not catch and process exceptions in your controllers.
Instead, you need to separate normal and error flows in your code and then process error flow separately. One of the main approaches to indicate that normal flow is not possible is to raise the .NET Exceptions (and you use it). But:
Controllers actions should be aware only of normal flow. No try-catch logic and so on.
For input validation use ActionFilter. You may have global filters for all controllers or define specific per action. See Filters section in documentation. ASP.NET Core allows also do Model Validation.
During controller action execution you should raise exceptions as soon as possible and stop further pipeline execution. And yes, the Exception may be raised on any of the levels (action level, Service/Business layer, DA layer, etc).
How to handle the raised exception then?
use provided by ASP.NET Core error handling approaches (like ExceptionHandler, or Exception Filters), it allows to analyze exceptions and generate appropriate/different responses accordingly. Look into related SO Error handling in ASP.NET Core question for the example. There is also the error-handling section in documentation.
I would recommend creating a custom action filter. This can be wrapped around every incoming request in the WebApiConfig Register method(See below).
In my example, I am checking that the model state is valid.
If it's not, I create an ErrorResponse and send back a Bad Request.
You don't have to simply send back the model state like in the example below, you could return anything you actually want.
This way it becomes uniform across all endpoints that have a model that needs to be validated as well as any other checks you want to do at this point in the pipeline.
Note: Because we are registering this attribute globally we dont then have to declare it anywhere else, from this point on, all incoming traffic be inspected by this class.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
public override bool AllowMultiple
{
get { return false; }
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.Filters.Add(new ValidateModelAttribute());
}
}
If you're using .Net Core, a great way to handle errors is to use the Exception Handling Middleware.
See these articles for more details:
https://code-maze.com/global-error-handling-aspnetcore/
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-5.0
This enables the removing of error handling logic, which is a cross cutting concern, into a dedicated component, allowing your controllers to remain thin and have a single responsibility - ultimately making your code/application more maintainable and robust.
I'm consuming a clunky WCF server that occasionally throws various exceptions, and additionally returns some of its errors as string. I have no access to the server code at all.
I want to override the inner WCF-client request invocation method and handle all inner exceptions and hard-coded errors returned by the server and raise the Fault event if an error occurs, pseudo:
class MyClient : MyServiceSoapClient
{
protected override OnInvoke()
{
object result;
try
{
result = base.OnInvoke();
if(result == "Error")
{
//raise fault event
}
catch
{
//raise fault event
}
}
}
So that when I call myClient.GetHelloWorld(), it goes thru my overridden method.
How can this be achieved?
I know I don't have to use the generated client, but I don't want to re-implement all the contracts again, and I want to use the generated ClientBase subclass or at least its channel.
What I need is control over the inner request call method.
Update
I read this answer, and looks it's partially what I'm looking for, but I'm wondering if there is a way to attach an IErrorHandler to the consumer (client) code only, I want to add it to the ClientBase<TChannel> instance somehow.
Update
This article also looks very promising but it doesn't work. The applied attribute doesn't seem to take effect.
I can't find a way to add IServiceBehavior to the client side.
Update
I tried attaching an IErrorHandler via IEndpointBehavior.ApplyClientBehavior calling:
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers
.Add(new ErrorHandler());
}
(clientRuntime is a parameter), but exceptions are still thrown directly skipping MyErrorHandler.
ApplyDispatchBehavior isn't called at all.
Conclusion
I need to achieve two aspects:
Wrap all exceptions that might occur during the lifetime of a BaseClient<TChannel> and decide whether to handle them or throw them on. This should take care of all operation (the service I'm consuming exposes few dozens)
Parse all server-replies and throw exceptions for some of them, so they're forwarded as in statement 1.
You could use and modify the Exception Handling WCF Proxy Generator, more specifically, the base class that it uses. It's basic idea (check this description too) is to provide connection resilience by catching connection faults, and retrying the failed operation. As you can imagine, for this purpose it needs to be able to catch thrown exceptions, and also, it can inspect the result of calls.
The main functionality is given by the ExceptionHandlingProxyBase<T> base class, which you use instead of the ClientBase<T>. This base class has an Invoke method as follows, you'd need to modify that.
Simplified Invoke:
protected TResult Invoke<TResult>(string operationName, params object[] parameters)
{
this.Open();
MethodInfo methodInfo = GetMethod(operationName);
TResult result = default(TResult);
try
{
this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait);
result = (TResult)methodInfo.Invoke(m_channel, parameters);
}
catch (TargetInvocationException targetEx) // Invoke() always throws this type
{
CommunicationException commEx = targetEx.InnerException as CommunicationException;
if (commEx == null)
{
throw targetEx.InnerException; // not a communication exception, throw it
}
FaultException faultEx = commEx as FaultException;
if (faultEx != null)
{
throw targetEx.InnerException; // the service threw a fault, throw it
}
//... Retry logic
}
return result;
}
You'll need to modify the throw targetEx.InnerException; part to handle the exceptions as you need, and obviously the resturn value shoudl also be inspected for your needs. Other then that you can leave the retry logic or throw it away if you don't expect connection problems. There is another variant of the Invoke for void return methods.
Oh, and by the way, it works with duplex channels as well, there is another base class for those.
If you don't want to use the generator (it might not even work in newer versions of VS), then you could just take the base class for example from here, and generate the actual implementation class with T4 from your service interface.
If the service isn't returning a true exception, but just a message, you probably want to add a ClientMessageInspector as a new client behavior. Please see: https://msdn.microsoft.com/en-us/library/ms733786.aspx
I've ended up using something based on the answers in this question.
It sticks to the generated client code, and allows invocation of the operations generically.
The code is incomplete, feel free to fork and edit it. Please notify me if you found any bugs or made any updates.
It's pretty bulky so I'll just share the usage code:
using (var proxy = new ClientProxy<MyServiceSoapClientChannel, MyServiceSoapChannel>())
{
client.Exception += (sender, eventArgs) =>
{
//All the exceptions will get here, can be customized by overriding ClientProxy.
Console.WriteLine($#"A '{eventArgs.Exception.GetType()}' occurred
during operation '{eventArgs.Operation.Method.Name}'.");
eventArgs.Handled = true;
};
client.Invoke(client.Client.MyOperation, "arg1", "arg2");
}
I have a client application that consumes a number of services. It's not always immediately obvious when a service is down or incorrectly configured. I own the service side code and hosting for most of the services, but not all of them. It's a real mixed bag of client proxies - different bindings (basichttp/wshttp/nettcp), some have been generated using svcutil.exe, while others are made programatically with ChannelFactory where the contract is in a common assembly. However, I always have access to the address, binding and contract.
I would like to have a single component in my client application that could perform a basic check of the binding/endpoint config and the service availability (to show in some diagnostic panel in the client). As a minimum I just want to know that there is an endpoint at the configured address, even better would be to find out if the endpoint is responsive and supports the binding the client is trying to use.
I tried googling and was surprised that I didn't find an example (already a bad sign perhaps) but I figured that it couldn't be that hard, all I had to do was to create a clientchannel and try to open() and close() catch any exceptions that occur and abort() if necessary.
I was wrong - in particular, with clients using BasicHttpBinding where I can specify any endpoint address and am able to open and close without any exceptions.
Here's a trimmed down version of my implementation, in reality I'm returning slightly more detailed info about the type of exception and the endpoint address but this is the basic structure.
public class GenericClientStatusChecker<TChannel> : ICanCheckServiceStatus where TChannel : class
{
public GenericClientStatusChecker(Binding binding, EndpointAddress endpoint)
{
_endpoint = endpoint;
_binding = binding;
}
public bool CheckServiceStatus()
{
bool isOk = false;
ChannelFactory<TChannel> clientChannelFactory = null;
IClientChannel clientChannel = null;
try
{
clientChannelFactory = new ChannelFactory<TChannel>(_binding, _endpoint);
}
catch
{
return isOk;
}
try
{
clientChannel = clientChannelFactory.CreateChannel() as IClientChannel;
clientChannel.Open();
clientChannel.Close();
isOk = true;
}
catch
{
if (clientChannel != null)
clientChannel.Abort();
}
return isOk;
}
}
[Test]
public void CheckServiceAtNonexistentEndpoint_ExpectFalse()
{
var checker = new GenericClientStatusChecker<IDateTimeService>(new BasicHttpBinding(), new Endpointaddress("http://nonexistenturl"));
// This assert fails, because according to my implementation, everything's ok
Assert.IsFalse(checker.CheckServiceStatus());
}
I also tried a similar technique with a dummy testclient class that implemented ClientBase with the same result. I suppose it might be possible if I knew that all my service contracts implemented a common CheckHealth() method, but because some of the services are outside my control, I can't even do that.
So, is it even possible to write such a simple general purpose generic service checker as this? And if so how? (And if not, why not?)
Thanks!
Have you looked at WCF Discovery?
WCF Discovery allows a client to search for a service based on
different criteria including contract types, binding elements,
namespace, scope, and keywords or version numbers. WCF Discovery
enables runtime and design time discovery. Adding discovery to your
application can be used to enable other scenarios such as fault
tolerance and auto configuration.
For a first attempt, you could query the endpoint to see if it supports the expected contract.
The big benefit is that you can have the client “discover” which service it wants to talk to at runtime. Which removes a lot of the client side configuration errors that you are likely used to seeing.
You need to check out SO-AWARE. It is a web service management tool that can manage SOAP or REST WCF-based service across your organization. Further it has a Test Workbench!
Here are a couple of videos that show it off too:
Part 1
Part 2
To put it in perspective, this is so complex that these people make a living doing it, I don't think it's something you want to realistically build on your own.