How to exit an Async function from another class - vb.net

I have an Async method that does not end immediately after I close its user control. So, when I close and reopen it very fast, my user control gets errors. How could I exit that Async function from another class. Is that possible?
Public Class Main
Private Sub mainfucn()
'exit otherfunc
End Sub
End Class
Public Class Other
Public Async Function otherfunc() As Task
' some code
End Sub
End Class

Well, you could slum it by implementing your own cancellation system yourself. For instance, probably the simplest way to do something like that would be with some sort of cancellation flag property, like this:
Public Class Main
Private _other As New Other()
Private Sub MainFunc()
other.Cancelled = True
End Sub
End Class
Public Class Other
Public Property Cancelled As Boolean ' Yes, I know I'm not British, but the American spelling of "Canceled" is phonetically stupid. But, then again, so is the spelling of "British", so...
Public Async Function OtherFunc() As Task
Cancelled = False
While Not Cancelled
' Some code
End While
End Sub
End Class
However, that would be pretty terrible, so I wouldn't recommend it. The two primary reasons why it's terrible is because, One, it assumes that there's only ever one Async method and that there's only ever one invocation of it running at a time. And Two, it is inconsistent with the standard async cancellation patterns of .NET.
I would strongly recommend that, instead of attempting to do it with your own (anti-) pattern, you should add a CancellationToken parameter to your Async function. However, the way that you would implement that within the method all depends on what it is doing asynchronously and how it does it. So it's impossible to give you a single good example for how to accomplish that. The best thing I could say is, you were on the right track with using a CancellationToken, so you should keep going down that path. If, after doing more research, you aren't able to get it working, then I would recommend posting a more specific question regarding how to implement a CancellationToken within the context of what your method is doing and how it operates.

Related

VB.NET multithreading

I need to do a taks on a list of parameters: all those tasks are independant.
I don't see how to do it.. I tried to divide the parameters into one "shared class" and make a different instance of a class for each item in the list, and then launch the function on each instance asynchroneously :
Imports System.Runtime.InteropServices
Imports System.IO
Public Class DataContainer
Public Parameters as double 'obviously simplified code ;-)
End Class
Public Class JobDoer
Public CommonData As DataContainer
Public PrivData as double
Public Async Function YesWeCan() As Task(Of Boolean)
Return Task.Factory.StartNew(Of Boolean)(
DoIt(CommonData.Parameters , PrivData)
)
End Function
Public Function DoIt(a as double,b as double)
return 0
end function
End Class
==> Task is not defined...
.NET framework 3.0
VS 2015
Any ideas?
The Async and Await keywords are not available in .NET 3.0. They have been introduced in .NET 4.5, although you can already make use of them in 4.0 (with some modifications, like having to use TaskEx instead of Task for some of the static functions) if you import the Microsoft.Bcl.Async package via NuGet.
You can of course simply start new threads without having to use Async/Await.
Or you could use the ThreadPool. Here is some code I made back in the past, which was originally written in C#. I converted it now and removed the parts that would require at least .NET 4.0. Didn't test it, though.
Private Sub SubmitWorkToThreadPool()
For i as Integer = 0 To yourWorkItems.Count 'Adjust this loop so it adds all your tasks to the thread pool.
'customParameter is passed as parameter 'state' to the DoParallelWork function.
ThreadPool.QueueUserWorkItem(AddressOf DoParallelWork, customParameter)
Next
End Sub
Private Sub DoParallelWork(state As Object)
'TODO: Add code to be executed on the threadpool
End Sub
In the 4.0 version I had it written in a way that would allow me to wait for all work items to be completed after submitting it to the threadpool by using a CountdownEvent. But that class only exists since 4.0, so I removed it. You might have to find another way if you need to wait for everything to be done.

Can a CodeAnalysis return a false positive of CA2202? or is really something wrong with my code?

