Adding ability to cancel a running PowerShell operation (using System.Management.Automation in VB.NET) [duplicate] - vb.net

I'm invoking powershell command with C#, and powershell command is invoked background. and i want to terminate the background thread. everytime, i terminate the background thread, the powershell is still running which result in that i can't run that thread again. is there any method to terminate powershell execution?
the background thread as follows:
Task.run(()=>{ while(...) {...
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}}});
Task.run(()=>{
while(...) { powershell.invoke(powershellCommand);// it will execute here, I don't know how to stop.
} })

Stopping a PowerShell script is pretty simple thanks to the Stop() method on the PowerShell class.
It can be easily hooked into using a CancellationToken if you want to invoke the script asynchronously:
using(cancellationToken.Register(() => powershell.Stop())
{
await Task.Run(() => powershell.Invoke(powershellCommand), cancellationToken);
}

I know I'm late to the party but I've just written an extension method which glues up the calls to BeginInvoke() and EndInvoke() into Task Parallel Library (TPL):
public static Task<PSDataCollection<PSObject>> InvokeAsync(this PowerShell ps, CancellationToken cancel)
{
return Task.Factory.StartNew(() =>
{
// Do the invocation
var invocation = ps.BeginInvoke();
WaitHandle.WaitAny(new[] { invocation.AsyncWaitHandle, cancel.WaitHandle });
if (cancel.IsCancellationRequested)
{
ps.Stop();
}
cancel.ThrowIfCancellationRequested();
return ps.EndInvoke(invocation);
}, cancel);
}

Related

Integrationtest IHost TestServer won't shutdown

I wrote some integration tests for an aspnetcore 3.1 application using xunit.
Tests show successful, but process is still running. After some time I get:
The process dotnet:1234 has finished running tests assigned to it, but is still running. Possible reasons are incorrect asynchronous code or lengthy test resource disposal [...]
This behavior does even show with boilerplate code like:
[Fact]
public async Task TestServer()
{
var hostBuilder = new HostBuilder()
.ConfigureWebHost(webHost =>
{
// Add TestServer
webHost.UseTestServer();
webHost.Configure(app => app.Run(async ctx =>
await ctx.Response.WriteAsync("Hello World!")));
});
// Build and start the IHost
var host = await hostBuilder.StartAsync();
}
Same if I add await host.StopAsync()...
I am on an Ubuntu 18.04 machine.
Try to dispose the host at the end of the test. Most likely, the error is caused just because you don't dispose disposable resource.
I would recommend you to use WebApplicationFactory for testing instead of HostBuilder. You may find more in the docs
I had the same problem. Since i was working with NUnit the suggested change was not an option (it is based on xunit). So i was digging into it and the root cause of it was quite simple:
I created a long running task in the Startup.cs which was doing some monitoring throughout all the hosting's lifetime. So i had to stop this task, and then also the instance of the TestHost was disposed properly.

NServiceBus 5.2.14 - Scheduler fails to trigger delegate

While using the NServiceBus Scheduler I have been unsuccessful in triggering the delegate defined. I used the documentation at the link below to setup the EndpointScheduler class.
The endpoints corresponding timeout queue is created and a message successfully enters the queue. No errors are encountered during execution, but the scheduler does not trigger the delegate. I am currently using NServiceBus 5.2.14, a similar test works using NServiceBus 3.2.7. Any ideas why the Scheduler isn't triggering the delegate?
http://docs.particular.net/nservicebus/scheduling/
public class EndpointScheduler : IWantToRunWhenBusStartsAndStops, ILoggable
{
public EndpointScheduler(Schedule schedule)
{
this.schedule = schedule;
}
public void Start()
{
schedule.Every(
TimeSpan.FromMinutes(1),
"Test",
() =>
{
Debug.WriteLine("I'm testing the scheduler");
}
);
}
public void Stop()
{
}
}
Thanks to #DavidBoike for pointing out a few potential setup issues.
The endpoint configuration contained:
configuration.DisableFeature<TimeoutManager>()
Removing it corrected the issue I encountered.
The reason for this is that the scheduler is dependent upon the TimeoutManager. It works by deferring a message to be processed later (using the TimeoutManager) and when that message is received, the delegate is invoked. Without the TimeoutManager activated, this can't work.

Web API 2 return OK response but continue processing in the background

I have create an mvc web api 2 webhook for shopify:
public class ShopifyController : ApiController
{
// PUT: api/Afilliate/SaveOrder
[ResponseType(typeof(string))]
public IHttpActionResult WebHook(ShopifyOrder order)
{
// need to return 202 response otherwise webhook is deleted
return Ok(ProcessOrder(order));
}
}
Where ProcessOrder loops through the order and saves the details to our internal database.
However if the process takes too long then the webhook calls the api again as it thinks it has failed. Is there any way to return the ok response first but then do the processing after?
Kind of like when you return a redirect in an mvc controller and have the option of continuing with processing the rest of the action after the redirect.
Please note that I will always need to return the ok response as Shopify in all it's wisdom has decided to delete the webhook if it fails 19 times (and processing too long is counted as a failure)
I have managed to solve my problem by running the processing asynchronously by using Task:
// PUT: api/Afilliate/SaveOrder
public IHttpActionResult WebHook(ShopifyOrder order)
{
// this should process the order asynchronously
var tasks = new[]
{
Task.Run(() => ProcessOrder(order))
};
// without the await here, this should be hit before the order processing is complete
return Ok("ok");
}
There are a few options to accomplish this:
Let a task runner like Hangfire or Quartz run the actual processing, where your web request just kicks off the task.
Use queues, like RabbitMQ, to run the actual process, and the web request just adds a message to the queue... be careful this one is probably the best but can require some significant know-how to setup.
Though maybe not exactly applicable to your specific situation as you are having another process wait for the request to return... but if you did not, you could use Javascript AJAX kick off the process in the background and maybe you can turn retry off on that request... still that keeps the request going in the background so maybe not exactly your cup of tea.
I used Response.CompleteAsync(); like below. I also added a neat middleware and attribute to indicate no post-request processing.
[SkipMiddlewareAfterwards]
[HttpPost]
[Route("/test")]
public async Task Test()
{
/*
let them know you've 202 (Accepted) the request
instead of 200 (Ok), because you don't know that yet.
*/
HttpContext.Response.StatusCode = 202;
await HttpContext.Response.CompleteAsync();
await SomeExpensiveMethod();
//Don't return, because default middleware will kick in. (e.g. error page middleware)
}
public class SkipMiddlewareAfterwards : ActionFilterAttribute
{
//ILB
}
public class SomeMiddleware
{
private readonly RequestDelegate next;
public SomeMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
await next(context);
if (context.Features.Get<IEndpointFeature>().Endpoint.Metadata
.Any(m => m is SkipMiddlewareAfterwards)) return;
//post-request actions here
}
}
Task.Run(() => ImportantThing() is not an appropriate solution, as it exposes you to a number of potential problems, some of which have already been explained above. Imo, the most nefarious of these are probably unhandled exceptions on the worker process that can actually straight up kill your worker process with no trace of the error outside of event logs or something at captured at the OS, if that's even available. Not good.
There are many more appropriate ways to handle this scenarion, like a handoff a service bus or implementing a HostedService.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio

TPL Task in WCF service fails to use correct IIS security Credentials (SQL Connection)

I have a WCF service method that calls a SQL stored proc. I'm developing using IIS 5 (can't do much about that, II6/7 not available)
To get some gains, I'm doing a number of async calls to this stored proc by putting the call into a c# TPL Task.
When run as a Task, I'm getting an SQL Exception...
"Login failed. The login is from an untrusted domain and cannot be used with Windows authentication"
However, If I run the exact same process without using a Task, I have no problems with SQL connection
It would appear to me that the credentials for the IIS Virtual folder (WCF) are not being delegated to the Task? Any ideas how I can specificy credentials for the TPL Task thread, ie to use the same as the parent etc ?
I am using Windows Authentication (sspi), and impersonation to be able to connect to the seperate SQL box.
Your help appreciated.
You have two choices.
1) Opt your entire application into always flowing the identity using:
<runtime>
<alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>
This has a side effect of overhead and the danger of accidentally executing some unintended code with the priviledges of the currently calling user rather than the application identity. I would personally avoid this and go with #2 where you explicitly opt-in.
2) Capture the WindowsIdentity before setting up your TPL tasks and explicitly impersonate where you need to make the calls using Impersonate + WindowsImpersonationContext:
public void SomeWCFOperation()
{
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
Task.Factory.StartNew(() =>
{
// some unpriviledged code here
using(WindowsImpersonationContext impersonationContext = currentIdentity.Impersonate())
{
// this code will execute with the priviledges of the caller
}
// some more unpriviledged code here
});
}
As another workaround, you can create extensions to the TPL as follows:
public static class TaskFactoryExtensions
{
public static Task StartNewImpersonated(this TaskFactory taskFactory, Action action)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew(() =>
{
using (identity.Impersonate())
{
action();
}
});
}
public static Task<TResult> StartNewImpersonated<TResult>(this TaskFactory taskFactory, Func<TResult> function)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew<TResult>(() =>
{
using (identity.Impersonate())
{
return function();
}
});
}
}
You would then call these new methods in place of the standard StartNew methods.
The downside to this is that there are a lot of methods to override.

WCF, multiple async calls

I have a View in Windows Form that needs to execute multiple WCF calls async.
The problem is that when the second callback return, WCF raises an error of timeout or a generic exception. If I execute them sync everything is fine.
This is the code:
Proxy.Open();
Proxy.BeginStepOne(ar =>
{
// do something
});
//This raises an Exception
Proxy.BeginStepTwo(ar =>
{
// do something
});
Proxy.Close();
Is there a better way?