0

How I can implement timeout for a block of code in asp.net application without using Task or Thread? I don't want create new threads because HttpContext will be NULL in another threads.

For example, following code will not work

var task = Task.Run(() =>
{
    var test = MethodWithContext();
});
if (!task.Wait(TimeSpan.FromSeconds(5)))
    throw new Exception("Timeout");

object MethodWithContext()
{
    return HttpContext.Current.Items["Test"]; // <--- HttpContext is NULL
}

EDIT:

I don't want pass current context to method, because I will have a lot of nested methods inside method... so a lot of refactor must be done for this solution

EDIT2:

I have realized that I can assign current context to variable before creating new task and replace HttpContext in task with this variable. This will be safe?

    var ctx = HttpContext.Current;

    var task = Task.Run(() =>
    {
        HttpContext.Current = ctx;
        var test = MethodWithContext();
    });
    if (!task.Wait(TimeSpan.FromSeconds(5)))
        throw new Exception("Timeout");

    object MethodWithContext()
    {
        return HttpContext.Current.Items["Test"]; // now works correctly
    }
mkul
  • 773
  • 1
  • 10
  • 28
  • Why do you not want to create a Task for this? – user9993 Jun 01 '17 at 09:06
  • Why do you need HttpContext in worker threads? Just pass all needed info and they wont need any other "context" – Szer Jun 01 '17 at 09:07
  • @Szer yes, this example is very simple, but in situation when many nested methods uses HttpContext, it may be difficult to refactor the code – mkul Jun 01 '17 at 09:15
  • 1
    Would [that](https://stackoverflow.com/q/8925227/728795) help? – Andrei Jun 01 '17 at 10:04
  • @Andrei It looks like my code from #EDIT2 section. Looks like it works with this, thanks – mkul Jun 01 '17 at 10:10

1 Answers1

2

You will need to pass the context of you main thread like this:

var task = Task.Run(() =>
{
    // Takes the context of you current thread an passes it to the other thread.
    var test = MethodWithContext(HttpContext.Current);
});

if (!task.Wait(TimeSpan.FromSeconds(5)))
    throw new Exception("Timeout");

void object MethodWithContext(HttpContext ctx)
{
    // Now we are operating on the context of you main thread.
    return ctx.Items["Test"];
}

But the question is still:
Why do you want to create a task for this?
After starting the task you are simply waiting for its completion. You could just call your method synchronously. Although I am not sure how to limit the execution to 5 seconds if you do that.


As you have mentioned in the comments you'd like to get rid of the additional parameter because you have more than one method. This is how I'd do it:

public void YourOriginalMethod()
{
   YourUtilityClass util = new YourUtilityClass(HttpContext.Current);

   var task = Task.Run(() =>
   {
       var test = util.MethodWithContext();
   });

   if (!task.Wait(TimeSpan.FromSeconds(5)))
       throw new Exception("Timeout");
 }



public class YourUtilityClass
{
    private readonly HttpContext _ctx;

    public YourUtilityClass(HttpContext ctx)
    {
       if(ctx == null)
          throw new ArgumentNullException(nameof(ctx));

       _ctx = ctx;
    }



    public void object MethodWithContext()
    {
       return _ctx.Items["Test"];
    }


    // You can add more methods here...
}
Noel Widmer
  • 4,444
  • 9
  • 45
  • 69
  • Can I avoid passing context to method? I mean situation when I have many methods in block and another methods nested in these methods – mkul Jun 01 '17 at 09:10
  • @mkul Updated my answer based on your comment. – Noel Widmer Jun 01 '17 at 09:20
  • Or maybe just assign context to variable before execute `Task.Run()`, and inside `Task.Run` replace current context? It will safe? `var ctx = HttpContext.Current; var task = Task.Run(() => { HttpContext.Current = ctx; var test = MethodWithContext() }` – mkul Jun 01 '17 at 09:54
  • @mkul Sure, but that's a detail. You asked to solve the problem that your program doesn't work. – Noel Widmer Jun 01 '17 at 10:05