how can i handle WCF Services when database result is very great? - c#

I use code below:
private class WcfProxy<TService> :
ClientBase<TService> where TService : class, IContract
{
public TService WcfChannel
{
get
{
return Channel;
}
}
}
protected TResult ExecuteCommand<TResult>(Func<TContract, TResult> command)
where TResult : IDtoResponseEnvelop
{
var proxy = new WcfProxy<TContract>();
try
{
var result = command.Invoke(proxy.WcfChannel);
proxy.Close();
return result;
}
catch (CommunicationException ex)
{
proxy.Abort();
throw new BusinessException(BusinessExceptionEnum.Operational, Properties.Resources.Exception.WcfAdapterBase_CommunicationException_TransportInEnamDataIsInvalid, ex);
}
catch (TimeoutException ex)
{
proxy.Abort();
throw new BusinessException(BusinessExceptionEnum.Operational, Properties.Resources.Exception.WcfAdapterBase_TimeoutException, ex);
}
catch (Exception)
{
proxy.Abort();
throw;
}
}
When the query returns high amount of result
i encounter with this message:
The communication object cannot be used for communication because it is in the Faulted state
does exist a way or trick that i observe the result of database query successfully
or a way that i divide the result or get part of result?

Probably youneed to enlatge maxReceivedMessageSize, or one of other parameters of binding.
You can also enable wcf trace and review it with svcTraceViewer.exe

You get this error:
The communication object cannot be used for communication because it
is in the Faulted state.
because you throw an error and it is not handled and gets thrown in the iis pool.
Check this link out: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/fc60cd6d-1df9-47ff-90a8-dd8d5de1f080/ also this is not caused by the large ammount of data: WCF Cannot be used for communication because it is in the Faulted state

Related

Error handling in the repository (API REST)

I have this situation (method in Repository):
public string Get(string name)
{
string response;
try
{
using (var context = new MyDB())
{
var row = context.TblSomething.FirstOrDefault();
response = row.GetType().GetProperty(name).GetValue(row, null).ToString();
}
return response;
}
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
}
When there is content other than the Property in the name field, it throws an exception
The method is called in the Controller
public IActionResult Get(string name)
{
string response;
try
{
response = _module.MyRepository().Get(name);
}
catch (ValidationException e)
{
return BadRequest(new { error = new { message = e.Message, value = e.Value } });
}
return Ok(response);
}
How to make it not return a 500 error to the user but should be BadRequest?
The way to make it return 400 instead of 500 is to actually catch the exception. You already have a catch block that returns BadRequest, so the only assumption that can be made is that ValidationException is not what's being thrown. Catch the actual exception being thrown and you're good.
That said, absolute do not catch an exception merely to throw the same exception. All you're doing is slowing down your app. You should also never catch Exception, unless you're simply trying to generally log all exceptions and then rethrow. If you don't have a specific handler for an exception type, then don't catch it. In other words, remove these lines:
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
If you're not going to handle any exceptions as your repo code does, then don't use a try block at all.
It's also worth mentioning that you shouldn't rely on exceptions unless you have to. Throwing exceptions is a drain on performance. In a situation like this, you should simply return null, instead of throwing an exception when there's no matching property. Then, you can do a null check to verify instead of a try/catch.
You could create your own Exception Handling Middleware to catch 500 error and return your custom error status code and message.
1.Create the middleware:
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context )
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
string message = "Something is wrong!";
httpStatusCode = HttpStatusCode.BadRequest; // Or whatever status code you want to return
message = exception.Message; // Or whatever message you want to return
string result = JsonConvert.SerializeObject(new
{
error = message,
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
return context.Response.WriteAsync(result);
}
}
2.Add it into the middleware pipeline after app.UseDeveloperExceptionPage();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMiddleware(typeof(ExceptionHandlingMiddleware));
}

Application specific exception wrapping "MongoDuplicateKeyException" not catch'ed

