Wcf client and long-term operations - c#

Good day!
I have simple wcf service and desktop client,wich uses some functions.
But my client fault with exception that my wcf operation goes too long.
Some code:
client=new MyWcfServiceClient();
client.DoWork(param1,param2..etc);
I dont need to wait while DoWork do work. I need to execute this method and go forward. It is like send command to do some work and i dont need to get result immediately.
How to do that?
Thank you!
P.S. server side code looks like:
DoWork(param1,etc)
{
// do long-term work at same thread
}
P.P.S. i ingnore the result.

On the service, move your logic from: DoWork(param1, etc) to another method e.g. DoWorkBackground(...)
static Task _backgroundTask;
void DoWork(param1, etc)
{
if (_backgroundTask == null || _backgroundTask.IsCompleted)
_backgroundTask = System.Threading.Tasks.Task.Run(
() => DoWorkBackground(param1, etc) );
}
void DoWorkBackground(param1, etc)
{
//long running logic
}

You could do something along:
private static Task DoWork()
{
// do stuff here
// return something (?) assuming you need or care about this
}
and then you can do something like
Task task = DoWork().Start;
// you can wait, poll, or if you don't care, ignore the result

Using .NET 4.5, you can create task-based proxies while adding service reference to an application. This can be done using by clicking on the Advanced button in the Add Service Reference dialogue. See here for more info.
Once this is done you will get the following: DoWorkAsync
Using this new proxy you can do things like this:
var result = await client.DoWorkAsync(param1,param2..etc);

If you can modify your DoWork operation, define it as OneWay, so it will return immediately. If DoWork is a web service, the HTTP code 202 will be returned.

Related

Invoke AspNetCore.Diagnostics.HealthCheck from code without a call to HTTP endpoint?

I have added the Microsoft.AspNetCore.Diagnostics.HealthChecks on a collection of Service Fabric services, some of which have a HTTP ServiceEndpoints and some do not.
For the ones which do not have a service endpoint, if I wanted to add some implementations of IHealthCheck and add them to the ServiceCollection in StartUp as follows:
services
.AddHealthChecks()
.AddCheck<DatabaseHealthCheck>("Database")
.AddCheck<Api1HealthCheck>("Dependency API 1")
.AddCheck<Api2HealthCheck>("Dependency API 2");
is there a way of invoking those health checks without calling a HTTP endpoint on the service itself?
These particular services have a while loop like this in the RunAsync method currently to output a heartbeat to the logs:
public async Task RunAsync(string appInstanceDesc, CancellationToken cancellationToken)
{
long iterations = 0;
var sleepTimeSpan = _config.PollingInterval.GetTimeSpan();
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
_logger.LogInformation("Cancellation requested - shutting down");
break;
}
_logger?.LogDebug($"CR Heartbeat log iteration
{++iterations}{appInstanceDesc}");
Thread.Sleep(sleepTimeSpan);
}
}
Is there a way to invoke the HealthCheck classes from within that loop so that the results of which can be output to the logs?
Assuming that you added built-in health check framework:
services.AddHealthChecks()
If you do:
.. appBuilder.ApplicationServices.GetService<HealthCheckService>();
or
.. serviceProvider.GetRequiredService<HealthCheckService>();
in order to manually execute the CheckHealthAsync and get a HealthReport back that contains the statuses:
HealthReport healthReport = await healthCheckService.CheckHealthAsync();
Make sure that you are using the right HealthCheckService because it exists at two places, in:
using Microsoft.Extensions.Diagnostics.HealthChecks;
and in:
using Microsoft.Extensions.HealthChecks;
In my case, I had to use the one from Microsoft.Extensions.Diagnostics.HealthChecks
I think you can do it like this:
Get a HealthCheckService instance from the container (IServiceProvider).
Pass it to your service if needed
Call healthCheckService.CheckHealthAsync to get the health status.
(bonus) Use await Task.Delay(sleepTimeSpan) instead of Thread.Sleep
This idea is based on the middleware code here.

How to listen for Pub/Sub messages in an ASP.NET Core app continuously?

