I want to add some request timings to the response headers of a request to a Nancy module. I've added some before/after request handlers into the RequestStartup and added the headers no problem (example below) and all was good. I've also added an OnError handler to the ApplicationStartup, to catch errors and return a nice formatted Json response.
pipelines.BeforeRequest += ctx =>
{
ctx.Items.Add("X-RequestStart", DateTime.Now.ToString());
return null;
};
pipelines.AfterRequest += ctx =>
{
var now = DateTime.Now;
try
{
//Not got around to forcing the culture on the datetime parsing yet...
var startTime = DateTime.Parse(ctx.Items["X-RequestStart"].ToString());
ctx.Response.Headers.Add("X-RequestStart", startTime.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestDuration", (now - startTime).ToString());
}
catch (Exception)
{
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
}
};
pipelines.OnError += (ctx, exception) =>
{
return ErrorResponse.FromException(exception);
};
What I am noticing however, is that when I have an error thrown, the AfterRequest action is not performed - thus I have no timing headers in to the error response. I've tried moving the before/after request handling to the application startup, but this has no effect either.
The question is in two parts really, firstly, is it possible to get the framework to perform an AfterRequest action after the OnError action has been performed, or is the pipeline set up in a way to prevent this, and secondly, should these before/after request actions be part of the RequestStartup or ApplicationStartup? ApplicationStartup seemed sensible for error handling, whereas RequestStartup seemed sensible for interacting with the response headers as it should be on a per request basis, but I'm not sure if there is a convention for this, or if my assumptions were incorrect.
Unfortunately, this does not seem possible in NancyFx. I took a detailed look at the source code, specifically DefaultRequestDispatcher. Dispatch catches any exceptions thrown during route processing, calls ResolveErrorResult, then gets the response from the negotiator. There does not appear to be an extensibility point to modify responses generated in this way.
In my opinion, this is an oversight that the developers should consider addressing.
public async Task<Response> Dispatch(NancyContext context, CancellationToken cancellationToken)
{
// TODO - May need to make this run off context rather than response .. seems a bit icky currently
var resolveResult = this.Resolve(context);
context.Parameters = resolveResult.Parameters;
context.ResolvedRoute = resolveResult.Route;
try
{
context.Response = await ExecuteRoutePreReq(context, cancellationToken, resolveResult.Before)
.ConfigureAwait(false);
if(context.Response == null)
{
context.Response = await this.routeInvoker.Invoke(resolveResult.Route, cancellationToken,
resolveResult.Parameters, context)
.ConfigureAwait(false);
if (context.Request.Method.Equals("HEAD", StringComparison.OrdinalIgnoreCase))
{
context.Response = new HeadResponse(context.Response);
}
}
await this.ExecutePost(context, cancellationToken, resolveResult.After, resolveResult.OnError)
.ConfigureAwait(false);
}
catch(Exception ex)
{
context.Response = this.ResolveErrorResult(context, resolveResult.OnError, ex);
if (context.Response == null)
{
throw;
}
}
return context.Response;
}
private Response ResolveErrorResult(NancyContext context, Func<NancyContext, Exception, dynamic> resolveResultOnError, Exception exception)
{
if (resolveResultOnError != null)
{
var flattenedException = exception.FlattenInnerExceptions();
var result = resolveResultOnError.Invoke(context, flattenedException);
if (result != null)
{
return this.negotiator.NegotiateResponse(result, context);
}
}
return null;
}
Related
I have this code, hoping to catch all exception during this async method. Somehow, an url exception happened but it was not caught by the catch clause. I have to add a try-catch block around it to catch that exception, don't know why, can someone explain?
public async transform(
): Promise {
const {result} = this.processUrl(url).catch(error => error);
return result;
}
private processUrl(url: string): Promise {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
}
I was hoping tranform function will never throw exception, but when I provide an invalid url, processUrl method throws out an exception which somehow didn't get caught in the transform function.
I have to do this to catch it.
public async transform(
): Promise {
try {
const {result} = this.processUrl(url).catch(error => error);
} catch(e) {
// invalid url exception got caught
return Promise.resolve(undefined);
}
return result;
}
processURL() is not an async function. Thus, it does not automatically return a promise and does not automatically catch exceptions and turn them into a rejected promise.
So, if an exception is thrown anywhere in processURL(), that exception just propagates upwards as a synchronous exception. If you want to catch that synchronous exception yourself, you will need a try/catch in order to catch it.
Or, you could make processURL() an async function and then it will automatically catch any synchronous exceptions and turned them into a rejected promise that you could then catch with .catch() like this:
private async processUrl(url: string): Promise {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
}
Or you could catch it manually:
private processUrl(url: string): Promise {
try {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
} catch(e) {
return Promise.reject(e);
}
}
You may also have an issue here:
const {result} = this.processUrl(url).catch(error => error);
Because your processUrl() function is set up to return a promise. You need to use .then() or await to get the value out of that promise. FYI, if processUrl() is actually entirely synchronous, then it is just complicating matters to make it return a promise when it could just return a value directly.
I want to use CancellationToken in my GUI but it doesn't work.
When I click on the cancel button I want to cancel the operation
this.tokenSource.Cancel();
In other place I have other button that need to do main operation. The main part includes Task and CancellationToken token and this part doesn works
private CancellationTokenSource tokenSource;
private async void DataSynchronization(object notInUse)
{
this.tokenSource = new CancellationTokenSource();
CancellationToken ct = new CancellationToken();
ct.ThrowIfCancellationRequested();
await Task.Run(() =>
{
try
{
// do main operation
}
catch (Exception e)
{
}
finally
{
// final operation
}
if (ct.IsCancellationRequested)
{
ct.ThrowIfCancellationRequested();
}
}, this.tokenSource.Token)
.ContinueWith(
completedTaskResult =>
{
// I want to check if cancel was presed
}
);
}
This is main structure but something wrong. I don't receive cancel operation
There are several problems here. First you shouldn't create your own CancellationToken, that's what CancellationTokenSource is for! It's the source for your token. Second, you should use the Run overload that takes a CancellationToken as the second argument, and third, you need to check the CancellationToken.IsCancellationRequested property in your do main operation to see if it's been cancelled and stop doing what you are doing if it is.
See here for a good example.
So you code might end up looking something like:
this.tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
await Task.Run(() =>
{
while(notDone && !token.IsCancellationRequested)
{
// do some stuff
}
}, token);
Now when you do:
this.tokenSource.Cancel();
It will signal to the associated Token that the operation is cancelled and somewhere inside your task you'll pick that up and stop doing that thing.
All, I call a .NET DLL containing a WinForm at run-time from a WinForm C# application. To do this I use the following:
DLL = Assembly.LoadFrom(strDllPath);
classType = DLL.GetType(String.Format("{0}.{1}", strNamespaceName, strClassName));
if (classType != null)
{
if (bDllIsWinForm)
{
classInst = Activator.CreateInstance(classType);
Form dllWinForm = (Form)classInst;
dllWinForm.Show();
// Invoke required method.
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInst, new object[] { dllParams });
return result == null ? String.Empty : result.ToString();
}
}
}
This is invoking the WinForm DLL and the required method fine for serial methods within the DLL. However, I am now invoking a multi-threaded DLL, and calling the following method:
public async void ExecuteTest(object[] args)
{
Result result = new Result();
if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
return;
IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
List<Enum> enumList = new List<Enum>()
{
Method.TestSqlConnection,
Method.ImportReferenceTables
};
Task task = Task.Factory.StartNew(() =>
{
foreach (Method method in enumList)
{
result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
Process.ProcessStrategyFactory.GetProcessType(method));
if (!result.Succeeded)
{
// Display error.
return;
}
}
});
await task;
Utilities.InfoMsg("VCDC run executed successfully.");
}
But this is returning control to the caller right away due to the await (which is expected). However, the return causes the calling method to exit which closes the DLL WinForm.
What is the best method to keep the DLL WinForm active/open?
Thanks for your time.
Edit. Following the suggestion by Stephen below I have decided to turn my DLL intery method type to Task<object> and set up a continuation as follows
if (classType != null)
{
if (bDllIsWinForm)
{
// To pass object array to constructor use the following.
// classInst = Activator.CreateInstance(classType, new object[] {dllParams});
classInst = Activator.CreateInstance(classType);
dllWinForm = (Form)classInst;
dllWinForm.Show();
// Invoke required method.
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInst, new object[] { dllParams });
if (result != null)
{
if (result.GetType() == typeof(Task<object>))
{
Task<object> task = (Task<object>)result;
task.ContinueWith(ant =>
{
object innerResult = task.Result;
return innerResult == null ? String.Empty : innerResult.ToString();
});
}
return result.ToString();
}
return String.Empty;
}
}
}
I decided to set up the continuation instead of the await to avoid the chaining that would occur with the await keyword - that is making the calling method (that calling the DLL of type Task<String> etc. up the call stack.
The DLL entry method now becomes:
public Task<object> ExecuteTest(object[] args)
{
Task<object> task = null;
Result result = new Result();
if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
return task;
IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
List<Enum> enumList = new List<Enum>()
{
Method.TestSqlConnection,
Method.ImportReferenceTables
};
task = Task.Factory.StartNew<object>(() =>
{
foreach (Method method in enumList)
{
result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
Process.ProcessStrategyFactory.GetProcessType(method));
if (!result.Succeeded)
{
// Display error.
}
task.Wait(5000); // Wait to prevent the method returning too quickly for testing only.
}
return null;
});
return task;
}
But this causes the DLL WinForm to be show for a split second and then disapear. i even attempted to make the Form dllWinForm global to keep the refernce to the object active, but this also has not worked. I want to note that the call to the DLL (N.B. the calling method is already running on a background thread-pool thread).
Any further helps is appreciated.
Change the return type of Execute to Task and await it.
It's difficult to guess what you have in dll but eventually your dll code + exposed in your question:
dllWinForm.Show();
should eventually have been after juxtaposing:
new Thread
(
() => new Form().ShowDialog()
)
.Start();
Probably, you should change dllWinForm.Show(); by dllWinForm.ShowDialog().Start();
ShowDialog(), in contrast with Show(), starts its own message pumping and returns only when explicitly closed.
Update (in respnse to comment):
It is not absolutely necessary to launch a form from UI.
Since you are on .NET 4.5, it is probably simpler to use WPF (instead of Windows Form) form.
Here is the code for WPF form which, in order to adjust for Windows Form, you should change Dispatcher parts by initializing WindowsFormsSynchronizationContext
Though, IMO, WinForms code will be much more complex.
I'm trying to wrap the Event Async Programming model used in RIA Services in a Task.
I have followed the standard way of using a TaskCompletionSource and implemented the following extension method:
public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query) where T : Entity
{
TaskCompletionSource<IEnumerable<T>> taskCompletionSource = new TaskCompletionSource<IEnumerable<T>>();
source.Load(
query,
loadOperation =>
{
if (loadOperation.HasError && !loadOperation.IsErrorHandled)
{
taskCompletionSource.TrySetException(loadOperation.Error);
loadOperation.MarkErrorAsHandled();
}
else if (loadOperation.IsCanceled)
{
taskCompletionSource.TrySetCanceled();
}
else
{
taskCompletionSource.TrySetResult(loadOperation.Entities);
}
},
null);
return taskCompletionSource.Task;
}
I then use this in the following way:
var task = _context.LoadAsync(_context.GetPlayersQuery());
task.Start();
task.Result;
The problem though is that I get an InvalidOperationException stating that "Start may not be called on a promise-style task". I have tried not starting the task, but then the loadOperation callback never fires.
Can anyone see what I am doing wrong here?
Thanks in advance
Problem is solved. Under the hood the DomainContext.Load() method is already operating in an asynchronous manner. There must have been some conflict with trying to wrap an already asynchronous method in a task.
However, even if I still follow the EAP correctly with the code below, I still get the InvalidOperationException of 'start cannot be called on a promise-style task'
public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query) where T : Entity
{
TaskCompletionSource<IEnumerable<T>> taskCompletionSource = new TaskCompletionSource<IEnumerable<T>>();
var loadOperation = source.Load(query);
loadOperation.Completed += (obj, args) =>
{
if (loadOperation.HasError && !loadOperation.IsErrorHandled)
{
taskCompletionSource.TrySetException(loadOperation.Error);
loadOperation.MarkErrorAsHandled();
}
else if (loadOperation.IsCanceled)
{
taskCompletionSource.TrySetCanceled();
}
else
{
taskCompletionSource.TrySetResult(loadOperation.Entities);
}
};
return taskCompletionSource.Task;
}
Try this instead
var result = await _context.LoadAsync(_context.GetPlayersQuery());
Try using
task.ContinuewWith(Action<Task<T>> continuation)
That worked for me, as I too got that exception when using task.Start
I'm facing a serious problem of deadlock in a multithreaded desktop/windows application. I fear I'm not using the correct approach to delegates in a very async environment. Also, even though I "sink" my events into the calling UI thread, if possible, I still have to Invoke on the UI thread to see some action. Follows, is the details.
The application is basically a client for users of an online file storage service. That service exposes functionality through REST calls. I first created a managed code wrapper DLL for such calls that allows for a .NET consumer to create a static instance of this DLL and call the functions. I'll take the file upload operation as an example.
Now, in the wrapper, here is the public interface for a file upload:
public Int32 UploadFile(FileSystemObject FolderToUploadTo, FileInfo LocalFileAndPath, OperationProgressReportEventHandler onOperationProgressReport, FileSystemObjectUploadCompletedEventHandler onOperationCompleted) {
Int32 ReplyNumber = 0;
try {
var TheOperation = new UploadFileObjectOperation(FolderToUploadTo, LocalFileAndPath, _User.APIKey) {
onProgressReport = onOperationProgressReport,
onUploadCompleted = onOperationCompleted
};
//Add it to the pool of operations
OperationPool.Add(TheOperation);
//Start the operation through the factory
OperationFactory.StartNew(() => {
TheOperation.Start();
});
//Chain the *actual* TPL Task to flush after usage
TheOperation.InnerTask.ContinueWith(t => {
t.Dispose(); //Dispose the inner task
OperationPool.Remove(TheOperation); //Remove the operation from the pool
TheOperation = null; //Nullify the Operation
});
ReplyNumber = TheOperation.TaskId;
}
catch {
ReplyNumber = 0;
}
return ReplyNumber;
}
As you can see, the actual UI application, that will refer this DLL, will be sending delegates for progress and completed to the operation(s). Now, the body of the operation itself:
public class UploadFileObjectOperation : BaseOperation, IDisposable {
//Store
public FileSystemObjectUploadCompletedEventHandler onUploadCompleted;
//Constructors
//Disposing stuff
protected override void PerformWork() {
try {
//Init the WebClient
UploadClient.UploadProgressChanged += (UploadProgressChanged_s, UploadProgressChanged_e) => {
//This is my event in base class being raised
ReportProgress(UploadProgressChanged_e.ProgressPercentage, UploadProgressChanged_e);
};
UploadClient.UploadFileCompleted += (UploadFileCompleted_s, UploadFileCompleted_e) => {
if (UploadFileCompleted_e.Error != null) {
throw new ApplicationException("Upload failed. " + UploadFileCompleted_e.Error.Message);
}
JObject JSONLiveObject = JObject.Parse(Encoding.UTF8.GetString(UploadFileCompleted_e.Result));
if (String.Compare((String)JSONLiveObject["status"], Constants._CONST_RESTRESPONSE_STATUS_VALUE_FAIL, false) == 0) {
throw new ApplicationException("Upload response failed. " + (String)JSONLiveObject["result"]["message"]);
}
//Eureka! Success! We have an upload!
//This is my event being raised
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = null,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Success,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
};
//Start the async upload
UploadClient.UploadFileAsync(AddressOfRESTURI, UploadingMethod, _FileToUpload.FullName);
}
catch (OperationCanceledException exp_Canceled) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp_Canceled,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Canceled,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// To ensure that the calling code knows the task was canceled
//throw;
}
catch (Exception exp) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Error,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// If the calling code also needs to know.
//throw;
}
}
protected void UploadTaskCompleted(UploadFileObjectOperationEventArg arg) {
if (onUploadCompleted == null)
return;
//Sinking into calling UI thread, if possible
if (onUploadCompleted.Target is Control) {
Control targetForm = onUploadCompleted.Target as Control;
targetForm.Invoke(onUploadCompleted, new object[] { arg });
}
else {
onUploadCompleted(arg);
}
Status = OperationRunningStatus.Completed;
}
}
The PerformWork() raises the two events: Progress reporting and completion. Note that while raising an event, I check if can get a route to the calling thread and push the event directly so to avoid invokes at UI.
Now, lets see how I'm using all of the above in a desktop client:
private void UploadFile(FileInfo DraggedFileInfo, FileSystemObject ParentDefination) {
SessionLifetimeStuff.APICore.UploadFile(ParentDefination, DraggedFileInfo,
(PercentageCompleted) => {
#region Progress
this.InvokeEx(f => {
UpdateTaskProgress(newTaskQueue.OID, PercentageCompleted.Progress, PercentageCompleted);
});
#endregion
}, (Result) => {
#region Completion
this.InvokeEx(f => {
switch (Result.Status) {
case OperationExitStatus.Success:
Console.WriteLine(String.Format("File: {0} uploaded to {1}", Result.UploadedFileSystemObject.DocumentFullname, Result.UploadedFileSystemObject.FolderId));
break;
case OperationExitStatus.Canceled:
DialogManager.ShowDialog(DialogTypeEnum.Warning, "Dropbox", "Upload canceled.", null, this);
break;
case OperationExitStatus.Error:
DialogManager.ShowDialog(DialogTypeEnum.Error, "Dropbox", "Upload failed.", Result.Error, this);
break;
}
});
#endregion
});
}
I'm using an extension method I found on Stackoverflow for adding the Invoking functionality:
public static class InvokeExtensions {
public static void InvokeEx<T>(this T #this, Action<T> action) where T : Control {
if (#this.InvokeRequired) {
#this.Invoke(action, new object[] { #this });
}
else {
if (!#this.IsHandleCreated)
return;
if (#this.IsDisposed)
throw new ObjectDisposedException("#this is disposed.");
action(#this);
}
}
public static IAsyncResult BeginInvokeEx<T>(this T #this, Action<T> action)
where T : Control {
return #this.BeginInvoke((Action)(() => #this.InvokeEx(action)));
}
public static void EndInvokeEx<T>(this T #this, IAsyncResult result)
where T : Control {
#this.EndInvoke(result);
}
}
In my code, i have commented out the invokes as I though i don't need then as the events being raised are coming in sinked. However, i realized that my UI was not doing anything at all. So, I added the InvokeEx({ code; }) and my UI started to shoe activity.
Now, why do I need to invoke?
If I attempt different operations from UI, eventually, my UI freezes although the application still behaves as normally functioning.
I found an old article at http://msdn.microsoft.com/en-us/library/ff649143.aspx#scag-ch06_topic4 that described the usage of delegates and I see that there is a IAsyncResult involved.
Could someone point me as to where I'm going wrong here?
Update:
Ok, with the invoking code commented on the UI, I get no activity at all. But upon using the this.InvokeEx or wrapping a work in this.BeginInvokeEx, I get UI updates but after a while, here are the two exceptions occurring (in this order):
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.