I'm suffering the same issue explained here but iterating a EnvDTE.Processes.
In the question that I linked the user #Plutonix affirms it is a false warning, and I think him reffers to the obj.Getenumerator() mention so I assume my problem will be considered a false warning too, however, if this is a false warning I would like to know more than an affirmation, the arguments to say it is a false warning.
This is the warning:
CA2202 Do not dispose objects multiple times Object
'procs.GetEnumerator()' can be disposed more than once in method
'DebugUtil.GetCurrentVisualStudioInstance()'. To avoid generating a
System.ObjectDisposedException you should not call Dispose more than
one time on an object.: Lines:
214 Elektro.Application.Debugging DebugUtil.vb 214
This is the code, procs object is the involved one on the warning, but I don't see any disposable object:
Public Shared Function GetCurrentVisualStudioInstance() As DTE2
Dim currentInstance As DTE2 = Nothing
Dim processName As String = Process.GetCurrentProcess.MainModule.FileName
Dim instances As IEnumerable(Of DTE2) = DebugUtil.GetVisualStudioInstances
Dim procs As EnvDTE.Processes
For Each instance As DTE2 In instances
procs = instance.Debugger.DebuggedProcesses
For Each p As EnvDTE.Process In procs
If (p.Name = processName) Then
currentInstance = instance
Exit For
End If
Next p
Next instance
Return currentInstance
End Function
PS: Note that the code-block depends on other members but they are unrelevant for this question.
Short version: this looks like a bug in the Code Analysis component to me.
Long version (hey, you suckered me into spending the better part of my afternoon and evening deciphering this, so you might as well spend a little time reading about it :) )…
The first thing I did was look at the IL. Contrary to my guess, it did not contain multiple calls to Dispose() on the same object. So much for that theory.
The method did, however, contain two separate calls to Dispose(), just on different objects. By this time, I was already convinced this was a bug. I've seen mention of CA2202 being triggered when dealing with related classes where one class instance "owns" an instance of the other class, and both instances are disposed. While inconvenient and worth suppressing, the warning seems valid in those cases; one of the objects really is getting disposed of twice.
But in this case, I had two separate IEnumerator objects; one did not own, nor was even related to, the other. Disposing one would not dispose the other. Thus, Code Analysis was wrong to warn about it. But what specifically was confusing it?
After much experimentation, I came up with this near-minimal code example:
Public Class A
Public ReadOnly Property B As B
Get
Return New B
End Get
End Property
End Class
Public Interface IB
Function GetEnumerator() As IEnumerator
End Interface
Public Class B : Implements IB
Public Iterator Function GetEnumerator() As IEnumerator Implements IB.GetEnumerator
Yield New C
End Function
End Class
Public Class C
Dim _value As String
Public Property Value As String
Get
Return _value
End Get
Set(value As String)
_value = value
End Set
End Property
End Class
Public Shared Function GetCurrentVisualStudioInstance2() As A
For Each a As A In GetAs()
For Each c As C In a.B
If (c.Value = Nothing) Then
Return a
End If
Next c
Next a
Return Nothing
End Function
Public Shared Iterator Function GetAs() As IEnumerable(Of A)
Yield New A()
End Function
This produces the same spurious CA2202 you are seeing in the other code example. Interestingly though, a minor change to the declaration and implementation of interface IB causes the warning to go away:
Public Interface IB : Inherits IEnumerable
End Interface
Public Class B : Implements IB
Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Yield New C
End Function
End Class
Somehow, Code Analysis is getting confused by the non-IEnumerable implementation of GetEnumerator(). (Even more weirdly is that the actual type you're using, the Processes interface in the DTE API, both inherits IEnumerable and declares its own GetEnumerator() method…but it's the latter that is the root of the confusion for Code Analysis, not the combination).
With that in hand, I tried to reproduce the issue in C# and found that I could not. I wrote a C# version that was structured exactly as the types and methods in the VB.NET version, but it passed Code Analysis without warnings. So I looked at the IL again.
I found that the C# compiler generates code very similar to, but not exactly the same as, the VB.NET compiler. In particular, for the try/finally blocks that protect the IEnumerator returned for each loop, all of the initialization for those loops is performed outside the try block, while in the VB.NET version the initialization is performed inside.
And apparently, that is also enough to prevent Code Analysis from getting confused about the usage of the disposable objects.
Given that it seems to be the combination of VB.NET's implementation of For Each and the nested loops, one work-around would be to just implement the method differently. I prefer LINQ syntax anyway, and here is a LINQified version of your method that compiles without the Code Analysis warning:
Public Shared Function GetCurrentVisualStudioInstance() As DTE2
Dim processName As String = Process.GetCurrentProcess.MainModule.FileName
Return GetVisualStudioInstances.FirstOrDefault(
Function(instance)
Return instance.Debugger.DebuggedProcesses.Cast(Of EnvDTE.Process).Any(
Function(p)
Return p.Name = processName
End Function)
End Function)
End Function
And for completeness, the C# version (since all of this code started when a C# implementation was converted to VB.NET and then extended to handle the "current instance" case):
public static DTE2 GetCurrentVisualStudioInstance()
{
string processName = Process.GetCurrentProcess().MainModule.FileName;
return GetVisualStudioInstances()
.FirstOrDefault(i => i.Debugger.DebuggedProcesses
.Cast<EnvDTE.Process>().Any(p => p.Name == processName));
}

how can we call ninjects service locator in code?