I would like to implement an ASP.NET Core API, which is not responding to HTTP requests, but upon startup starts listening to Google Cloud Pub/Sub messages, and it keeps listening indefinitely throughout its lifetime.
What is the preferred way to implement this with the official Pub/Sub SDK?
I can think of two ways:
Approach 1: Just use a SimpleSubscriber, and in the Startup.Configure start listening to messages:
public void Configure(IApplicationBuilder app)
{
var simpleSubscriber = await SimpleSubscriber.CreateAsync(subscriptionName);
var receivedMessages = new List<PubsubMessage>();
simpleSubscriber.StartAsync((msg, cancellationToken) =>
{
// Process the message here.
return Task.FromResult(SimpleSubscriber.Reply.Ack);
});
...
}
Approach 2: Use a library specifically created to periodically run a job, for example Quartz, Hangfire or FluentScheduler, and every time the job is triggered, pull the new messages with a SubscriberClient.
Which one is the preferred approach? The first one seems simpler, but I'm not sure if it's really reliable.
The first approach is definitely how this is intended to be used.
However, see the docs for StartAsync:
Starts receiving messages. The returned Task completes when either
StopAsync(CancellationToken) is called or if an unrecoverable
fault occurs. This method cannot be called more than once per
SubscriberClient instance.
So you do need to handle unexpected StartAsync shutdown on unrecoverable error. The simplest thing to do would be be use an outer loop, although given these errors are considered unrecoverable it is likely something about the call needs to be changed before it can succeed.
The code might look like this:
while (true)
{
// Each SubscriberClientinstance must only be used once.
var subscriberClient = await SubscriberClient.CreateAsync(subscriptionName);
try
{
await subscriberClient.StartAsync((msg, cancellationToken) =>
{
// Process the message here.
return Task.FromResult(SimpleSubscriber.Reply.Ack);
});
}
catch (Exception e)
{
// Handle the unrecoverable error somehow...
}
}
If this doesn't work as expected, please let us know.
Edit: SimpleSubscriber was renamed to SubscriberClient in the library so the answer has been edited accordingly.

How to log asynchronously with log4net in an ASP.NET MVC Web Application without using up all available threads?

Is AsyncForwardingAppender of the Log4Net.Async package safe to use in an ASP.NET MVC Web Application? I'm worried that it will clog up the available threads.
It comes down to me wanting to make a call to an async method to send the logs to an HTTP API. I could use an async void method like the way this guy did it:
protected override async void Append(log4net.Core.LoggingEvent loggingEvent)
{
var message = new SplunkMessage(loggingEvent.Level, loggingEvent.ExceptionObject);
var success = await _splunkLogger.Report(message);
//do something with the success status, not really relevant
}
He later updated his code:
public void DoAppend(log4net.Core.LoggingEvent loggingEvent)
{
var clientIp = _clientIpRetriever.GetClientIp();
var message = new SplunkMessage(loggingEvent.Level, loggingEvent.ExceptionObject, clientIp);
SendMessageToSplunk(message);
}
private async void SendMessageToSplunk(SplunkMessage message)
{
try
{
var success = await _splunkLogger.Report(message);
//do something unimportant
}
catch(Exception x)
{
LogLog.Error(GetType(), "Error in SplunkAppender.", x);
}
}
But I'm too scared to actually try it because of the dangers involved: "First off, let me point out that "fire and forget" is almost always a mistake in ASP.NET applications".
Any suggestions?
Looking at the source you can see that the AsyncForwardingAppender uses only one thread to dequeue the events. Using it won't kill your MVC app since only one thread will be used.
Regarding "Fire and forget" as a bad pattern in web apps, you have to add a grain of salt to the statement since the answer talks about the danger of letting a functional operation go unsupervised, not a logging one. Logging should be able to fail without your application ceasing working (which is why log4net never says anything when configuration or logging fails)

Topshelf - handling loops

Generally with services, the task you want to complete is repeated, maybe in a loop or maybe a trigger or maybe something else.
I'm using Topshelf to complete a repeated task for me, specifically I'm using the Shelf'ing functionality.
The problem I'm having is how to handle the looping of the task.
When boot strapping the service in Topshelf, you pass it a class (in this case ScheduleQueueService) and indicate which is its Start method and it's Stop method:
Example:
public class QueueBootstrapper : Bootstrapper<ScheduledQueueService>
{
public void InitializeHostedService(IServiceConfigurator<ScheduledQueueService> cfg)
{
cfg.HowToBuildService(n => new ScheduledQueueService());
cfg.SetServiceName("ScheduledQueueHandler");
cfg.WhenStarted(s => s.StartService());
cfg.WhenStopped(s => s.StopService());
}
}
But in my StartService() method I am using a while loop to repeat the task I'm running, but when I attempt to stop the service through Windows services it fails to stop and I suspect its because the StartService() method never ended when it was originally called.
Example:
public class ScheduledQueueService
{
bool QueueRunning;
public ScheduledQueueService()
{
QueueRunning = false;
}
public void StartService()
{
QueueRunning = true;
while(QueueRunning){
//do some work
}
}
public void StopService()
{
QueueRunning = false;
}
}
what is a better way of doing this?
I've considered using the .NET System.Threading.Tasks to run the work in and then maybe closing the thread on StopService()
Maybe using Quartz to repeat the task and then remove it.
Thoughts?
Generally, how I would handle this is have a Timer event, that fires off a few moments after StartService() is called. At the end of the event, I would check for a stop flag (set in StopService()), if the flag (e.g. your QueueRunning) isn't there, then I would register a single event on the Timer to happen again in a few moments.
We do something pretty similar in Topshelf itself, when polling the file system: https://github.com/Topshelf/Topshelf/blob/v2_master/src/Topshelf/FileSystem/PollingFileSystemEventProducer.cs#L80
Now that uses the internal scheduler type instead of a Timer object, but generally it's the same thing. The fiber is basically which thread to process the event on.
If you have future questions, you are also welcomed to join the Topshelf mailing list. We try to be pretty responsive on there. http://groups.google.com/group/topshelf-discuss
I was working on some similar code today I stumbled on https://stackoverflow.com/a/2033431/981 by accident and its been working like a charm for me.
I don't know about Topshelf specifically but when writing a standard windows service you want the start and stop events to complete as quickly as possible. If the start thread takes too long windows assumes that it has failed to start up, for example.
To get around this I generally use a System.Timers.Timer. This is set to call a startup method just once with a very short interval (so it runs almost immediately). This then does the bulk of the work.
In your case this could be your method that is looping. Then at the start of each loop check a global shutdown variable - if its true you quit the loop and then the program can stop.
You may need a bit more (or maybe even less) complexity than this depending on where exactly the error is but the general principle should be fine I hope.
Once again though I will disclaim that this knowledge is not based on topshelf, jsut general service development.