Out of need have created application exception which wraps a MongoDuplicateKeyException and throwing that exception like below
Public class AppException : Exception
{
// all constructor implementation
public int ErrorCode { get; set; }
public string AppMessage { get; set; }
}
In method catching and throwing exception
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch(MongoduplicateKeyException ex)
{
var exception = new AppException(ex.Message, ex)
{
ErrorCode = 22,
AppMessage = "some message",
};
throw exception;
}
}
Method that calls Method1() above
try
{
//some other operation
var response = await Method1();
}
catch(AppException ex)
{
SomeOtherLoggingMethod(ex, other parameter);
}
catch(Exception ex)
{
SomeMethod(ex, other parameter);
}
Surprisingly the catch(AppException ex) catch block never gets catched even though am throwing an AppException from Method1(). It always catch the generic catch block catch(Exception ex).
After debugging, found that in catch(Exception ex) catch block the exception type ex.GetType() is actually a WriteConcernException type (MongoduplicateKeyException : WriteConcernException).
So essentially that specific catch block not hitting cause the exception type is not AppException rather WriteConcernException But
Not sure why is it so? am I missing something obvious here? Please suggest.
You found the answer while debugging. The catch(AppException ex) block is not executed because public async Task<Response> Method1 does not throw an AppException it throws a WriteConcernException.
The API shows a WriteConcernException is the superclass of DuplicateKeyException so the catch block in Method1 is not hit and the exception bubbles up to the 2nd catch block in the caller.
So if you update your code to catch the appropriate exception it should work as you intend.
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch (MongoServerException mse)
...

BusinessRuleException is not working in UI project

I'm working on 3 layer windows application in C#. We have custom exception to capture businessrule exceptions. this is getting captured in Data access layer and business layer. But it is not falling in businessrule exception in UI project.
[Serializable]
public class BusinessRuleException : ApplicationException
{
public BusinessRuleException():base(){}
public BusinessRuleException(string message):base(message){}
public BusinessRuleException(string message, Exception exception):base(message,exception){}
public BusinessRuleException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context):base(info,context){}
}
In Data access layer, below catch block is getting captured.
catch (BusinessRuleException ex)
{
throw ex;
}
In UI, below catch block is not working. it is going to System.Exception catch block
catch(BusinessRuleException ex)
{
m_strErrorMessage = ex.Message;
}
catch(Exception ex)
{
m_strErrorMessage = ex.Message;
}

How to log the "path taken" by the code and its exceptions

I have a requirement of compose the log message through the path taken by a code in a user click. Let me give an example:
Imagine the classical example: A user clicks in a button in a View, that calls code from the Business Layer that call code from Data Access Layer, that returns data to the Business, that return to a View.
I want to compose my log message through these layers. The caller method (in a View) that started the whole process will receive the full message. Here are some code sample just to help me explain what i am trying to achieve.
public void ViewMethod()
{
try
{
BussinessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured");
Logger.Print();
}
}
public void BussinessMethod()
{
try
{
DataAcessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured in the bussiness method")
}
}
public void DataAcessMethod()
{
try
{
// some code that executes an SQL command
// Log the SQL Command 1
// Log the SQL Command 2 and do on...
}
catch (Exception ex)
{
Logger.Enqueue("Error occurred, sqls executed are ...", sqlExecuted);
}
}
EDIT: The reason i am needing it is that i need to log all the SQL's executed in the whole process. If an error occurs in any point of the whole process, the user cant be warned, i need to store as much as possible information becouse the support technician will need it later.
My question is if there is any design pattern to develop it or passing a Logger reference across the "layers" are acceptable?
I would do something like this
public class Context
{
[ThreadStatic]
private static LogStore _store;
public static Log(....)
{
.....
}
}
public void ViewMethod()
{
var response = BussinessMethod();
if (response.Status = ResponseStatus.Success)
// do something with response.Data
else
// show message?
}
public BusinessMethodResponse BussinessMethod()
{
var response = new BusinessMethodResponse() {Status = ResponseStatus.Failure};
SomeData data;
try
{
data = DataAcessMethod();
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Data retrieval failed";
return response;
}
try
{
// massage the data here
response.Status = ResponseStatus.Success;
response.Data = myMassagedData;
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Something failed";
}
return response;
}
public void DataAcessMethod()
{
// some code that executes an SQL command
}
What this do? Now you can call your business objects from MVC, WPF, WinForms, Web Forms, etc...

