I have a service method that does so many things.
public Result DoSomething(){
var queryResult = service.GetResult();
SaveResultToRedis(queryResult);
logger.Log($"this data saved in redis successfully {queryResult.Id}");
AddSomethingToKafka(queryResult);
logger.Log($"this data saved in kafka successfully {queryResult.Id}");
logger.Log($"this data response is success {queryResult.Id}");
}
In this stuation,
if redis or kafka fails, the request response will fail.
if logger service fails, the request response will fail.
if I put all logics in try catch blocks, code will appear so bad.
Which way may apply in this stuations? Is there any design pattern approaches or else?
If you want to try to make your method thinner, then try to apply SOLID rules.
If DoSomething() method just saves data to some database or event system, then we can separate them by database or event systems. However, code example just saves in two places and it would not be great choice separate by storage.
As an alterantive, it is possible to hide logger.log methods by creating a private helper method and call it from DoSomething():
private void ExecuteAndLog(Action action, logger, string message)
{
action();
logger.log(message);
}
and the full code looks like this:
public void SaveToKafka(string str)
{
}
public void SaveToRedis(string str)
{
}
public void DoSomething()
{
try
{
string s1 = "s1";
ExecuteAndLog(() => SaveToKafka(s1), logger, "someMessage");
ExecuteAndLog(() => SaveToRedis(s1), logger, "someMessage");
logger.log("this data response is success");
}
catch (Exception)
{
throw;
}
}
private void ExecuteAndLog(Action action, logger, string message)
{
action();
logger.log(message);
}
Related
Using Entity Framework Core 2.0 and .NET Core 2.0 Web API controllers I am trying to rewrite them from synchronous to asynchronous methods.
This actually works easy for my controller methods just querying data.
Unfortunatly I wrapped the DbContext method SaveChanges into some helper methods for centralized logging of DB changes.
And here I start struggling how to correctly use combinations of void in an asynchronous context.
Explanation of the code:
MyController is a web api controller. The PostMethod is a (currently) synchronous post method receiving the request model, handling it, making changes and then saving the changes.
The SaveChangesWithLogs within the controller calls the extension method and prints the returned logs.
The extension method SaveChangesWithLogs generates the log entries (some before saving, some after saving), does the actual saving and returns the logs.
public class MyController : BaseController
{
[HttpPost]
public IActionResult PostMethod([FromBody]PostRequestModel request)
{
//do something
SaveChangesWithLogs();
//return created at
}
protected void SaveChangesWithLogs()
{
List logs = DbContext.SaveChangesWithLogs();
foreach (string log in logs)
{
LogInfo(log); //just prints the generated logs
}
}
}
public static class MyExtensionMethod
{
public static List SaveChangesWithLogs(this DbContext dbContext)
{
List logs = null;
//pre-save prepare logs
dbContext.SaveChanges();
//post-save modifications of logs
return logs;
}
}
In tutorials about async programming they mention the methods should be async all the way down.
So my question: How would the (method signatures) of the SaveChangesWithLogs methods look like?
public class MyController2 : BaseController
{
[HttpPost]
public async Task PostMethod([FromBody]PostRequestModel request)
{
//do something
await SaveChangesWithLogs();
//return created at
}
//does a correct implementation need async here too?
protected void SaveChangesWithLogs()
{
List logs = await DbContext.SaveChangesWithLogs();
foreach (string log in logs)
{
LogInfo(log); //just prints the generated logs
}
//return what???
}
}
public static class MyExtensionMethod2
{
public static async Task> SaveChangesWithLogs(this DbContext dbContext)
{
List logs = null;
//pre-save prepare logs
await dbContext.SaveChanges();
//post-save modifications of logs
return logs;
}
}
You just use the return type as before and wrap Task around it. There is no more magic than that involved.
I'm guessing that your List type is of some type and added that for display purposes.
protected async Task<bool> SaveChangesWithLogs()
{
List logs = await DbContext.SaveChangesWithLogs();
foreach (string log in logs)
{
LogInfo(log); //just prints the generated logs
}
return true;
}
public static async Task<List<myLogType>> SaveChangesWithLogs(this DbContext dbContext)
{
List<myLogType> logs = null;
//pre-save prepare logs
await dbContext.SaveChanges();
//post-save modifications of logs
return logs;
}
I’m trying to implement a producer/consumer queue using Dataflow for HTTP requests towards a web service. I found an excellent post from Stephen Cleary, which is covering exactly this scenario. However, in contrast to Stephen’s post, I cannot mark the producer queue as complete since clients shall be able to enqueue requests throughout the entire lifetime of the application. The idea behind this approach that the client can constantly produce requests and the consumer is able to handle requests differently if more than 1 request is pending (which is required).
This requirement leads also to the fact that the consumption of the requests cannot be started after the production was finished, but have to be started the first request was enqueued. This also requires me to start the consumption in a non-blocking way (otherwise it would lead to a deadlock). I’ve done this via an async-call which is not awaited, which unfortunately hampers the exception handling. Exceptions occurring during the consumption (implementing the HTTP requests) cannot bubble up since the call of the consume-function is not awaited. I’ve introduced and event to deal with this kind of problem, but this leads me to the following questions:
Is it a good idea to use an event to forward exceptions from the consumer to the client of the producer?
Is this a good idea to implement the producer/consumer pattern in that fashion for my use case?
Are there potentially other approaches, which are more beneficial under the given circumstances?
To make it a more explicit, I’ve prepared a code example illustrating the problem I described above:
public class HttpConnector
{
private BufferBlock<RequestPayload> queue;
public delegate void ConnectorExceptionHandler(object sender, Exception e);
public event ConnectorExceptionHandler ConnectorExceptionOccured;
public Task<bool> ProduceRequest(RequestPayload payload)
{
if(this.queue == null)
{
this.queue = new BufferBlock<RequestPayload>();
this.ConsumeRequestsAsync(queue); //this call cannot be awaited since it would lead to a deadlock
//however, by not awaiting this call all exceptions raised in
//ConsumeRequestsAsync will be lost
}
return await queue.SendAsync(payload)
}
public Task ConsumeRequestsAsync(BufferBlock<RequestPayload> queue)
{
while(await queue.OutputAvailableAsync())
{
try
{
var payload = await queue.ReceiveAsync();
//do the HTTP request...
}
catch (Exception e)
{
ConnectorExceptionOccured(this, e); //fire event to forward the exception to the client
}
}
}
}
public class Client
{
private HttpConnector connector = new HttpConnector();
public Task<bool> UpdateDataAsync()
{
connector += (object sender, Exception e ) //register an event handler to receive exceptions occur
//during the consumption of the requests
{
//handle exception or re-throw
};
connector.ProduceRequest(new RequestPayload()); //produce a request
}
}
Forwarding exceptions via an event has some severe drawbacks:
Natural exception handling is not possible. If developers are aware of this mechanism, they won't catch any exception.
You cannot use AppDomain#UnhandledException for unhandled exceptions during the application runtime. In fact, if you don't have a subscription to the 'Exception'-event, the exception is completely lost.
If you have only one event to subscribe to, your exception object needs a lot of context information in order to figure out which operation caused the exception.
For our problem it turned out that it is better to use TaskCompletionSource, which is a standard technique to synchronize different threads. An instance of TaskCompletionSource class is provided by each RequestPayload object. After the consumption the TaskCompletionSource.Task is completed (either with the result or with an exception). The producer doesn't return the Task for queue.SendAsync(payload) but payload.CompletionSource.Task:
public class RequestPayload
{
public IModelBase Payload { get; set; }
public TaskCompletionSource<IResultBase> CompletionSource { get; private set; }
}
public class HttpConnector
{
private BufferBlock<RequestPayload> queue;
public Task ProduceRequest(RequestPayload payload)
{
if(this.queue == null)
{
this.queue = new BufferBlock<RequestPayload>();
this.ConsumeRequestsAsync(queue);
}
await queue.SendAsync(payload);
return await payload.CompletionSource.Task;
}
public Task ConsumeRequestsAsync(BufferBlock<RequestPayload> queue)
{
while(await queue.OutputAvailableAsync())
{
try
{
var payload = await queue.ReceiveAsync();
//do the HTTP request...
payload.CompletionSource.TrySetResult(null);
}
catch (Exception e)
{
payload.CompletionSource.TrySetException(e)
}
}
}
}
public class Client
{
private HttpConnector connector = new HttpConnector();
public Task UpdateDataAsync()
{
try
{
await connector.ProduceRequest(new RequestPayload());
}
catch(Exception e) { /*handle exception*/ }
}
}
My DAL doesn't handle exceptions and it will be propagated up to the calling method in the presenter classes where the exception will be handled.
I'm using a single handler called ExecutAction(Action action) so I'm catching exceptions in one place rather than repeating in every method.
At the moment, I'm not logging errors. Just alert the user for an action and try to keep the system alive if possible.
When showing messages to users, Presenters will use a static class called MessagingService. (ShowErrorMessage()). So that I can customize all massage boxes in one place.
private void Search()
{
ExecutAction(() =>
{
var info = _DataService.GetByACNo(_model.AccountNumber);
if (info != null)
{
_Model = info ;
this.SetViewPropertiesFromModel(_Model, _View);
}
else
{
MessageBox.Show ("Bank account not found");
}
});
}
private void ExecutAction(Action action)
{
try
{
action();
}
catch (NullReferenceException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlTypes.SqlTypeException e) { MessagingService.ShowErrorMessage(e.Message); }
catch (System.Data.SqlClient.SqlException e) { MessagingService.ShowErrorMessage(e.Message); }
}
}
Should I include general exception handler to this, to be able to handle any unforeseen exceptions?
Also could you show me a better way to handle showing messages than using a static?
Does use of lambda statements in every method call (ExecutAction(() =>) degrade code readability?
When showing user messages how to show a custom message like "Check the server connection" etc. first and then if the user wants more information (like StackTrace / technical details) he /she could press a button like More Info which is in the MessageBox dialog?
I agree with jeffrey about trying to incorporate IoC for your message service. You could define an abstract base presenter class that has a dependency on an interface for your message service. The base class would be responsible for handling the delegate execution + exception logging.
public interface IMessageService
{
void ShowErrorMessage(Exception e);
}
public abstract class PresenterBase
{
private readonly IMessageService _messageService;
public PresenterBase(IMessageService messageService)
{
this._messageService = messageService;
}
protected void ExecuteAction(Action action)
{
try
{
action();
}
catch (Exception e) { this._messageService.ShowErrorMessage(e); }
}
}
public class SearchPresenter: PresenterBase
{
public SearchPresenter(IMessageService messageService)
: base(messageService)
{
}
public void Search()
{
this.ExecuteAction(() =>
{
//perform search action
});
}
}
Regarding your question about catching all exeptions. Unless you are doing something special for specific types of exceptions, I would suggest just handling all the same. The example I provided passes the exception to the message service so that the formatting specifics can be handled by your message service.
If you have not yet incorporated any sort of IoC container, you can always start by using the interface injection and then passing the instance explicitly from the child class constructor.
public class SearchPresenter: PresenterBase
{
public SearchPresenter()
: base(new SomeMessageService())
{
}
...
}
This is at least removes the static dependency and is not too dificult to swap out later if you ever introduce an IoC container.
I think your approach is good enough for your work. Wrapping logics by ExecuteAction is an acceptable way to me. As another option, I might use AOP for centralized exception handling in practice.
Also, I might use a MessagingService resolved from dependency injection container rather than a static one.
Regarding how to display the error, that's totally depend on your business purpose. For example, you could simply log the error and tell the user "something's wrong", or show them the complete stacktrace including the environment information so they could simply copy & paste in the email.
Is there a better way to catch exceptions? I seem to be duplicating a lot of code. Basically in every controller I have a catch statement which does this:
try
{
Do something that might throw exceptions.
}
catch (exception ex)
{
Open database connection
Save exception details.
If connection cannot be made to the database save exception in a text file.
}
I have 4 controllers and around 5-6 actions methods in each controller which is a lot of code duplication. How can I trim down on the amount of line in the try catch statement above?
You could make use of Extension methods here.
Create an extension method in a new class.
public static class ExtensionMethods
{
public static void Log(this Exception obj)
{
// log your Exception here.
}
}
And use it like:
try
{
}
catch (Exception obj)
{
obj.Log();
}
You don't need to put try/catch blocks on every method. That's tedious and painful! Instead you can use the Application_Error event of Global.asax for logging the exceptions. The code below is the sample implementation which can be used to catch exceptions that occur in your web application.
protected void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (!string.IsNullOrWhiteSpace(error.Message))
{
//do whatever you want if exception occurs
Context.ClearError();
}
}
I would like also to stress that "Handled exception" especially trying to put try/catch blocks on most methods is one of the "Top 3 silent performance killers for IIS / ASP.NET apps" as explained in this blog http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/
What you are trying to do is called a cross-cutting concern. You are trying to log any error that happens anywhere in your code.
In ASP.NET MVC cross-cutting concerns can be achieved by using Filters. Filters are attributes that can be applied globally, to a controller or to a method. They run before an action method executes or after it.
You have several types of filters:
Authorization filters, they run to check if the user is allowed to access a resource.
Action filters, these run before and after an action method executes.
Result filters, these can be used to change the result of an action method (for example, add some extra HTMl to the output)
Exception filters run whenever an exception is thrown.
In your case, you are looking for exception filters. Those filters only run when an exception happens in in an action method. You could apply the filter globally so it will automatically run for all exceptions in any controller. You can also use it specifically on certain controllers or methods.
Here in the MSDN documentation you can find how to implement your own filters.
Personally, since I greatly dislike try/catch blocks, I use a static Try class that contains methods that wrap actions in reusable try/catch blocks. Ex:
public static class Try {
bool TryAction(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostException(exception);
return false;
}
}
bool TryQuietly(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostExceptionQuietly(exception);
return false;
}
}
bool TrySilently(Action pAction) {
try {
pAction();
return true;
} catch { return false; }
}
// etc... (lots of possibilities depending on your needs)
}
I have used a special class in my applications that is called ExceptionHandler, in the class that is static I have some methods to handle application's exceptions. It gives me an opportunity to centralize exception handling.
public static class ExceptionHandler
{
public static void Handle(Exception ex, bool rethrow = false) {...}
....
}
In the method you can log the exception, rethrow it, replace it with another kind of exception, etc.
I use it in a try/catch like this
try
{
//Do something that might throw exceptions.
}
catch (exception ex)
{
ExceptionHandler.Handle(ex);
}
As Wouter de Kort has rightly stated in his answer, it is cross-cutting concern, so I've put the class in my Application Layer and have used it as a Service. If you defined the class as an interface you would be able to have different implementations of it in different scenarios.
Also you can use Singleton pattern:
sealed class Logger
{
public static readonly Logger Instance = new Logger();
some overloaded methods to log difference type of objects like exceptions
public void Log(Exception ex) {}
...
}
And
Try
{
}
Catch(Exception ex)
{
Logger.Instance.Log(ex);
}
Edit
Some peoples don't like Singleton for reasonable grounds.instead of singleton we can use some DI:
class Controller
{
private ILogger logger;
public Controller(ILogger logger)
{
this.logger = logger;
}
}
And use some DI library that will inject one instance of ILogger into your controllers.
I like the answers suggesting general solutions, however I would like to point out another one which works for MVC.
If you have a common controller base (wich you should anyways, it's a Best Practice IMO). You can simply override the OnException method:
public class MyControllerBase : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
DoSomeSmartStuffWithException(filterContext.Exception);
base.OnException(filterContext);
}
}
Then simply inherit your normal controllers from your common base instead of Controller
public class MyNormalController : MyControllerBase
{
...
If you like this you can check out the Controller class for other handy virtual methods, it has many.
In ASP .NET MVC you can implement your own HandleErrorAttribute to catch all the exceptions that occur in all controllers:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var ex = filterContext.Exception;
// Open database connection
// Save exception details.
// If connection cannot be made to the database save exception in a text file.
}
}
Then register this filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
}
}
And of-course call the register method on application start-up:
public class MvcApplication : HttpApplication
{
protected override void OnApplicationStarted()
{
// ...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ...
}
}
Wouter de Kort has already explained the concept behind this in his answer.
I use IErrorHandler in my project for handle exceptions.
But how can i log incoming method parameter with exception.
I want to get Request parameter for logging.
Sample Method:
public Response GetData(Request request) {
return new Response();
}
You could get the request message like this:
Message requestMessage = OperationContext.Current.RequestContext.RequestMessage;
What I do usually is to log the entire request XML.
You don't have such information in IErrorHandler - you can only parse raw message in ProvideFault method.
You can try to use another approach - implement custom IOperationInvoker and in Invoke method do something like:
// Just synchronous implementation - for asynchronous handle InvokeBegin and InvokeEnd
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
try
{
// Run common invoker - you will create new Invoker as decorator for existing one.
return innerInvoker.Invoke(instance, inputs, outputs);
}
catch(Exception e)
{
// Handle error here
}
}
Operation invoker is responsible for selection correct operation in service and ivoke it. It is just idea - I haven't tested it.
Two ways:
The native WCF logger will capture all requests & responses when set to verbose however, these files tend to get real big, real quick.
Use log4net (search google to download)
private static readonly ILog log = LogManager.GetLogger(typeof(MyClass));
public class MyClass
{
...
public Foo DoSomething(string arg)
{
try
{
//do something
}
catch(Exception e)
{
log.error(string.format("{0} Arguements: {1}", e.Tostring(), arg);
}
}
}