first time on stackoverflow + ninject (IoC's)
I have a situation in which I have Business Objects Implemented in a way that they have Models in them... i.e.
Public Class Whatever
Implements IWhatEver
Public Property Id as Integer
Public Property Name as String
Public Function SetWhatEver() as Whatever
'Do Whatever Settings
End Function
End Class
I am using ninject for DI (Dependency Injection) however the issue was that I couldn't use an Interface as a model being passed in an action, therefore I am trying to make a custom modelbinder and want to use the bindingContext.ModelType to pass to ninject and ninject to resolve it for me and so I can do my binding with metadata
Public Overrides Function BindModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As Object
Dim modelType = ninjectPleaseResolve(bindingContext.ModelType)
Dim metaData = ModelMetadataProviders.Current.GetMetadataForType(Nothing, modelType)
bindingContext.ModelMetadata = metadata
Return MyBase.BindModel(controllerContext, bindingContext)
End Function
I hope this makes sense... I have tried looking for answers BTW and nothing online is making sense to me, so please can you explain in simple terms..
EDIT
I am adding the controller code below to give you a better understanding of what I am trying to do.. I don't want to use the Whatever class instead I want to use the IWhatever in the controller for my processing... please see below an example...
Public Class MainController
Inherits System.Web.Mvc.Controller
Dim repository As IWhatever
Public Sub New(pWhatever As IWhatever)
repository = pWhatever
End Sub
Function Index(myValues As IWhatever) As ActionResult
'So I can process these values to my liking...
repository.SetWhatEver(myValues)
' and then perhaps other functions like...
repository.Save()
Return View()
End Function
I hope this makes a little sense now..
the issue was that I couldn't use an Interface as a model being passed
in an action
You shouldn't pass in services through the action method. You should pass services in through the constructor. This way your container can build up the controller and all related objects for you and this way you don't have to write a custom model binder.

Threading: Call a delegate from a separate thread (VS2010)

So, I'm having troubles implementing a separate thread. This is because I have a simple class, and in it I start a new thread. So, as it is not any form, I haven't found any way to make it call the function in the UI Thread.
So, I cannot use the Invoke method. Is there any way to call a function from another thread?
I am going to assume that you have events exposed from your class and that you want the event handlers to execute on a UI thread. I suppose you could have a callback that the caller specifies as well. Either way the pattern I will describe below will work in both cases
One way to make this happen is to have your class accept an ISynchronizeInvoke instance. Form and Control instances implement this interface so a reference to one of them could be used. You could make it a convention that if the an instance is not specified then event handlers executed by raising events on your class would execute in the worker thread instead of the thread hosting the ISynchronizeInvoke instance (usually a form or control).
Public Class YourClass
Private m_SynchronizingObject As ISynchronizeInvoke = Nothing
Public Sub New(ByVal synchronizingObject As ISynchronizeInvoke)
m_SynchronizingObject = synchronizingObject
End Sub
Public Property SynchronizingObject As ISynchronizeInvoke
Get
Return m_SynchronizingObject
End Get
Set(ByVal value As ISynchronizeInvoke)
m_SynchronizingObject = value
End Set
End Property
Private Sub SomeMethodExecutingOnWorkerThread()
RaiseSomeEvent()
End
Private Sub RaiseSomeEvent()
If Not SychronizingObject Is Nothing AndAlso SynchronizingObject.InvokeRequired Then
SynchronizingObject.Invoke(New MethodInvoker(AddressOf RaiseSomeEvent)
End If
RaiseEvent SomeEvent
End Sub
End Class
The first thing to notice is that you do not have to specify a synchronizing object. That means you do not have to have a Form or Control reference. If one is not specified then SomeEvent will be raised on the worker thread. This is the same pattern that is used in the System.Timers.Timer class.
Try to expose some events in your class, fire them when you need to notify your UI and finally make your UI Component register to these events,
when the event is fired, the listener methods will be executed. there you can use Control.Invoke or Control.BeginInvoke to execute your code on the UI thread.

Wrap Sub as Function for use in Lambda

I have a problem with VB9 and Moq.
I need to call a verify on a Sub. Like so:
logger.Verify(Function(x) x.Log, Times.AtLeastOnce)
And my logger looks like this:
Public Interface ILogger
Sub Log()
End Interface
But with VB this is not possible, because the Log method is a Sub, and thereby does not produce a value.
I don't want to change the method to be a function.
Whats the cleanest way of working around this limitation and is there any way to wrap the Sub as a Function like the below?
logger.Verify(Function(x) ToFunc(AddressOf x.Log), Times.AtLeastOnce)
I have tried this, but i get:
Lambda Parameter not in scope
VB10 allows for the usage of Lambada Subs.
Have you tried a simple wrapper, such as:
Public Function Wrapper(source as Action) as Boolean
source.Invoke()
Return True
End Function
In 2010 if its a Sub and not a Function just replace Function with Sub.
logger.Verify(Sub(x) x.Log, Times.AtLeastOnce)