Using ASP.NET WebApi 2,
Why can't I catch HttpRequestValidationException in my Global ExceptionHandler or Global ExceptionLogger?
Error is: [HttpRequestValidationException (0x80004005): A potentially dangerous Request.QueryString value was detected from the client...]
Using Application_Error works fine, HttpRequestValidationException can be caught fine.
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
//...stuffs
//Global exception handler
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
//add global error logger
config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());
}
public class GlobalExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
//This does not handle HttpRequestValidationException
Exception exception = context.ExceptionContext.Exception;
//.....
}
}
public class GlobalExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
//This does not handle HttpRequestValidationException either ...
var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An unexpected error occured. Please notify your administrator"),
ReasonPhrase = "Unexpected Error"
};
context.Result = new UnhandledExceptionResult(context.Request, result);
}
public class UnhandledExceptionResult : IHttpActionResult
{
private HttpRequestMessage _request;
private HttpResponseMessage _httpResponseMessage;
public UnhandledExceptionResult(HttpRequestMessage request, HttpResponseMessage httpResponseMessage)
{
_request = request;
_httpResponseMessage = httpResponseMessage;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_httpResponseMessage);
}
}
}
Related
Headers are published with Azure Service Bus, like below:
string content = "body";
await _busPublisher.Activator.Bus.Publish(content, headers);
How to retrieve both header and content on subscriber?
class Handler : IHandleMessages<string>
{
public Handler(IMessageContext messageContext, ILog log)
{
_messageContext = messageContext;
_log = log;
}
public async Task Handle(string message)
{
Console.WriteLine("Handle(string message): {0}", message);
}
}
Update
Below is one solution. Is this the best solution?
public Handler(IMessageContext messageContext, ILog log)
{
_messageContext = messageContext;
_log = log;
}
public async Task Handle(string message)
{
Console.WriteLine("Handle(string message): {0} ", message);
Console.WriteLine("headers: {0} ", string.Join(' ', _messageContext.Headers));
}
When a Handler is instantiated like below, is it possible to use dependency injection instead?
var Activator = new BuiltinHandlerActivator();
Activator.Register((mc) =>
{
return new Handler(mc, log); //no new?
}
Accepted IMessageContext injected into the constructor of your handler is the way to go:
public class Handler : IHandleMessages<string>
{
readonly IMessageContext messageContext;
public Handler(IMessageContext messageContext, ILog log)
{
this.messageContext = messageContext;
}
public async Task Handle(string message)
{
var headers = messageContext.Headers;
// do stuff
}
}
If you're using BuiltinHandlerActivator, you can have it injected like this:
activator.Register(context => new Handler(context));
or if you also need the IBus in your handler:
activator.Register((bus, context) => new Handler(bus, context));
i'm currently have a look a springboot undertow and it's not really clear (for me) how to dispatch an incoming http request to a worker thread for blocking operation handling.
Looking at the class UndertowEmbeddedServletContainer.class, it look like there is no way to have this behaviour since the only HttpHandler is a ServletHandler, that allow #Controller configurations
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
this.builder.setHandler(getContextHandler(servletHandler));
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
private HttpHandler getContextHandler(HttpHandler servletHandler) {
if (StringUtils.isEmpty(this.contextPath)) {
return servletHandler;
}
return Handlers.path().addPrefixPath(this.contextPath, servletHandler);
}
By default, in undertow all requests are handled by IO-Thread for non blocking operations.
Does this mean that every #Controller executions will be processed by a non blocking thread ? or is there a solution to chose from IO-THREAD or WORKER-THREAD ?
I try to write a workaround, but this code is pretty uggly, and maybe someone has a better solution:
BlockingHandler.class
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface BlockingHandler {
String contextPath() default "/";
}
UndertowInitializer.class
public class UndertowInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
configurableApplicationContext.addBeanFactoryPostProcessor(new UndertowHandlerPostProcessor());
}
}
UndertowHandlerPostProcessor.class
public class UndertowHandlerPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(BlockingHandler.class));
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("org.me.lah")){
try{
Class clazz = Class.forName(beanDefinition.getBeanClassName());
beanDefinitionRegistry.registerBeanDefinition(clazz.getSimpleName(), beanDefinition);
} catch (ClassNotFoundException e) {
throw new BeanCreationException(format("Unable to create bean %s", beanDefinition.getBeanClassName()), e);
}
}
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//no need to post process defined bean
}
}
override UndertowEmbeddedServletContainerFactory.class
public class UndertowEmbeddedServletContainerFactory extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware, ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {
DeploymentManager manager = createDeploymentManager(initializers);
int port = getPort();
if (port == 0) {
port = SocketUtils.findAvailableTcpPort(40000);
}
Undertow.Builder builder = createBuilder(port);
Map<String, Object> handlers = applicationContext.getBeansWithAnnotation(BlockingHandler.class);
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
port, port >= 0, handlers);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
...
override UndertowEmbeddedServletContainer.class
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager,
String contextPath, int port, boolean autoStart, Map<String, Object> handlers) {
this.builder = builder;
this.manager = manager;
this.contextPath = contextPath;
this.port = port;
this.autoStart = autoStart;
this.handlers = handlers;
}
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
String path = this.contextPath.isEmpty() ? "/" : this.contextPath;
PathHandler pathHandler = Handlers.path().addPrefixPath(path, servletHandler);
for(Entry<String, Object> entry : handlers.entrySet()){
Annotation annotation = entry.getValue().getClass().getDeclaredAnnotation(BlockingHandler.class);
System.out.println(((BlockingHandler) annotation).contextPath());
pathHandler.addPrefixPath(((BlockingHandler) annotation).contextPath(), (HttpHandler) entry.getValue());
}
this.builder.setHandler(pathHandler);
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
set initializer to the application context
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).initializers(new UndertowInitializer()).run(args);
}
finaly create a HttpHandler that dispatch to worker thread
#BlockingHandler(contextPath = "/blocking/test")
public class DatabaseHandler implements HttpHandler {
#Autowired
private EchoService echoService;
#Override
public void handleRequest(HttpServerExchange httpServerExchange) throws Exception {
if(httpServerExchange.isInIoThread()){
httpServerExchange.dispatch();
}
echoService.getMessage("my message");
}
}
As you can see, my "solution" is really heavy, and i would really appreciate any help to simplify it a lot.
Thank you
You don't need to do anything.
Spring Boot's default Undertow configuration uses Undertow's ServletInitialHandler in front of Spring MVC's DispatcherServlet. This handler performs the exchange.isInIoThread() check and calls dispatch() if necessary.
If you place a breakpoint in your #Controller, you'll see that it's called on a thread named XNIO-1 task-n which is a worker thread (the IO threads are named XNIO-1 I/O-n).
I use the code below to throttle my ASP.NET Web Api:
public class Throttle : ActionFilterAttribute
{
public override async Task OnActionExecutingAsync(HttpActionContext context, CancellationToken cancellationToken)
{
// ...
if (throttle)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Conflict));
}
}
}
However, I cannot return error code 429, because it's not in HttpStatusCode enum. Is there a way to return a custom error code?
I found this over here.
var response = new HttpResponseMessage
{
StatusCode = (HttpStatusCode)429,
ReasonPhrase = "Too Many Requests",
Content = new StringContent(string.Format(CultureInfo.InvariantCulture, "Rate limit reached. Reset in {0} seconds.", data.ResetSeconds))
};
response.Headers.Add("Retry-After", data.ResetSeconds.ToString(CultureInfo.InvariantCulture));
actionContext.Response = response;
Hope this helps
This is what I did based on another response on StackOverflow.
Create Class (in controller file worked for me)
public class TooManyRequests : IHttpActionResult
{
public TooManyRequests()
{
}
public TooManyRequests(string message)
{
Message = message;
}
public string Message { get; private set; }
public HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage((HttpStatusCode)429);
if (!string.IsNullOrEmpty(Message))
{
response.Content = new StringContent(Message); // Put the message in the response body (text/plain content).
}
return response;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
}
Use in controller
public IHttpActionResult Get()
{
// with message
return new TooManyRequests("Limited to 5 request per day. Come back tomorrow.");
// without message
// return new TooManyRequests();
}
I have intereception working with the Ninject Interceptions Extentions and Dynamic Proxy v3.0. I'm trying to class proxy intercept an MVC 3 contoller. The controller is intercepted but the behavior is incorrect. The intereceptor only intercepts calls to public virtual methods on the classes ControllerBase and Controller. My HomeController public virtual methods are never intercepted. Here's my code. I'm thinking of using MVC's Filters to accomplish this instead of Ninject Interception.
public class AuditAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<AuditInterceptor>();
}
}
[Audit] //HomeController method not intercepted.
public virtual ActionResult Index()
{
return View();
}
public class AuditInterceptor : SimpleInterceptor
{
public AuditInterceptor(IAuditor auditor)
{
if (auditor == null)
throw new ArgumentNullException("auditor");
this.auditor = auditor;
}
protected override void OnError(IInvocation invocation, Exception exception)
{
stopWatch.Stop();
AuditEvent auditEvent = new AuditEvent();
auditEvent.ExceptionDescription = exception.Message;
auditEvent.FormName = string.Format("class: {0}, method: {1}", invocation.Request.Method.DeclaringType, invocation.Request.Method.Name);
auditEvent.AppName = appName;
this.auditor.WriteAudit(auditEvent);
auditEvent.LengthOfMethodCall = stopWatch.Elapsed;
base.OnError(invocation, exception);
}
protected override void AfterInvoke(IInvocation invocation)
{
stopWatch.Stop();
AuditEvent auditEvent = new AuditEvent();
auditEvent.ExceptionDescription = defaultExp;
auditEvent.FormName = string.Format("class: {0}, method: {1}", invocation.Request.Method.DeclaringType, invocation.Request.Method.Name);
auditEvent.AppName = appName;
auditEvent.LengthOfMethodCall = stopWatch.Elapsed;
this.auditor.WriteAudit(auditEvent);
}
protected override void BeforeInvoke(IInvocation invocation)
{
stopWatch.Start();
}
}
I want to write some message to response if exceptions occur in controller ,To do this I need response object .Can I access current response/request object staticly or I have to pass this object to exception too.like in jsf (FacesContext.getCurrentInstance().getExternalContext().getResponse());
List<View_Probes> getAllProbes(HttpServletResponse response) throws ResourceNotFoundException{
try {
List<Probe> probes= inseptraPersistenceService.listAllProbes();
List<View_Probes> result= mapper.mapAll(probes, View_Probes.class);
return result;
} catch (Exception e) {
throw new ResourceNotFoundException(e);
}
}
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException() {
}
public ResourceNotFoundException(Throwable e) {
super(e);
}
}