Handling WCF web config errors with MVC? - asp.net-mvc-3

I was about to use the following Application_Error() handling in my Global.asax:
protected void Application_Error()
{
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
string action;
switch (httpException.GetHttpCode())
{
case 404:
// page not found
action = "HttpError404";
break;
case 500:
// server error
action = "HttpError500";
break;
default:
action = "General";
break;
}
// clear error on server
Server.ClearError();
Response.Redirect(String.Format("~/Error/{0}/?message={1}", action, exception.Message));
}
}
However, the issue was that I couldn't trap this error:
The maximum message size quota for incoming messages (100000) has been
exceeded. To increase the quota, use the MaxReceivedMessageSize
property on the appropriate binding element.
When I had the web.config value set to low, as when it got to the Response.Clear(); call, I get an HTTP exception:
Response is not available in this context.
How can I get around this to handle all exceptions?
Thanks.

Related

How to properly handle Exceptions in client thrown by a SOAP web service

I am setting up a Client using Spring-boot in Java to access a soap endpoint (for testing purpose).What's the best approach to handle Exceptions? I want to handle SOAPFaultClientExceptions...
I have already tried this:
How to Parse SoapFaultClientException in spring-ws
but it didn't work properly, as I couldn't call the getValue() method on detail
try {
JAXBElement res = (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(url, request);
return (GetBankResponseType) res.getValue();
}catch (SoapFaultClientException ex) {
SoapFaultDetail soapFaultDetail = ex.getSoapFault().getFaultDetail(); // <soapFaultDetail> node
// if there is no fault soapFaultDetail ...
if (soapFaultDetail == null) {
throw ex;
}
SoapFaultDetailElement detailElementChild = soapFaultDetail.getDetailEntries().next();
Source detailSource = detailElementChild.getSource();
Object detail = getWebServiceTemplate().getUnmarshaller().unmarshal(detailSource);
JAXBElement source = (JAXBElement) detail;
System.out.println("Text::"+source.getValue());
}//catch other Exceptions...Which ones?
return null;
}
Expected result is a handled Exception, (SOAPFaultClientException) or others... which get Thrown by the webservice when wrong parameters are passed. I don't find any suitable solutions.
Configure ClientInterceptor or FaultMessageResolver to your WebServiceTemplate and do your error handling there.

Display server side Exception Message on DataTables.NET

