Thread wait using WaitHandles in C# - c#

Here is what I'm trying to achieve.
I have a login class. Once the user is authenticated, some post login operations are done in a thread. And the user gets to home page.
Now from home page I go to a different functionality, say class FindProduct. I need to check if post login operations in the login thread are completed. Only if post login operation is completed I allow to enter the functionality.
Do I have to put wait handles on PerformLoginAsyncThread as well as OnClickFindProduct?
Class Login
{
public bool Login(Userinfo)
{
// do tasks like authenticate
if(authenticationValid)
{
PerformLoginAsyncThread(UserInfo)
//continue to homepage
}
}
}
Class HomePage
{
public void OnClickFindProduct
{
if(finishedPostLoginThread)
// proceed to Find Product page
else
{
//If taking more than 8 seconds, throw message and exit app
}
}
}

Here is the general idea how to use EventWaitHandles. You need to Reset it before doing the work, and Set it when you are done.
In the example below I have made the ResetEvent property static, but I suggest you pass the instance somehow instead, I just could not do it without more details about your architecture.
class Login
{
private Thread performThread;
public static ManualResetEvent ResetEvent { get; set; }
public bool Login(Userinfo)
{
// do tasks like authenticate
if(authenticationValid)
{
PerformLoginAsyncThread(UserInfo);
//continue to homepage
}
}
private void PerformLoginAsyncThread(UserInfo)
{
ResetEvent.Reset();
performThread = new Thread(() =>
{
//do stuff
ResetEvent.Set();
});
performThread.Start();
}
}
class HomePage
{
public void OnClickFindProduct
{
bool finishedPostLoginThread = Login.ResetEvent.WaitOne(8000);
if(finishedPostLoginThread)
{
// proceed to Find Product page
}
else
{
//If taking more than 8 seconds, throw message and exit app
}
}
}

If you don't want to complicate your logic with await or raising an event the simplest solution would be inside the PerformLoginAsyncThread function just set a session variable to true on complete and in your OnClickFindProduct check for the session variable.

Related

How to efficiently count HTTP Calls in asp.net core?

I have an abstract class called HttpHelper it has basic methods like, GET, POST, PATCH, PUT
What I need to achieve is this:
Store the url, time & date in the database each time the function is called GET, POST, PATCH, PUT
I don't want to store directly to the database each time the functions are called (that would be slow) but to put it somewhere (like a static queue-memory-cache) which must be faster and non blocking, and have a background long running process that will look into this cache-storage-like which will then store the values in the database.
I have no clear idea how to do this but the main purpose of doing so is to take the count of each calls per hour or day, by domain, resource and url query.
I'm thinking if I could do the following:
Create a static class which uses ConcurrentQueue<T> to store data and call that class in each function inside HttpHelper class
Create a background task similar to this: Asp.Net core long running/background task
Or use Hangfire, but that might be too much for simple task
Or is there a built-in method for this in .netcore?
Both Hangfire and background tasks would do the trick as consumers of the queue items.
Hangfire was there before long running background tasks (pre .net core), so go with the long running tasks for net core implementations.
There is a but here though.
How important is to you that you will not miss a call? If it is, then neither can help you.
The Queue or whatever static construct you have will be deleted the time your application crashes/machine restarts or just plain recycling of the application pools.
You need to consider some kind of external Queuing mechanism like rabbit mq with persistence on.
You can also append to a file, but that might also cause some delays as read/write.
I do not know how complex your problem is but I would consider two solutions.
First is calling Async Insert Method which will not block your main thread but will start task. You can return response without waiting for your log to be appended to database. Since you want it to be implemented in only some methods, I would do it using Attributes and Middleware.
Simplified example:
public IActionResult SomePostMethod()
{
LogActionAsync("This Is Post Method");
return StatusCode(201);
}
public static Task LogActionAsync(string someParameter)
{
return Task.Run(() => {
// Communicate with database (X ms)
});
}
Better solution is creating buffer which will not communicate with database each time but only when filled or at interval. It would look like this:
public IActionResult SomePostMethod()
{
APILog.Log(new APILog.Item() { Date = DateTime.Now, Item1 = "Something" });
return StatusCode(201);
}
public partial class APILog
{
private static List<APILog.Item> _buffer = null;
private cont int _msTimeout = 60000; // Timeout between updates
private static object _updateLock = new object();
static APILog()
{
StartDBUpdateLoopAsync();
}
private void StartDBUpdateLoopAsync()
{
// check if it has been already and other stuff
Task.Run(() => {
while(true) // Do not use true but some other expression that is telling you if your application is running.
{
Thread.Sleep(60000);
lock(_updateLock)
{
foreach(APILog.Item item in _buffer)
{
//Import into database here
}
}
}
});
}
public static void Log(APILog.Item item)
{
lock(_updateLock)
{
if(_buffer == null)
_buffer = new List<APILog.Item>();
_buffer.Add(item);
}
}
}
public partial class APILog
{
public class Item
{
public string Item1 { get; set; }
public DateTime Date { get; set; }
}
}
Also in this second example I would not call APILog.Log() each time but use Middleware in combination with Attribute

