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
}
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...
}
Related
I have an API method with this signature:
public Task<MResponse> StartAsync(MRequest request)
I can't change that (I can change the implementation inside but not the signature of the method).
This is how I call this method:
var ret = await _SyncClient.StartAsync(Request);
This is the implementation
public Task<MResponse> StartAsync(MRequest request)
{
if (request.Number == 1)
{
return new Task<MResponse>(() => new MResponse() { Description = "Error", Code = 1 });
}
else
{
return new Task<MResponse>(() => new MResponse() { Description = "", Code = 0 });
}
}
On the debug mode I see that my code get into StartAsync and and the return and finish it, but its look like the wait never ends....
I have no idea what it can be.
If you need more information about my code, let me know.
It looks like you're not actually having anything asynchronous to do in the implementation. That's fine, there's always cases where the signature is set (i.e. an interface) and some implementations don't need it.
You can still make the method async and just return the response as if it were as synchronous method, like so:
public async Task<MResponse> StartAsync(MRequest request)
{
return new MResponse() { ... }
}
But that will probably trigger Intellisense to tell you there's nothing being awaited in your method. A better approach is to use Task.FromResult like so:
public Task<MResponse> StartAsync(MRequest request)
{
return Task.FromResult(new MResponse() ... );
}
which will return a Task that already as completed and therefore will not block your await in the follow-up.
You are creating a task by calling the Task Constructor
This creates a Task, but does not start it. You would have to explicitly call Task.Start
public Task<MResponse> StartAsync(MRequest request)
{
var task = (request.Number == 1)
? new Task<MResponse>(() => new MResponse() { Description = "Error", Code = 1 })
: new Task<MResponse>(() => new MResponse() { Description = "", Code = 0 });
task.Start();
}
You have other options here. You can create the object on the current thread and return it as a completed task
return Task.FromResult<MResponse>(new MResponse(...))
Another option is to invoke Task.Run to kick off the work on a background thread.
public Task<MResponse> StartAsync(MRequest request)
{
Func<MResponse> generateResponse = (request.Number == 1)
? () => new MResponse() { Description = "Error", Code = 1 })
: () => new MResponse() { Description = "", Code = 0 });
return Task.Run(generateResponse);
}
Method Under Test
protected override async Task<Name> DoExecuteAsync(NameContext context)
{
context.ThrowIfNull("context");
var request = new Request
{
Id = context.Id,
Principal = context.UserPrincipal,
};
return await this.repository.NameAsync(request, new CancellationToken(), context.ControllerContext.CreateLoggingContext());
}
protected override Name HandleError(NameContext viewContext, Exception exception)
{
if (this.errorSignaller != null)
{
this.errorSignaller.SignalFromCurrentContext(exception);
}
return Name.Unknown;
}
This is implementation of
public abstract class BaseQueryAsync<TInput, TOutput> : IQueryAsync<TInput, TOutput>
{
public async Task<TOutput> ExecuteAsync(TInput context)
{
try
{
return await this.DoExecuteAsync(context);
}
catch (Exception e)
{
return this.HandleError(context, e);
}
}
protected abstract Task<TOutput> DoExecuteAsync(TInput context);
protected virtual TOutput HandleError(TInput viewContext, Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
Test Case goes like below
[SetUp]
public void Setup()
{
var httpContext = MvcMockHelpers.MockHttpContext(isAuthenticated: true);
this.controller = new Mock<Controller>();
this.controller.Object.SetMockControllerContext(httpContext.Object);
this.repoMock = new Mock<IRepository>();
this.errorSignaller = new Mock<IErrorSignaller>();
this.query = new NameQuery(this.repoMock.Object, this.errorSignaller.Object);
this.userPrinciple = new Mock<IPrincipal>();
this.context = new NameContext(this.controller.Object.ControllerContext, this.userPrinciple.Object);
}
[Test]
public async Task TestDoExecuteAsyncWhenRepositoryFails()
{
// Arrange
this.repoMock.Setup(
x => x.NameAsync(
It.IsAny<Request>(),
It.IsAny<CancellationToken>(),
It.IsAny<ILoggingContext>())).Throws<Exception>();
// Act
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
// Assert
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
}
To verify the Name Object ,When I use the var result = await act() before the line
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
The this.errorSignaller.Verify fails since it's count is 2 instead of 1. My intention is to check the Name object along with below code.
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
I knew that if I write a new test case I can easily verify it, but is there any way I can do altogether in this test?
If you want to test the result then use:
Name result = await this.query.ExecuteAsync(this.context);
result.Should().Be(expectefResult);
Make sure to make your test method public async Task
Update
To be able to verify name you would need to set it in the function.
//...code removed for brevity
Name expectedName = Name.Unknown;
Name actualName = null;
// Act
Func<Task> act = async () => {
actualName = await this.query.ExecuteAsync(this.context);
};
// Assert
act.ShouldNotThrow();
actualName
.Should().NotBeNull()
.And.Be(expectedName);
//...rest of code
Original
As already mentioned in the comments, act is a function that returns a Task.
While its implementation is awaited, the function itself still needs to be invoked. And since the function returns a Task it too would need to be awaited.
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
var name = await act();
It is the same as having the following function.
async Task<Name> act() {
return await this.query.ExecuteAsync(this.context);
}
You would have to await it the same way
var name = await act();
The only difference being that the former example has the function in a delegate.
Try to avoid mixing blocking calls like .Result with async/await code. This tends to cause deadlocks.
You can try to check it with
await query.ExecuteAsync(this.context);
or
this.query.ExecuteAsync(this.context).GetAwaiter().GetResult();
and in case of Func:
act.Invoke().GetAwaiter().GetResult();
I'm trying to use Async and Await for upload process. I created a small code to see if it works.
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
TestAsync().Wait();
}
}
public static async Task TestAsync()
{
await Task.Run(() => {
Thread.Sleep(1000);
var context = new CommonEntities();
context.AddToDummies(new Dummy { TimeStamp = DateTime.Now, Caption = "Async" });
context.SaveChanges();
});
}
}
But for some reason, it never gets to Console.WriteLine. If I replaced var context = new EntityObject(); with var stringBuilder = new StringBuilder(); then it worked.
The idea is that I will create a method which has many complex procedures of saving and updating database as well as calling a webservice and store the result to database etc. Let say that method is called MethodA.
public static async void test()
{
await Task.Run(() => MethodA());
}
But before going further, I am stuck in this simple test. Any idea why that is?
You shouldn't be using async void anywhere other than an event handler.
async void doesn't allow the caller to wait (asynchronously or otherwise) for the operation to complete, it just moves on. In your case it reaches the end of Main and the application ends before you get a chance to reach the Console.WriteLine.
You need to change TestAsync to return a Task and wait for it in Main:
static void Main()
{
TestAsync().Wait();
}
public static async Task TestAsync()
{
await Task.Run(() =>
{
var objectContext = new CommonEntities();
Console.WriteLine("Processed");
});
}
I want to use a Task.Run in a static method. But when i m calling the task.run in static method it gets lost.
public static void TestLevel()
{
var UserSetting = Task.Run(async () =>
{
return await database.GetSettingByName("test");
}).Result.Value;
User objuser = new User();
objuser.usersetting = UserSetting;
}
When it is calling the task.run its not coming back.
I suspect you're calling this from a UI or ASP.NET request thread. In that case, it is the Result that is causing a deadlock, as I explain on my blog and in a recent MSDN article.
You should use await instead of Result:
public static async Task TestLevelAsync()
{
var UserSetting = await Task.Run(async () =>
{
return await database.GetSettingByName("test");
});
User objuser = new User();
objuser.usersetting = UserSetting.Value;
}
Also, consider following the Task-based asynchronous pattern. In this case, you would rename GetSettingByName to GetSettingByNameAsync and move any Task.Run usage into that method.
I want to unit test a method that I have that performs and async operation:
Task.Factory.StartNew(() =>
{
// method to test and return value
var result = LongRunningOperation();
});
I stub the necessary methods etc in my unit test (written in c#) but the problem is that the async operation is not finished before I assert the test.
How can I get around this? Should I create a mock of the TaskFactory or any other tips to unit testing an async operation?
You'd have to have some way of faking out the task creation.
If you moved the Task.Factory.StartNew call to some dependency (ILongRunningOperationStarter) then you could create an alternative implementation which used TaskCompletionSource to create tasks which complete exactly where you want them to.
It can get a bit hairy, but it can be done. I blogged about this a while ago - unit testing a method which received tasks to start with, which of course made things easier. It's in the context of async/await in C# 5, but the same principles apply.
If you don't want to fake out the whole of the task creation, you could replace the task factory, and control the timing that way - but I suspect that would be even hairier, to be honest.
I would propose to stub a TaskScheduler in your method with a special implementation for unit tests. You need to prepare your code to use an injected TaskScheduler:
private TaskScheduler taskScheduler;
public void OperationAsync()
{
Task.Factory.StartNew(
LongRunningOperation,
new CancellationToken(),
TaskCreationOptions.None,
taskScheduler);
}
In your unit test you can use the DeterministicTaskScheduler described in this blog post to run the new task on the current thread. Your 'async' operation will be finished before you hit your first assert statement:
[Test]
public void ShouldExecuteLongRunningOperation()
{
// Arrange: Inject task scheduler into class under test.
DeterministicTaskScheduler taskScheduler = new DeterministicTaskScheduler();
MyClass mc = new MyClass(taskScheduler);
// Act: Let async operation create new task
mc.OperationAsync();
// Act: Execute task on the current thread.
taskScheduler.RunTasksUntilIdle();
// Assert
...
}
Try something like this...
object result = null;
Task t = Task.Factory.StartNew(() => result = LongRunningThing());
Task.Factory.ContinueWhenAll(new Task[] { t }, () =>
{
Debug.Assert(result != null);
});
Set UI and background task schedulars and replace them in unit test with this one.
Below code was copied from internet, sorry for missing reference to author:
public class CurrentThreadTaskScheduler : TaskScheduler
{
protected override void QueueTask(Task task)
{
TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(
Task task,
bool taskWasPreviouslyQueued)
{
return TryExecuteTask(task);
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
public override int MaximumConcurrencyLevel => 1;
}
So to test code:
public TaskScheduler TaskScheduler
{
get { return taskScheduler ?? (taskScheduler = TaskScheduler.Current); }
set { taskScheduler = value; }
}
public TaskScheduler TaskSchedulerUI
{
get { return taskSchedulerUI ?? (taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext()); }
set { taskSchedulerUI = value; }
}
public Task Update()
{
IsBusy = true;
return Task.Factory.StartNew( () =>
{
LongRunningTask( );
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler )
.ContinueWith( t => IsBusy = false, TaskSchedulerUI );
}
You will write following unit test:
[Test]
public void WhenUpdateThenAttributeManagerUpdateShouldBeCalled()
{
taskScheduler = new CurrentThreadTaskScheduler();
viewModel.TaskScheduler = taskScheduler;
viewModel.TaskSchedulerUI = taskScheduler;
viewModel.Update();
dataManagerMock.Verify( s => s.UpdateData( It.IsAny<DataItem>>() ) );
}