I am developing a MVC application which has handles authorization and login information at a base controller class overriding OnActionExecuting event.
At AJAX calls when an exception arises I can handle this via attributes and display error messages with on custom model window.
My custom attribute is as follows :
public class JsonExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
string msg = HttpUtility.HtmlDecode(filterContext.Exception.Message);
if (filterContext.Exception.GetType() == Type.GetType("System.UnauthorizedAccessException"))
{
msg = "Unauthorized access";
}
filterContext.Result = new JsonResult
{
Data = new
{
errorMessage = msg
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
But when an Exception occurs while using DataTables.Net the only mesage I get is the DataTables.NET's own error mesaages saying "... please see http://datatables.net/tn/7"
But I want to display my own Exception message as I do in other AJAX calls. Basically I want to display the error message I provide in my custom attribute response.
I have Googled it, advising to use "fnServerData" but I can not find my Exception message in any of the parameters (sSource, aoData, fnCallback, oSettings) I get by this event handler.
How can I possibly get the Exception message that my base controller returns and display it?
Regards.
P.S. : Handling the Exception in the Action and returning it does not apply here, because I do not fall to Action method at all.

Spring WS client handling HTML instead of SOAP Fault

I have a SOAP client that is calling many different web services. In some cases some send back HTML error pages with HTTP error status codes instead of SOAP faults. I know that they should be sending SOAP faults, but I want to be able to handle this scenario. I'd like to be able to get access to the HTML error page. Right now when I get back an HTML error page with a 200 status code, a SoapMessageCreationException is thrown, which I catch. HTML error pages with HTTP error status codes throw WebServiceTransportException. How can I access the HTML data in the response at that point? I am using org.springframework.ws.transport.http.CommonsHttpMessageSender (Jakarta Commons HttpClient) as the message sender, with Spring 2.0.
I would like the code to be able to work with the default message sender if possible, otherwise, I would just check whether the instance of the message sender is CommonsHttpMessageSender or not. I prefer not to have to upgrade to Spring-WS 3/Apache HttpComponents right now, but am open to it if necessary. If I call this.webserviceTemplate.getMessageSenders(), is it ok to always take the first one ([0])?
try {
this.webserviceTemplate.sendSourceAndReceiveToResult(source,
new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message)
throws IOException, TransformerException {
if (LOG.isDebugEnabled()) {
// log the SOAP request
ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
LOG.debug("SOAP Request Payload: " + new String(out.toByteArray()));
}
if (soapActionHttpHeader != null) {
((SoapMessage)message).setSoapAction(soapActionHttpHeader);
LOG.debug("Setting SOAP Action HTTP header to: " + soapActionHttpHeader);
}
else
LOG.debug("SOAP Action HTTP not set in the configuration.");
}
}, result);
}
catch (SoapMessageCreationException e)
{//org.springframework.ws.transport.http.CommonsHttpMessageSender
String errorMsg= "Error processing SOAP message";
LOG.info(errorMsg);
LOG.debug("Stack trace: ",e);
throw new ServiceInvocationException(errorMsg);
}
catch (WebServiceTransportException e) {
String errorMsg= "Error invoking SOAP service";
LOG.info(errorMsg);
LOG.debug("Stack trace: ",e);
throw e;
}
catch (WebServiceIOException e) {
throw new ServiceInvocationException(e);
}

Elmah doesn't log exceptions using WebAPI with HttpResponseException