Silverlight 4: REST API call data retrieval layer?

I'm working in .NET 4 and SL 4.
I'm wanting to abstract out the data retrieval portion of my DAL from my silverlight page's code behind.
Ideally into its own DLL as an interface layer between my silverlight application and REST API calls.
My intent is not to use RIA services as I already have an existing DAL that's making use of a DLL that makes REST API calls.
The issue is the asynchronous "WebClient" call back process.
I know that I can utilize the WebClient class to make a REST call and then register the asynchronous handler to simply bind the results from that call to the UI.
But in my case, I want to abstract this out into its own DLL. Basically....making it synchronous.
By definition an asynchronous call has issues here being that it can't immediately and directly return an IEnumerable of some type.
Can anyone point me to a sample/tutorial where something like this is being done?
RIA makes method call to separate DLL for IEnumerable data collection
That method makes REST API call to retrieve data, then returns that IEnumerable to the RIA and is bound to the UI.
Boling it right down to the fundementals what you are actually asking for is to be able to make a synchronous call into an API that performs an asynchronous task but only returns when that asynchronous task is complete. To state it another way you want to re-combine the Begin and End phases of an asynchronous operation back into a single atomic synchronous operation.
The only way to acheive that is to block the thread making the call until the end phase of the asynchronous operation is reached. For a number of reasons this is not a good idea.
If you are serious about using Silverlight you have to swallow its asynchronous nature and work with in that framework rather than attempting to force it back into a synchronous system.
Converting synchronous to asynchronous
Have a read of this blog about converting synchronous code into asynchronous code. Having read that now lets just imagine that your code uses a synchronous method in your new DLL called DownloadYourDataObjects which has this imaginary signature:-
public IEnumerable<YourDataObject> DownloadYourDataObjects(Uri source);
Internally it use WebClient to download a string from a REST base service and converts it to a set of YourDataObject instances. The imaginary synchronous code to display this set of data might be:-
private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
{
try
{
LoadMyData();
}
catch (Exception err)
{
// Oops something bad happened show err.
}
}
private void LoadMyData()
{
DataItemsListBox.ItemsSource = DownloadYourDataObjects(someUri);
}
Since Silverlight WebClient is asynchronous we need to convert this whole chain of code to work in an asynchronous manner.
Using the AsyncOperationService from the blog we first need to convert the DownloadYourDataObjects to return an AsyncOperation instead. It would have a signature like this (see later for an implementation idea):-
public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult);
The usage code would then look something like this:-
private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
{
LoadMyData().Run(err =>
{
if (err != null)
{
// Oops something bad happened show err.
}
});
}
private IEnumerable<AsyncOperation> LoadMyData()
{
yield return DownloadYourDataObjects(someUri, result =>
{
DataItemsListBox.ItemsSource = result;
});
}
This may look a litte OTT but in fact it isn't much more code than the original "synchronous" version. In this simple case LoadMyData only had one operation to perform. A more complex version of LoadMyData may have multiple other operations that need to be asynchronous as well. In such a case those operations would just be other yield points in the code, the basic logical structure of LoadMyData would not change much from an original synchronous version.
Here is an example of an implementation of DownloadYourDataObjects that your DLL would supply.
public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult)
{
return (completed) =>
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, args) =>
{
try
{
returnResult(ConvertStringToYourDataObjects(args.Result));
completed(null);
}
catch (Exception err)
{
completed(err);
}
};
client.DownloadStringAsync(source);
};
}

Categories

Resources