|
I looked different section sorry.
modified 20-Sep-20 21:01pm.
|
|
|
|
|
For continuations, I find it best to use the explicit continuation that suits that particular status. So, your tasks would look something like this:
Task task = Task.Factory.StartNew(() =>
{
service.Start();
}, TaskCreationOptions.LongRunning, service.CancellationTokenSource.Token);
task.ContinueWith(antecedent => { AddStatus(string.Format("Service '{0}' completed", service.ServiceId)) }, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(antecedent => { AddStatus(string.Format("Service '{0}' cancelled", service.ServiceId)) }, TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(antecedent => {
AddStatus(string.Format("Service '{0}' errored", service.ServiceId));
AddStatus(task.Exception.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(antecedent => {
App.Current.Dispatcher.Invoke(() =>
{
Services.Remove(SelectedService);
SelectedService = null;
AddStatus("Removed from the dispatcher");
});
_services.Remove(service);
});
This space for rent
|
|
|
|
|
Pete O'Hanlon wrote: For continuations, I find it best to use the explicit continuation that suits that particular status.
OK. Why? What benefit does it provide? Your example doesn't seem to do anything different than what mine does, unless I'm just not seeing something.
Also, this change doesn't solve my issue.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
To answer your questions back to front - did you read the code comment in the last task continuation? This one: // If you haven't reached this point, then you don't have a current App Dispatcher.. If you don't see the message immediately after, it means your App.Current.Dispatcher has gone.Kevin Marois wrote: What benefit does it provide? There are a few reasons I prefer this approach. Here are some of them:
- I can have my tasks attached to different schedulers - some of the stuff I deal with uses very complex scheduling.
- I'm not mixing code. Each continuation has a single responsibility
- This makes it very easy for me to provide general purpose continuation handlers - for instance, I could have a single OnlyOnFaulted handler that any Task calls.
- This reduces the cyclomatic complexity of your code
Here's an example of the last point
public static class TaskExtensions
{
public static void OnFaulted(this Task task)
{
task.ContinueWith(()=>{ }, TaskContinuationOptions.OnlyOnFaulted);
}
} Calling this becomes as simple as
Task.Factory.StartNew(()=> { }).OnFaulted(); Granted, a single use of this doesn't do much but when you have multiple calls of the same type, this makes things a lot neater.
This space for rent
|
|
|
|
|
Excellent explantion. Thank you. I'm still fairly new to Tasks/threading, so I like deep explantions.
As far as the Dispatcher goes, no I'm sorry I totally missed that comment. So how to I solve my issue of reaching back into the UI?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
BTW, this doesn't compile:
Task task = Task.Factory.StartNew(() =>
{
service.Start();
}, TaskCreationOptions.LongRunning, service.CancellationTokenSource.Token);
I get
Delegate 'Action<object>' does not take 0 arguments
If I remove the "TaskCreationOptions.LongRunning" part then it compiles.
Not sure what's wrong here.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Pete O'Hanlon wrote: // If you haven't reached this point, then you don't have a current App Dispatcher...
OK, so I now have
Task task = Task.Factory.StartNew(() =>
{
service.Start();
}, service.CancellationTokenSource.Token);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' completed", service.ServiceId));
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' cancelled", service.ServiceId));
}, TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' errored", service.ServiceId));
AddStatus(task.Exception.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(antecedent => {
App.Current.Dispatcher.Invoke(() =>
{
Services.Remove(SelectedService);
SelectedService = null;
AddStatus("Removed from the dispatcher");
});
_services.Remove(service);
});
}
In my Service class to test the faulted state I do a
throw null;
Both the ContinueWith for OnlyOnFaulted AND the code inside the Dispatcher are being hit, yet the Services.Remove doesn't remove the item.
As far as the "If you haven't reached this point, then you don't have a current App Dispatcher..".... my code DOES reach that point even when faulted.. the Services.Remove just doesn't remove the item.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 11-Apr-17 12:02pm.
|
|
|
|
|
The other thought that occurs to me is that SelectedService isn't what you think it is - you're going to have to put a breakpoint on the line you're removing it and see what it is. If it's not the instance that's in the list, you're not going to be able to remove it.
This space for rent
|
|
|
|
|
You know what, you're right. I changed this
Services.Remove(SelectedService);
to
var serviceModel = Services.FirstOrDefault(x => x.ServiceId == service.ServiceId);
Services.Remove(serviceModel);
and it works
Thanks Pete!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
You're welcome. Glad you got it sorted.
This space for rent
|
|
|
|
|
OK, one more thing. I now have this
private void AddService()
{
MyService service = new MyService();
_services.Add(service);
service.StatusChanged += Service_StatusChanged;
AddStatus(string.Format("Service '{0}' created", service.ServiceId));
Task task = Task.Factory.StartNew(() =>
{
service.Start();
}, service.CancellationTokenSource.Token);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' completed", service.ServiceId));
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' cancelled", service.ServiceId));
}, TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(antecedent =>
{
AddStatus(string.Format("Service '{0}' errored", service.ServiceId));
AddStatus(task.Exception.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(antecedent =>
{
App.Current.Dispatcher.Invoke(() =>
{
var serviceModel = Services.FirstOrDefault(x => x.ServiceId == service.ServiceId);
Services.Remove(serviceModel);
SelectedService = null;
AddStatus("Service removed");
});
_services.Remove(service);
});
}
As you know, I'm storing my services in a list called "_services". Works great. I also have a Stopped method:
private void Stopped()
{
IsStopped = true;
foreach (var service in _runningServices)
{
service.Stop();
}
_runningServices.Clear();
}
Given how I'm storing the service instances, how can I tell when all have finally stopped? I see this but I'm not sure this is what I want.
Bear in mind that new tasks can be started and added to the _services collection at any time. The Stopped sets IsStopped to True, after which no new services can start. But there could be any number of services running that have yet to complete.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 12-Apr-17 13:04pm.
|
|
|
|
|
Use the ServiceController[^] class. Using a combination of GetServices and Status , you can find the state of your services. However, as a trick, what I would do is, immediately before you call the Stop method in your code, call the WaitForStatus[^] method on the service and tell it to wait for it to be stopped.
This space for rent
|
|
|
|
|
I think you misunderstood my question.
I'm not trying to determine when the Windows Service is stopped... I want to know when all TASKS I created have stopped.
Review
My app will allow me to run code defined in separate assemblies (services). The host is a Windows Service. On start it loads classes from a manifest and creates instances of these classes (a service) and runs the Start method in a separate thread.
At any point a "service" could be loaded or removed. The Windows Service will always be running, but there could be any number of service threads running in it at any time. I add a new service like this (which you already helped me with)
private void AddService()
{
MyService service = new MyService();
_services.Add(service);
Task task = Task.Factory.StartNew(() =>
{
service.Start();
}, service.CancellationTokenSource.Token);
}
Problem
Because I can add new service classes at any time, meaning install an assembly, create an instance of a type in it, and run its Start method in a new thread, how can I reliably know when ALL threads that I stated are stoppped?
Solution?
I looked at Task.WhenAll. To use this I would need to store each Task I create in a list. Then, later, in StopAllServices, I would have:
public void StopAllServices()
{
foreach (var service in _services)
{
service.Stop();
}
Task waitAllTask = Task.WhenAll(_tasks.ToArray());
try
{
waitAllTask.Wait();
}
catch { }
}
The problem is, what keeps waitAllTask in scope? Can I just store it as a class field?
When a new service is added (and run in another new Task), how does it get included in the WaitAll array? if I am continually added new Tasks to the waitAll array, will Task.WaitAll handle it? Also, isn't WaitAll a blocking call?
Is there a better approach to this?
Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have used minimalistic library for telnet automation. For this i need to read input dynamically from an external XML file.
|
|
|
|
|
Interesting; do you have a question?
|
|
|
|
|
You'll need some form of XML reader then. .NET provides a few choices now.
This space for rent
|
|
|
|
|
I need to make the buttons events of the form designer (form1.designer.cs) be activated in a different class other than form1.cs. I do this to have a class that activates standard form buttons for different programs and does not have to repeat code. For this, For the event to be activated in the Cls_StandardEventos class, i have introduced lines as:
This._Main_Nv2MedioDerSuperTabControl.TabMoved + = new System.EventHandler (Name_StandardEventos.Cls_StandardEventos.Fcn_Tab_Nv2MedioDerSuperTabControl_TabMoved);
form1.designer.cs does not display red error line but I can not see the design view of the form because it shows the error that does not find Name_StandardEventos.Cls_StandardEventos in the assembly.
On the other hand, in Visual Studio 2017 I have seen enough things to improve. I am surprised that in Microsoft work so many people and they are all so ready and yet so many defects are easily visible. One problem is that if you modify something in one class and switch to another class, it takes a long time to notice the changes. It is a problem, because you can see a red line of error for quite some time and you are left wondering what the problem is and suddenly it is solved because it has detected the change. I can find dozens of suggestions to make easily but the years pass and from one version to another things do not improve.
|
|
|
|
|
Then you should send your complaint to Microsoft.
|
|
|
|
|
A lame computer produces a lame Visual Studio experience.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I think you do have a valid technical question here, but you need to state what it is more clearly; going on about the speed of VS is not going to get you to a solution.
A way I handle event triggers across Forms is something like this:
1. Define an Action public field in the Form you want to raise an Event, but have the Event handled in another Form:
public Action<Button> BtnAction = null; 1.a. define the Button's Click EventHandler, and modify it to invoke the BtnAction:
private void SomeButton_Click(object sender, EventArgs e)
{
if(BtnAction != null) BtnAction(sender as Button);
} 2. in the Form that creates the instance of 'FormWithBtn ... for example, the Main Form
private FormWithButton FWBInstance = new FormWithButton();
private void Form1_Load(object sender, EventArgs e)
{
FWBInstance.BtnAction = FWBButtonHandler;
}
private void FWBButtonHandler(Button btn)
{
} This "model" of creating Event handling across Forms uses "injection" of an Action (a form of delegate), and it avoids dependency creation between the two contexts (Forms) ... imho, a good thing.
Hope this helps.
«When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal
|
|
|
|
|
Regequion wrote: One problem is that if you modify something in one class and switch to another class, it takes a long time to notice the changes. It is a problem, because you can see a red line of error for quite some time and you are left wondering what the problem is and suddenly it is solved because it has detected the change. I can find dozens of suggestions to make easily but the years pass and from one version to another things do not improve. This is because there is a compilation process silently running in the background to see if the changes you are making are correct (this has been the way for a long time now); meaning that you need to wait for the compile cycle to start and complete before you can be 100% certain that things are okay.
This space for rent
|
|
|
|
|
Hi
I An application built with vs2013. And setup file with installshield le from vs2013 did create.
After installing the app when I click on the desktop shortcut application that gives this error:
unable to open the physical file
"c:\Windows\system32\database.mdf".Operating system error 2:
"2(The system cannot find the file specified.)"
changed database context to 'master'
Please help to solve this error
|
|
|
|
|
mahdiiiiyeh wrote: "2(The system cannot find the file specified.)" What part of that message do you not understand?
|
|
|
|
|
|
OK, and what do you still not understand about "file not found"?
|
|
|
|
|