ServiceStack - how to disable default exception logging

In line with the ServiceStack documentation, we have a global service exception handler. The docs say that this handler should log the exception then call DtoUtils.HandleException, like this:
private object LogServiceException(object request, Exception exception)
{
var message = string.Format("Here we make a custom message...");
_logger.Error(message, exception);
return DtoUtils.HandleException(this, request, exception);
}
This results in the error being logged twice, since DTOUtils.HandleException also logs it, in a less customised format. Yes, I much prefer this to the DTOUtils logging and don't want to just use that.
How do we turn off DTOUtils logging while retaining the rest of the functionality? Nobody likes getting twice as many error emails as they should.
I hope the following code solves your problem.
based on the documentation New API, Custom Hooks, ServiceRunner
and Fine grain error handling using the New API's ServiceRunner
in AppHost.Configure
LogManager.LogFactory = new ServiceStack.Logging.Support.Logging.ConsoleLogFactory();
then in AppHost class
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}
in the ServiceRunner class
public class MyServiceRunner<T> : ServiceRunner<T>
{
public override object HandleException(IRequestContext requestContext, T request, Exception ex)
{
if ( isYourCondition )
{
ResponseStatus rs = new ResponseStatus("error1", "your_message");
// optionally you can add custom response errors
rs.Errors = new List<ResponseError>();
rs.Errors.Add(new ResponseError());
rs.Errors[0].ErrorCode = "more details 2";
// create an ErrorResponse with the ResponseStatus as parameter
var errorResponse = DtoUtils.CreateErrorResponse(request, ex, rs);
// log the error
Log.Error("your_message", ex);
return errorResponse;
}
else
return base.HandleException(requestContext, request, ex);
}
}
if you return the base.HandleException, it calls internally the DtoUtils.HandleException.
You will see in console, one log error only.
In client, if you handle the WebServiceException for custom errors.
catch (WebServiceException err)
{
if ( err.ResponseStatus.Errors != null)
{ // do something with err.ResponseStatus.Errors[0].ErrorCode;
}
}
Do not call DtoUtils.HandleException as it logs the error. Don't call ServiceRunner.HandleException either, it calls DtoUtils.HandleException.
Call DtoUtils.CreateErrorResponse to make the response (it is used by DtoUtils.HandleException). The ToResponseStatus helper is also in DtoUtils
My AppServiceRunner is now like this:
public class AppServiceRunner<T> : ServiceRunner<T>
{
public AppServiceRunner(AppHost appHost, ActionContext actionContext)
: base(appHost, actionContext)
{
}
public override object HandleException(IRequestContext requestContext,
T request, Exception ex)
{
LogException(requestContext, request, ex);
var responseStatus = ex.ToResponseStatus();
return DtoUtils.CreateErrorResponse(request, ex, responseStatus);
}
private void LogException(IRequestContext requestContext, T request, Exception ex)
{
// since AppHost.CreateServiceRunner can be called before AppHost.Configure
// don't get the logger in the constructor, only make it when it is needed
var logger = MakeLogger();
var requestType = typeof(T);
var message = string.Format("Exception at URI:'{0}' on service {1} : {2}",
requestContext.AbsoluteUri, requestType.Name, request.ToJson());
logger.Error(message, ex);
}
private static ILog MakeLogger()
{
return LogManager.GetLogger(typeof(AppServiceRunner<T>));
}
}
Now the only service errors that I get are those generated by this code.

Categories

Resources