Hangfire retry pattern

It is possible to retry task till condition is not completed ? e.g.
internal class Program
{
private static void Main(string[] args)
{
var user = new User();
var jobs = new Jobs();
Hangfire.BackgroundJob.Enqueue(() => jobs.SendNotification(user));
}
}
public class Jobs
{
Rules rules = new Rules();
public void SendNotification(User user)
{
if (rules.Rule1() && rules.Rule2())
{
// send notification
return;
}
// somehow retry the execution of this method (throw exception does not seem right)
}
}
public class Rules
{
public bool Rule1() { return true; }
public bool Rule2() { return true; }
}
public class User { }
I know that it is possible to retry execution of method by throwing exception but that does not seem right, since I know that recovering from exception is rather costly, and it will mark job as failed in hangfire admin interface which is not true.
I could write retry pattern myself, but I like the way hangfire is saving all the information related to background job processing to the persistent storage (SQL in my case), no data is kept in a process’ memory. So I assume it can recover the queue from storage even after server was shut down and continue processing.
Note: i would like to use hangfire because we already using it for the jobs but if it is not suitable I have free hand. Could you recommend some library that can do what I want and you have good experience with it ?

SignalR registering a user to a group outside of hub?

Maybe I am just not understanding Groups in SignalR correctly, but I am confused on the registering a user to a group part. I am using version 1.2.2.
Here: Groups demonstrates how to use groups in older SignalR
I am using a singleton to maintain the context of the hub. I am also using asp.net mvc 4. Basically, I want to do something with a menu item (make it flash, add a count of new tasks, etc..) during an update, but only to the users that are assigned tasks within that option.
So I figured, server side when checking the user's roles, I can conditionally assign them to the SignalR Group for broadcasts.
Here is my hub, and singleton classes:
public class TransactHub : Hub
{
public Task RegisterForTransactionPartUpdates()
{
return Groups.Add(Context.ConnectionId, "Transact");
}
public void UpdateDailyTransactionTable(string r)
{
Clients.All.broadcastUpdate(r);
}
}
And Singleton:
public class TransactSingleton
{
private readonly static Lazy<TransactSingleton> _instance = new Lazy<TransactSingleton>(() => new TransactSingleton(GlobalHost.ConnectionManager.GetHubContext<TransactHub>().Clients));
private TransactSingleton(IHubConnectionContext clients)
{
Clients = clients;
}
private IHubConnectionContext Clients
{
get;
set;
}
public static Transact Instance
{
get
{
return _instance.Value;
}
}
public void RegisterForTransactionUpdates()
{
//I want to register user here..
}
public void BroadcastUpdate(List<string> orders)
{
}
}
So where would I actually register the user? Also, upon a new connection using:
$.connection.hub.disconnected(function () {
setTimeout(function () {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
Will the user stay registered in the group?
Hmm, so it appears from this article: Hubs
public class ContosoChatHub : Hub
{
public override Task OnConnected()
{
// Add your own code here.
// For example: in a chat application, record the association between
// the current connection ID and user name, and mark the user as online.
// After the code in this method completes, the client is informed that
// the connection is established; for example, in a JavaScript client,
// the start().done callback is executed.
return base.OnConnected();
}
public override Task OnDisconnected()
{
// Add your own code here.
// For example: in a chat application, mark the user as offline,
// delete the association between the current connection id and user name.
return base.OnDisconnected();
}
public override Task OnReconnected()
{
// Add your own code here.
// For example: in a chat application, you might have marked the
// user as offline after a period of inactivity; in that case
// mark the user as online again.
return base.OnReconnected();
}
}
I should be using the OnConnected, and make a database call to handle the conditional assigning. I was hoping I would be able to handle the database call outside of the hub, but doesn't look possible. Correct me if I am wrong.

Async command execution in MVVM light

I am wondering why MVVM light is missing command with async execution? I believe there are many cases where this could be useful, so let me name one.
Let's say that our UI contains one container that contains multiple screens. User can close a particular screen or a container with multiple screens. Let's say that a user has issued a close command on the container. Container in return invokes close command on each screen, and it needs to wait for screen to be closed. This in practice can means validating data. saving, etc. For this reason we need to issue an async call to keep the UI from becoming unresponsive, and also we need to wait for task to complete, in order to continue.
So, if we have something like this in Command
public RelayCommand CloseCommand
{
get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
{
foreach (var screen in Screens)
{
if (!await screen.CloseCommand.ExecuteAsync(null))
{
// do something
}
}
}) }
}
We could also expose additional method on screen, but in my opinion it should be task of RelayCommand, since it already exist there.
Or there is a different methodology to handle such scenario?
Probably because there are many different ways of doing it; I describe a few approaches in my MSDN article on the subject.
Asynchronous lifetime commands are especially tricky. Something like a "close" command must be carefully considered. Is there some indication that a close is in progress? What happens if the user closes more than once ("close" in particular can often be initiated by an OS or another app even if a "close button" is disabled)?
I found this being in some ways a solution to making async commands in MVVM Light.
If fact it overwrap a async method with Task.Run. Our wrapped method has to verify if it not executed twice, and catches errors from lower async executions.
private bool isLoading;
public bool IsLoading
{
get { return isLoading; }
set
{
if (value != isLoading)
{
Set(ref isLoading, value);
//Used to refresh Commands CanExecute laying on IsLoading
CommandManager.InvalidateRequerySuggested();
}
}
}
private RelayCommand loadCommand;
public RelayCommand LoadCommand
{
get
{
return loadCommand ?? (loadCommand = new RelayCommand(
() => Task.Run(LoadAsync),
() => !IsLoading
));
}
}
private async Task LoadAsync()
{
//Prevents double execution in case of many mouse clicks on button
if (IsLoading)
{
return;
}
//Assignments which need to be done on UI tread
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = true;
});
try
{
list = await service.LoadAsync();
...
}
catch (Exception e)
{
...
}
finally
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = false;
});
}
}

