I am learning C# again after a whole lot of years. I did C# programming back in the 2.0 days. The language has indeed evolved, and its fantastic. That being said, I am making a W8/WP8 universal app. Basically when the app launches, the constructor runs a method. This method checks for a connection and if the connection is enabled, the program flows forward.
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand(
"Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));
// Show the message dialog
await msgdialog.ShowAsync();
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
So if you notice, if the connection fails then we have a message dialog popped up. There is a "try again" button the popup. When users click this button, it has a "callback function" associated with it (new stuff to me, I guess its like an event handler?). Anyways, instead of coding a new method, I made the callback method the same as the current method the messagebox is executed in. So basically what I did was added an argument so I have this UpdateInformationSection(IUICommand command). And then the callback function is the same method.
What I am scared of: Everytime they click the "try again" button, will it destroy the old instance of it? In other words, when they click the "try again" button, does the method finish executing? Otherwise I am imagining a scenario where the method is called again and again and each method is stuck in limbo (if this makes any sense).
Also, in my constructor when the method is FIRST called ,I had to change it to
//Update HUB Sections.
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);
Is it okay sending a "null" like that to the "command" argument? What is the right procedure here.
For sure, there's no true recursion here, because you are using async. But it is possible (probable, actually, but I haven't double-checked) that the MessageDialog does not complete the ShowAsync() method call until your own command delegate completes. This would result in the multiple instances of MessageDialog remaining reachable until you finally don't show it, preventing them from being garbage-collected (i.e. the closest you can get to a real memory leak with managed objects).
IMHO, the method would be better-implemented if you avoided this potential re-entrancy, by queuing the method for execution again instead of call it directly. That could look something like this:
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand("Try again"));
// Show the message dialog
await msgdialog.ShowAsync();
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
return;
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
This way, each time the MessageDialog is displayed, it's given the opportunity to go ahead and close before you redisplay it.
The above assumes "Try again" really is the only option you present. Of course, if you have additional options, you can use the UICommand object to distinguish between the selected option and do the appropriate thing; "Try again" would do the above call to RunAsync() the method again, while other options would do whatever they do.
All that said, personally I think it would be better to avoid this pattern. Presumably, the user did something else that originally initiated this dialog. At the very least, there ought to also be a "Cancel" option as an alternative to "Try Again". And IMHO it would actually be better to just present this as an alert with the default "Close", so that the user simply is taken back to wherever they were, so that after they fix the configuration issue, they can just explicitly attempt the action/operation again.
I'm of course making some assumptions about the program here. Lacking specific details, I admit there could be some compelling reason to do it the way you are now instead. But at least be sure this is really the best way to do it. Sticking a user in a potentially endless loop seems a bit "off" to me. :)
EDIT:
To elaborate on this bit of code:
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
The RunAsync() method causes the given delegate to be executed in the Dispatcher's thread, i.e. the UI thread for your program. This is where the method is already (presumably) running, since it's a command invoked by some UI object. Doing it this way allows the method to be re-invoked, but in a non-re-entrant way. I.e. the current method call is allowed to complete and return before the next one starts. This eliminates any recursive aspect.
The invoked delegate itself — () => { var ignoreTask = UpdateInformationSection(command); } — using the statement body lambda syntax, is simply the method call to invoke your command method again.
Finally, both the RunAsync() method and your command method are async methods, returning a Task instance. In this particular case, we don't need to wait for them to finish, so there's no await, but if we don't do something with the return value the compiler will generate a warning. For me, the easiest, cleanest way to suppress the warning is to go ahead and copy the Task reference to a local variable, which is enough to make the compiler happy. The RunAsync() method is copied to a variable named _, which is what I usually use for variables that I don't actually need to use, while the command method's return value is copied to a variable named ignoreTask, named that way to be explicit about the purpose of the variable (which is to ignore the Task returned from your command method).
Related
I am trying to silently send a synchronous Lisp command to autocad from c# code.
Here's how we send a Synchronous command to autocad.
string textToSend = $"(command-s \"_.-layout\" \"_t\" {filePath} {layoutName})";
object acadDoc = Application.DocumentManager.MdiActiveDocument.GetAcadDocument();
acadDoc.GetType().InvokeMember("SendCommand", BindingFlags.InvokeMethod, null, acadDoc, new[] { textToSend + "\n" });
The command works but the problem is that the command ends up in autocad's command line and clogs up the history of the drafters using our extensions.
We tried modifying system variables CMDECHO, CMDDIA, and NOMUTT without success
Directly in autocad's command line manually
With the c# method SetSystemVariable()
The same way we called our InvokeMember("SendCommand")
In the same Lisp command where we do our action
I looked at the InvokeMember parameters but didn't see anything that might affect the display of the command like there exists for the ActiveDocument.SendTextToExecute() asynchronous command.
How do we send synchronous Lisp commands to autocad from c# code silently?
Ps: The reason why I am not using WBlockCloneObjects() is because it makes our apps extremely unstable. I am not really interested in opening that whole can of worms in this issue, I'm only stating this to explain why I ended up with the solution from my question.
The title of my question was misleading. I didn't need to run lisp code silently, I needed to run commands in acad's command line silently. It just happened to be that acad's command line accepts lisp code so that's what I was using.
Instead of running lisp code, I used the method ActiveDocument.Editor.Command() to send my command to autocad. This method is synchronous and is affected by the system variable cmdecho.
I encountered a subsequent problem; because I was calling this method from a button in the banner with RelayCommand, Editor.Command was throwing the exception eInvalidInput because I was in the Application context instead of the Document context.
The best way to handle this was to split my first method in two and call the second method with ActiveDocument.SendStringToExecute() which uses the command line so I end up in the Document context. But because SendstringToExecute() is async, I had to rework my method's logic a bit.
Here is the final result (simplified)
private Layout Layout;
private RelayCommand _Command_Test;
public RelayCommand Command_Test
{
get
{
if (_Command_Test == null)
{
_Command_Test = new RelayCommand(
(param) =>
{
FirstMethod();
},
(param) =>
{
return true;
}
);
}
return _Command_Test;
}
}
[CommandMethod("FirstMethod")]
public void FirstMethod()
{
// Many actions and processing
Layout = new Layout(/*With stuff*/);
Application.DocumentManager.MdiActiveDocument.SendStringToExecute("SecondMethod ", true, false, false);
}
[CommandMethod("SecondMethod")]
public void SecondMethod()
{
short cmdecho = (short)Application.GetSystemVariable("cmdecho");
Application.SetSystemVariable("cmdecho", 0);
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.Command("_.-layout", "_t", Layout.FilePath, Layout.Name);
Application.SetSystemVariable("cmdecho", cmdecho);
// Actions that need to be ran after the command
}
I had to split my first method differently to have two sets of synchronous actions.
Because CommandMethod can't receive parameters, I had to store information in the fields of the class.
I skipped it in the code shown here but I, of course, used try-catches and transactions to handle potential issues.
I am trying to use ActionFilters to capture the result in my api call and change it if needed.
But it appears to change only the object i pass not the result type. (from OK to BadRequest)
return Ok(await _Data.Remove());
The above code in my controller leads to my filter:
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
Guid userId = await _data.GetId();
BaseModel baseModel = (BaseModel)((ObjectResult)resultContext.Result).Value;
if (baseModel.ApiResponse == ApiResponse.AllGood)
{
BaseModel m = _data.GetBaseModel(userId);
m.ApiResponse = baseModel.ApiResponse;
resultContext.Result = new OkObjectResult(m);
}
else if (baseModel.ApiResponse == ApiResponse.NotFound)
resultContext.Result = new NotFoundObjectResult(baseModel);
else
resultContext.Result = new BadRequestObjectResult(baseModel);
}
The model is correctly captured and i can check against its contents. And i can change it and pass it back. But it always goes back to the controller and then returns the "ok" with the new model.
What i want is it returning BadRequest
I have tried putting doing this:
resultContext.Result = new BadRequestObjectResult(baseModel);
As you can see from the above code, but it does not work.
The reason you cannot get it to work, is because this approach isn't possible (in the general case, at least).
The async variant of the ActionFilter combines both the pre and post variants of the synchronous variant, in one callback, by giving you next().
Once you have called and successfully returned from next(), you are in 'executed' land, not 'executing' land anymore.
The trouble is, if next() has started sending the response to the client, it is too late to change the response. Your receiving client may already sit with 'http 200 ok' in his hand!
You can observe this, by trying to write to the response in context.HttpContext.Response (You can set the Http Status Code on it, and use WriteAsync on it),
in the spot where you attempt to modify Result.
If next had already started the response, you'll get a direct exception telling you this.
However, IF next() hadn't begun the response, you may actually be able to control the response.
A last-resort option you have, is to throw at this point, it will (mostly) break your http response into http-500 server error. This may or may not be good for your client.
Lastly, your resultContext actually has a 'Cancelled' attribute which you can flag.
However I don't know if that has any effect if the response has already begun (it might affect the middleware server side).
In my own case for this, I concluded it was the wrong place to solve our issue, so I moved our necessary handling to a wrapper in the controller method return statement.
I.e. you then get
return wrapper(OK(response));
where wrapper will decide whether to pass on OK(..) unharmed.
If you use this approach, be careful if you had
return OK(responseWIthSideEffect(..));
in that case, you must make sure the side effect code is forced to execute,
before your wrapper makes its decision (i.e. assuming the wrapper checks something that might depend on that side effect).
Introduction
Currently I'm trying to create a Bot Framework application using the Microsoft Bot Framework v4.
Structure of program
We currently have the following setup:
The root of the bot class is named: SubDialogBotBot
Within the SubDialogBot we create a new Dialog named ParentDialog. This Dialog is responsible for reacting to a specific Intent.
We then start a new Dialog from the ParentDialog named ChildDialog. This child dialog will be responsible for asking the user a question based on arguments passed by ParentDialog.
After this question completed we want to return to the ParentDialog and continue the flow.
In this example we want to re-use the ChildDialog from all kinds of different intents as the code in here is exactly the same. The only thing that changes is the questions that have to be asked to the user.
Problem
When the ChildDialog completes the 'flow' is never returned to the ParentDialog.
We also tried to have the Dialog following after the ChildDialog ID set to something specific and then call this using Context.BeginDialog(....) from the ChildDialog. However because apparently the dialog was added to the ParentDialog and not to the ChildDialog it can't find this by the id.
Github repository reproducing the problem
https://github.com/devedse/SubDialogBotReproduction
First, this is an awesomely prepared question, thank you... especially for sharing the code.
Now, the good news is I don't think I see any problem with your dialogs. The problem is actually in your bot's OnTurnAsync. You are only ever calling BeginDialogAsync on your ParentDialog. Every single activity is going to come in through your OnTurnAsync and that means you're responsible for handling re-entrancy into the dialog stack. This means that, you need to check for an active dialog and, if there is one, you need to be calling ContinueDialogAsync instead to resume from where the discussion left off. Here's your current OnTurnAsync with the extra checks added:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
// Create a dialog context
var dc = await Dialogs.CreateContextAsync(turnContext);
// Handle Message activity type, which is the main activity type for shown within a conversational interface
// Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
// see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// If there's no active dialog, begin the parent dialog
if(dc.ActivDialog == null)
{
await dc.BeginDialogAsync(nameof(ParentDialog));
}
else
{
await dc.ContinueDialogAsync();
}
// Save the new turn count into the conversation state.
await _accessors.ConversationState.SaveChangesAsync(turnContext);
}
else
{
await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
}
}
I am currently developing an application in ASP.NET CORE 2.0
The following is the action inside my controller that get's executed when the user clicks submit button.
The following is the function that get's called the action
As a measure to prevent duplicate inside a database I have the function
IsSignedInJob(). The function works
My Problem:
Sometimes when the internet connection is slow or the server is not responding right away it is possible to click submit button more than once. When the connection is reestablished the browser (in my case Chrome) sends multiple HttpPost request to the server. In that case the functions(same function from different instances) are executed so close in time that before the change in database is made, other instances are making the same change without being aware of each other.
Is there a way to solve this problem on a server side without being to "hacky"?
Thank you
As suggested on the comments - and this is my preferred approach-, you can simply disable the button once is clicked the first time.
Another solution would be to add something to a dictionary indicating that the job has already been registered but this will probably have to use a lock as you need to make sure that only one thread can read-write at a time. A Concurrent collection won't do the trick as the problem is not whether this operation is thread-safe or not. The IsSignedInJob method you have can do this behind the scenes but I wouldn't check the database for this as the latency could be too high. Adding/removing a Key from a dictionary should be a lot faster.
Icarus's answer is great for the user experience and should be implemented. If you also need to make sure the request is only handled once on the server side you have a few options. Here is one using the ReaderWRiterLockSlim class.
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
This will prevent overlapping DoWork code. It does not prevent DoWork from finishing completely, then another post executing that causes DoWork again.
If you want to prevent the post from happening twice, implement the AntiForgeryToken, then store the token in session. Something like this (haven't used session in forever) may not compile, but you should get the idea.
private const SomeMethodTokenName = "SomeMethodToken";
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
var token = Request.Form.Get["__RequestVerificationToken"].ToString();
var session = Session[SomeMethodTokenName ];
if (token == session) return;
session[SomeMethodTokenName] = token
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
Not exactly perfect, two different requests could happen over and over, you could store in session the list of all used tokens for this session. There is no perfect way, because even then, someone could technically cause a OutOfMemoryException if they wanted to (to many tokens stored in session), but you get the idea.
Try not to use asynchronous processing. Remove task,await and async.
I'm trying to use this pre-made C# tftp server app with my windows c# form. In the authors server example, which works great, he uses a console app. When I trying porting his console example into my form app it doesn't work (no errors, just doesn't connect) and I believe my issue is in the "using" statement:
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Console.Read();
}
Not sure if I understand correctly but I believe the Console.Read() blocks keeping the app from exiting. If this is the case how would I implement a equivalent with a form app. I just can't get my head around the "using". Sorry I'm new to c#.
Windows Forms will always remain open until they're explicitly closed by the user. They always have a thread reading the message queue for user input, so they won't exit the same way an unrestrained console application will. In Windows Forms, we have to worry a bit more about multithreading and concurrency than we would in console apps. It mostly comes naturally, but not always.
Because of that, you can't really use an equivalent to Console.Read() to hold off execution of the using disposal until the user requests it. If you did, your form would simply appear unresponsive.
However, you're in luck! A using block in C# is nothing more than syntactic sugar for remembering to call IDisposable.Dispose() after you're done with an object. So the equivalent to this in a Forms project could just be storing the server object in a class-wide field, then calling server.Dispose() on, say, a Button.Click event. That's, of course, just an example. You could also do it on Form.Closing if that felt more appropriate.
High-level, you want to do something like this:
Declare a field in your form class TftpServer server;.
Register a Load event and whatever you need for your server to function in your constructor.
Open your server field in the Form_Load event.
Use the server's events as you see so fit during the life of your Form. You may or may not have to worry about concurrency, but that's a matter for another question.
Call server.Dispose() in the form's Dispose event.
In essence,
class main : Form
{
private TftpServer server;
public main()
{
InitializeComponent();
this.Load += main_Load;
server = new TftpServer();
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
}
private void main_Load(object sender, EventArgs e)
{
server.Start();
}
private void server_OnReadRequest(/* I wasn't sure of the arguments here */)
{
// use the read request: give or fetch its data (depending on who defines "read")
}
private void server_OnWriteRequest(/* I wasn't sure of the arguments here */)
{
// use the write request: give or fetch its data (depending on who defines "write")
}
protected override void Dispose(bool disposing)
{
if (server != null) // since Dispose can be called multiple times
{
server.Dispose();
server = null;
}
}
}
The problem is that disposing the server is what is closing it. Keep in mind using is just syntactic sugar. The following two code chunks are [practically] equivalent:
var foo = new Foo();
try
{
foo.Do();
}
finally
{
foo.Dispose();
}
using (var foo = new Foo())
{
foo.Do();
}
You are fine blocking the main thread from exiting in a Console app, but in a Forms app it's different. The problem is not that you need to hold the thread inside the using by doing some sort of blocking operation. That would be bad, and the behavior would lock up your forms app. The problem is you don't want to use using. You want to new it up when you start the server, and then later on, on application exit, or on a stop click, explicitly dispose it with Dispose().
In a console application your TftpServer instance is listening until the thread exits which is only after a key is pressed which is detected by Console.Read()
In your forms app that Console.Read() isn't waiting around and so the using block finishes and that causes your server instance to fall out of scope.
So you are not exactly misusing the using but rather the intended use is not helping you at all. Take a look at using the task parallel library to let some background tasks run asynchronously.
A small note that also doubles as an answer, you could use a using block here, you just put it in your main function:
...(make your form and stuff)
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Application.Run(yourFormHere); //This blocks until the form is closed
}
Another option I forgot to mention is overriding Dispose in your Form. You probably want to do this. With this option you're guaranteed your server will be disposed (bar some event that would prevent it from being disposed either way [ie. being out of memory])