I'm working on WCF Data Services and I want to put custom errors once I encounter one. Through my research I am pointed to overriding the HandleException method so that I can catch any exception that I will encounter but that method doesn't get executed if ever there are errors. What am I doing wrong?
Here's a sample code that I use to force the exception.
throw new DataServiceException("Testing");
Here's the override method HandleException.
protected override void HandleException(HandleExceptionArgs args)
{
throw new DataServiceException("HandleException");
}
Here's my configuration.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.DataServiceBehavior.AcceptProjectionRequests = true;
config.UseVerboseErrors = true;
}
Please helpppppp!
Can you show us where did you put the exception thrown code?
The following code puts it into a custom Action, the Handler can be called successfully.
protected override void HandleException(HandleExceptionArgs args)
{
Console.WriteLine("hello");
using (FileStream fs = new FileStream("D:\\time.txt", FileMode.Append))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now);
}
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetServiceOperationAccessRule("S1", ServiceOperationRights.All);
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.DataServiceBehavior.AcceptProjectionRequests = true;
config.UseVerboseErrors = true;
}
[WebGet]
public int S1()
{
throw new DataServiceException("ui1");
}
Also, if I put exception in the IRequestHandler logic, the handler method would also be called.
Related
I have been creating a project with Aspect Oriented Programming paradigm and
I have an "ExceptionLogAspect" class attribute which is used on business methods to log the errors throwing from them.
public class ExceptionLogAspect : MethodInterception
{
private readonly LoggerServiceBase _loggerServiceBase;
private static byte _risk;
public ExceptionLogAspect(Type loggerService, byte risk)
{
if (loggerService.BaseType != typeof(LoggerServiceBase))
{
throw new System.Exception(AspectMessages.WrongLoggerType);
}
_loggerServiceBase = (LoggerServiceBase)Activator.CreateInstance(loggerService);
_risk = risk;
}
protected override void OnException(IInvocation invocation, System.Exception e)
{
var logDetailWithException = GetLogDetail(invocation);
logDetailWithException.ExceptionMessage = e.Message;
_loggerServiceBase.Error(logDetailWithException);
}
}
This Aspect migrates MethodInterception class that I created with Castle.DinamicProxy package. And OnException method included by MethodInterception logs the exception data.
public abstract class MethodInterception:MethodInterceptionBaseAttribute
{
protected virtual void OnBefore(IInvocation invocation){}
protected virtual void OnAfter(IInvocation invocation){}
protected virtual void OnException(IInvocation invocation, System.Exception e){}
protected virtual void OnSuccess(IInvocation invocation){}
public override void Intercept(IInvocation invocation)
{
var isSuccess = true;
OnBefore(invocation);
try
{
invocation.Proceed();//Business Method works here.
}
catch (Exception e)
{
isSuccess = false;
OnException(invocation, e);
throw;
}
finally
{
if(isSuccess)
OnSuccess(invocation);
}
OnAfter(invocation);
}
}
When I run the code and try-catch block doesn't work for Exception. So catch block isn't called and no messages are logged.
If I turn the business method into a syncronous method, exception will be thrown and data will be logged.
How can I solve this asynchronous method problem?
I tried this solution, it works properly.
Intercept method has to be like this to make this process asynchronous.
Otherwise, this method doesn't work properly for async.
There are some other ways, for example Castle CoreAsync Interceptor, you can find it on Github or NuGet.
https://github.com/JSkimming/Castle.Core.AsyncInterceptor
public override void Intercept(IInvocation invocation)
{
var isSuccess = true;
OnBefore(invocation);
try
{
invocation.Proceed(); //Metodu çalıştır
if (invocation.ReturnValue is Task returnValueTask)
{
returnValueTask.GetAwaiter().GetResult();
}
if (invocation.ReturnValue is Task task && task.Exception != null)
{
throw task.Exception;
}
}
catch (Exception e)
{
isSuccess = false;
OnException(invocation, e);
throw;
}
finally
{
if (isSuccess)
OnSuccess(invocation);
}
OnAfter(invocation);
}
I have setup Serilog to log to MSSql using:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("System", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Async(x => x.MSSqlServer(logConntectionString, tableName, LogEventLevel.Warning, autoCreateSqlTable: false, columnOptions: columnOptions))
.CreateLogger();
Additionally I have added added a SerilogMiddleware in the pipeline that successfully adds LogContext from the HttpContext.
In a test controller, I have these 2 test methods:
public class TestController : ControllerBase
{
[HttpGet, Route("test")]
public IActionResult Get() {
try
{
string[] sar = new string[0];
var errorgenerator = sar[2]; // Trigger exception
}
catch (Exception ex)
{
Log.Error(ex, "Caught Exception");
return StatusCode(500, "Custom 500 Error");
}
return Ok();
}
[HttpGet, Route("test2")]
public IActionResult Get2() {
string[] sar = new string[0];
var errorgenerator = sar[2];// Trigger exception
return Ok();
}
}
The first method is not DRY, and so I would like to handle global/uncaught exceptions such as method 2.
What I have from here is:
public class GloablExceptionFilter : ActionFilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext context)
{
var httpContext = context.HttpContext; // This does not appear to have the actual HttpContext
Log.Error(context.Exception, "Unhandled Exception");
}
}
Problem is, my middleware that otherwise worked no longer does.. It does not edit the response body, etc... Further, when I access ExceptionContext's context.HttpContext, it does not contain the actual HttpContext when triggered from inside a controller method such as above.
How do I inject or share HttpContext and or LogContext with this Filter?
If thats not possible, how do I accomplish logging exceptions, while being DRY, and having context when its available?
Update 1: Current Middleware
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddSerilog();
app.UseAuthentication();
// Logging Middleware is just after Authentication, to have access to
// user IsAuthorized, claims, etc..
app.UseMiddleware<SerilogMiddleware>();
app.UseCors("CORSPolicy");
app.UseMvc();
}
In the middleware itself:
public class SerilogMiddleware
{
readonly RequestDelegate _next;
public SerilogMiddleware(RequestDelegate next)
{
if (next == null) throw new ArgumentNullException(nameof(next));
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
// Do logging stuff with Request..
await _next(httpContext);
// Do logging stuff with Response but..
// This point is never reached, when exception is unhandled.
}
}
Based on code snippet you are not catching the exception when you pass the context down the pipeline.
If you do not catch/handle the exception within the middleware then it wont reach your code after calling down stream.
public class SerilogMiddleware {
readonly RequestDelegate _next;
public SerilogMiddleware(RequestDelegate next) {
if (next == null) throw new ArgumentNullException(nameof(next));
_next = next;
}
public async Task Invoke(HttpContext httpContext) {
// Do logging stuff with Request..
try {
await _next(httpContext);
} catch(Exception ex) {
try {
//Do exception specific logging
// if you don't want to rethrow the original exception
// then call return:
// return;
} catch (Exception loggingException) {
//custom
}
// Otherwise re -throw the original exception
throw;
}
// Do logging stuff with Response
}
}
The above will re-throw the original error after logging it so that the other handler in the pipeline will catch it and do the out of the box handling.
I am trying to mock static method using powermock.
Below is my code:
public class Helper{
public static User getLoggedInUser(HttpServletRequest request) throws NotFoundException {
String access = request.getHeader("Authorization");
if(access == null || access.isEmpty()) {
throw new Exception("Access is null");
}
User user = new User();
return user;
}
}
And this is the controller function from where i am calling the static method getUser:
#RequestMapping(value = "user/userInfo/{Id}", method = RequestMethod.GET, headers = "Accept=application/json")
public #ResponseBody
ResultDTO getUser(#PathVariable("Id") Integer Id, HttpServletRequest request) throws NotFoundException, UnauthorizedException {
Integer userID = -1;
User user = Helper.getLoggedInUser(request);
if(user != null){
userID = user.getUserId();
}
//do something
}
And this is my test class:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
public class CustomerControllerNGTest {
#InjectMocks
private userController instance = new PaymentCustomerController();
public PaymentCustomerControllerNGTest() {
}
#BeforeClass
public void setUpClass() throws Exception {
}
#AfterClass
public static void tearDownClass() throws Exception {
}
#BeforeMethod
public void setUpMethod() throws Exception {
try{
MockitoAnnotations.initMocks(this);
}catch(Exception ex){
System.out.println(ex.getMessage());
}
try{
mockMvc = MockMvcBuilders.standaloneSetup(instance).build();
// mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}catch(Exception ex){
System.out.println(ex.getMessage());
}
}
#AfterMethod
public void tearDownMethod() throws Exception {
}
#Test
public void testGetUserInfo() throws Exception {
User user = new User();
user.setUserId(1234);
HttpServletRequest request = mock(HttpServletRequest.class);
//this is for the static method
PowerMockito.mockStatic(Helper.class);
**PowerMockito.when(Helper.getLoggedInUser(request)).thenReturn(user);**
//do something
}
}
Now whenever i am executing the test case, and whenever it is executing the lone marked with bold, it is going inside the static method and throwing the exception "Access is null" rather than mocking the method , it is executing the method. Any idea?
I also tried by uncommenting these lines:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
but still same exception.
Thanks
Try to uncomment:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
and use
Mockito.when(Helper.getLoggedInUser(request)).thenReturn(user);
I wrote blog post on topic, that contain links to working examples on GitHub. These use TestNg instead of JUnit, but this shouldn't matter.
EDIT
I would suggest to always use latest combination of Mockito and PowerMock available. Older combinations were often pretty buggy with confusing errors. Current latest combination is Mockito 1.9.5-rc1+, PowerMock 1.5+. Pre-1.5 versions of PowerMock wasn't Java7 compliant.
I have created a wcf service, but when i am installing it on server, it is not picking the code.
Here is my program.cs class:
log4net.Config.XmlConfigurator.Configure();
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
and here is my service1.cs:
public Service1()
{
logger.Info("log started");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
logger.Info("Service Started");
timerHandlingFirst.Elapsed += new ElapsedEventHandler(OnElapsedTimeFirst);
timerHandlingFirst.Enabled = true;
timerHandling.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timerHandling.Enabled = true;
}
I have attached used log4net dll, but its not even generating the logs.
When working with SQL Azure, if I create my own RetryPolicy, e.g.:
var retryStrategy = new FixedInterval(3, TimeSpan.FromSeconds(10));
var retryPolicySQL = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(retryStrategy);
retryPolicySQL.Retrying += ....;
I am able to get notified when a retry is happening which is useful to log.
However, if I use what seems to be the new recommended strategy with EF6 and Azure - i.e. a custom DbConfiguration class something like this:
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () =>
{
var strat = new SqlAzureExecutionStrategy();
// strat. No events
return strat;
});
}
}
I can't seem to find a way to hook into the retrying process. Is there a way to do this?
Implement the protected method called ShouldRetryOn by subclassing from SqlAzureExecutionStrategy. In that method you could put your logic to log or hook it into a handler as I show below.
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class MyStrategy : SqlAzureExecutionStrategy
{
public event ChangedEventHandler Changed;
protected override bool ShouldRetryOn(Exception exception)
{
OnChanged(EventArgs.Empty);
return base.ShouldRetryOn(exception);
}
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
}
If you would perfer to just log the exception or the retry, you can do as follows:
public class LoggedSqlAzureExecutionStrategy : SqlAzureExecutionStrategy
{
protected override bool ShouldRetryOn(Exception exception)
{
var shouldRetry = base.ShouldRetryOn(exception);
if (shouldRetry)
{
// log retry
}
return shouldRetry;
}
}