In my WebApi code, I raise a HttpResponseException which short-circuits the request pipeline and generates a valid Http response. However, I'm trying to integrate webApi with elmah logging, yet the HttpResponseExeptions aren't showing up.
I have the web.config set-up for elmah and have the following code:
In Global.asx.cs:
static void ConfigureWebApi(HttpConfiguration config)
{
config.Filters.Add(new ServiceLayerExceptionFilter());
config.Filters.Add(new ElmahHandledErrorLoggerFilter());
config.DependencyResolver = new WebApiDependencyResolver(ObjectFactory.Container);
}
Filter:
public class ElmahHandledErrorLoggerFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
base.OnException(actionExecutedContext);
ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);
}
}
Code where exception is raised:
public Task<FileUpModel> UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
var provider = new TolMobileFormDataStreamProvider("C:\images\");
var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
t =>
{
if (t.IsFaulted || t.IsCanceled)
throw new HttpResponseException(HttpStatusCode.InternalServerError);
var fileInfo = provider.FileData.FirstOrDefault();
if (fileInfo == null)
// the exception here isn't logged by Elmah?!
throw new HttpResponseException(HttpStatusCode.InternalServerError);
var uploadModel = new FileUpModel { success = true };
return uploadModel;
});
return task;
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
}
}
Can anyone who has implemented this before let me know what I'm doing wrong?
As mentioned above, the Elmah filter does not catch and log anything when you raise a HttpResponseException. More specifically, if the following syntax is used:
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "It was a bad request");
or
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "HttpResponseException - This request is not properly formatted"));
I wanted to trap and log an error in both cases. The way to do it is to use an "ActionFilterAttribute", override "OnActionExecuted", and check actionExecutedContext.Response.IsSuccessStatusCode.
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// when actionExecutedContext.Response is null, the error will be caught and logged by the Elmah filter
if ((actionExecutedContext.Response != null) && !actionExecutedContext.Response.IsSuccessStatusCode)
{
try
{
var messages = (System.Web.Http.HttpError)((System.Net.Http.ObjectContent<System.Web.Http.HttpError>)actionExecutedContext.Response.Content).Value;
StringBuilder stringBuilder = new StringBuilder();
foreach (var keyValuePair in messages) {
stringBuilder.AppendLine("Message: Key - " + keyValuePair.Key + ", Value - " + keyValuePair.Value);
}
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Web API Failed Status Code returned - " + stringBuilder.ToString()));
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Error in OnActionExecuted - " + ex.ToString()));
}
}
}
On a side note, I also overwrote "OnActionExecuting" to validate the model state. This allowed me to remove all of the checks within my actions.
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.ModelState != null && !actionContext.ModelState.IsValid)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var obj in actionContext.ModelState.Values)
{
foreach (var error in obj.Errors)
{
if(!string.IsNullOrEmpty(error.ErrorMessage)) {
stringBuilder.AppendLine("Error: " + error.ErrorMessage);
}
}
}
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Invalid Model State -- " + stringBuilder.ToString()));
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
Of course, you will need to add the filter using "config.Filters.Add".
Web API special cases HttpResponseException thrown in action and converts into HttpResponseMessage and hence you are not seeing your exception filter getting invoked.
This is not true in the case of throwing HttpResponseException from filters. However, ideally one need not throw HttpResponseException from filters as you could short-circuit a request by setting the Response property on the supplied input context.
You need to turn on Elmah for HttpFilters in order to get this to work as you expect for WebApi.
Use Elmah.Contrib.WebApi available as a NuGet Package, it will wire include a class that you can then wire up following the instructions on the Elmah.Contrib.WebApi project site.
If you want to do this yourself, Capturing Unhandled Exceptions in ASP.NET Web API's with ELMAH walks you through what the Elmah.Contrib.WebApi is doing for you.
Additionally, I had to change the way that the error response is thrown for it to be picked by Elmah to:
throw new HttpException((int)HttpStatusCode.NotAcceptable, "This request is not properly formatted");
I would also recommend the use of the Elmah.MVC NuGet Package.

MVC Generic error view and Ajax Post and error code 500

I have set up an mvc app with an _error.cshtml that is set to catch exceptions I throw in the controller.
I also have a few ajax posts on some pages that checks for errors and then it does something else.
On the server, I have a filter on all exceptions and then check if it is an ajax request and return something that can be deserialized on the client. The problem is that if I do not set the post response status code to 500 then ajax will not see this error and I can't show a nice message. If I set the status to 500 I get the default IIS error message stating something happened on the server.
I would like to handle some errors on the page in the ajax results but maintain the generic error handling. Is this an IIS setting to allow custom 500 message per site? The web.config Custom Error On|Off makes no difference in my case.
The filter you have on all exceptions that is checking if its an ajax request, is that a filter made on your own?
I had a slightly similar issue, and I had to make sure the flag TrySkipIisCustomErrors was set as true in order to avoid the standard IIS error.
This flag is located on the Response object of the HttpContext.
This is also done by the standard HandleError filter, pay attention to the last line in its implementation of the OnException method:
public virtual void OnException(ExceptionContext filterContext) {
if (filterContext == null) {
throw new ArgumentNullException("filterContext");
}
if (filterContext.IsChildAction) {
return;
}
// If custom errors are disabled, we need to let the normal ASP.NET exception handler
// execute so that the user can see useful debugging information.
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
return;
}
Exception exception = filterContext.Exception;
// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
// ignore it.
if (new HttpException(null, exception).GetHttpCode() != 500) {
return;
}
if (!ExceptionType.IsInstanceOfType(exception)) {
return;
}
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
filterContext.Result = new ViewResult {
ViewName = View,
MasterName = Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
// Certain versions of IIS will sometimes use their own error page when
// they detect a server error. Setting this property indicates that we
// want it to try to render ASP.NET MVC's error page instead.
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}

Resources