ASP.NET MVC 4: Only allow one request at a time

In my ASP.NET MVC Application, I want to handle all requests sequentially; no action/controller code should be executed concurrently with another. If two requests come in at similar times, it should run the first one first, then the second one when the first one is done.
Is there a better way of doing this besides using a global lock variable?
EDIT: The application is more of a batch/service over the web that performs web service calls and cleans up a database. Different URLS in the site lead to different batch operations. This is not a site for end-users. Thus, I need to make it so that only one request to a URL (which will do some batch operations) will be done at a time, otherwise the batch operation could be corrupted if code for it runs concurrently with itself, or other batch operations. In fact, if another request comes when one is currently executing, it should not be run at all, even after the previous one finishes; it should just give an error message.
I would like to know if there was a way to do this in IIS instead of code. If I have a global lock variable, it would make the code more complicated, and I might run in a deadlock where the lock variable is set to true but never can be set to false.
EDIT: Sample code of implementation plan
[HttpPost]
public ActionResult Batch1()
{
//Config.Lock is a global static boolean variable
if(Config.Lock) { Response.Write("Error: another batch process is running"); return View(); }
Config.Lock = true;
//Run some batch calls and web services (this code cannot be interleaved with ExecuteBatchCode2() or itself)
ExecuteBatchCode();
Config.Lock = false;
return View();
}
[HttpPost]
public ActionResult Batch2()
{
if(Config.Lock) { Response.Write("Error: another batch process is running"); return View(); }
Config.Lock = true;
//Run some batch calls and web services (this code cannot be interleaved with ExecuteBatchCode1() or itself)
ExecuteBatchCode2();
Config.Lock = false;
return View();
}
Would I need to be worried about a case where the code does not reach Config.Lock = false, resulting in Config.Lock = true forever, causing no more requests to be served?
You have accept request as much as you can, people don't like waiting in front of browser.
But after, on serve side, yuo can push them into (say) Queue<T> and process them in sequence.
In short:
accept in async way
process, on the server, in sequence
You could write an attribute:
public class ExclusiveActionAttribute : ActionFilterAttribute
{
private static int isExecuting = 0;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Interlocked.CompareExchange(ref isExecuting, 1, 0) == 0)
{
base.OnActionExecuting(filterContext);
return;
}
filterContext.Result =
new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
Interlocked.Exchange(ref isExecuting, 0);
}
}
then use it on the controllers/methods that you want to control:
[ExclusiveAction] //either here, for every action in the controller
public class MyController : Controller
{
[ExclusiveAction] //or here for specific methods
public ActionResult DoTheThing()
{
//foo
return SomeActionResult();
}
}
the above code does not work probably because when request 1 is running and send request 2, app return service unavailable, it's good but if request 1 doesn't completed and again send request 2 to app, app running both request at same time. I'm reviewed code and change it.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ExclusiveActionAttribute : ActionFilterAttribute
{
private static int _isExecuting = 0;
private static int _isDuplicated = 0;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 0)
{
base.OnActionExecuting(filterContext);
return;
}
Interlocked.Exchange(ref _isDuplicated, 1);
filterContext.Result = new StatusCodeResult((int)HttpStatusCode.ServiceUnavailable);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
if (_isDuplicated == 1)
{
Interlocked.Exchange(ref _isDuplicated, 0);
return;
}
Interlocked.Exchange(ref _isExecuting, 0);
}

Categories