This is workaround I came up with when faced the same problem. Solution is more related to ASP.NET than ABP.
First, I in my base exception I created field for error code.
Something like this :
public class BaseException : Exception
{
public int ErrorCode { get; private set; }
public BaseException() : this(500)
{
}
public BaseException(int errorCode)
{
ErrorCode = errorCode;
}
public BaseException(int errorCode, string message) : base(message)
{
ErrorCode = errorCode;
}
}
Then I introduced following modified exception filter that would recognize my BaseException
exceptions and read the error code :
namespace Abp.WebApi.ExceptionHandling
{
/// <summary>
/// Used to handle exceptions on web api controllers.
/// </summary>
public class CustomApiExceptionFilter : ExceptionFilterAttribute, ITransientDependency
{
/// <summary>
/// Reference to the <see cref="ILogger"/>.
/// </summary>
public ILogger Logger { get; set; }
/// <summary>
/// Reference to the <see cref="IEventBus"/>.
/// </summary>
public IEventBus EventBus { get; set; }
public IAbpSession AbpSession { get; set; }
private readonly IAbpWebApiModuleConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="AbpApiExceptionFilterAttribute"/> class.
/// </summary>
public CustomApiExceptionFilter(IAbpWebApiModuleConfiguration configuration)
{
_configuration = configuration;
Logger = NullLogger.Instance;
EventBus = NullEventBus.Instance;
AbpSession = NullAbpSession.Instance;
}
/// <summary>
/// Raises the exception event.
/// </summary>
/// <param name="context">The context for the action.</param>
public override void OnException(HttpActionExecutedContext context)
{
var wrapResultAttribute = (context.ActionContext.ActionDescriptor)
.GetWrapResultAttributeOrNull();
// ?? _configuration.DefaultWrapResultAttribute;
if (wrapResultAttribute == null || wrapResultAttribute.LogError)
{
LogHelper.LogException(Logger, context.Exception);
}
if (wrapResultAttribute == null || wrapResultAttribute.WrapOnError)
{
context.Response = context.Request.CreateResponse(
GetStatusCode(context),
new AjaxResponse(
SingletonDependency<ErrorInfoBuilder>.Instance.BuildForException(context.Exception),
context.Exception is Abp.Authorization.AbpAuthorizationException)
);
EventBus.Trigger(this, new AbpHandledExceptionData(context.Exception));
}
}
private HttpStatusCode GetStatusCode(HttpActionExecutedContext context)
{
if (context.Exception is Abp.Authorization.AbpAuthorizationException)
{
return AbpSession.UserId.HasValue
? HttpStatusCode.Forbidden
: HttpStatusCode.Unauthorized;
}
var customException = (context.Exception as BaseException);
if (customException != null)
return
(HttpStatusCode)customException.ErrorCode;
return
HttpStatusCode.InternalServerError;
}
}
}
Finally, replaced ABP auto-registered filter with my implementation in WebApiModule initialization.
public MyWebApiModule : AbpModule
{
public override void Initialize()
{
// ...
var filters = Configuration.Modules.AbpWebApi().HttpConfiguration.Filters;
var exceptionFilter = filters.First(h => h.Instance is AbpExceptionFilterAttribute).Instance;
filters.Remove(exceptionFilter);
filters.Add(IocManager.Resolve<CustomApiExceptionFilter>());
}
}
Now through my custom exceptions and filter I was able to control response status codes.