I have two calls to my server application. One is normal Invoke method and another is InvokeAsync method. We are using HttpWebRequestCompressed code as well with request.Headers.Add("Accept-Encoding", "gzip, deflate").
Invoke method
<System.Web.Services.Protocols.SoapDocumentMethodAttribute("://abc.com/myApp/WS/OpenAllSupplier", RequestNamespace:="://abc.com/myApp/WS", ResponseNamespace:="://abc.com/myApp/WS", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _
Public Function OpenAllSupplier() As dsSupplier
Dim results() As Object = Me.Invoke("OpenAllSupplier", New Object(-1) {})
Return CType(results(0),dsSupplier)
End Function
Invoke Async method
Public Overloads Sub OpenSupplierAsync(ByVal buCode As String, ByVal buType As String, ByVal userState As Object)
If (Me.OpenSupplierOperationCompleted Is Nothing) Then
Me.OpenSupplierOperationCompleted = AddressOf Me.OnOpenSupplierOperationCompleted
End If
Me.InvokeAsync("OpenSupplier", New Object() {buCode, buType}, Me.OpenSupplierOperationCompleted, userState)
End Sub
Private Sub OnOpenSupplierOperationCompleted(ByVal arg As Object)
If (Not (Me.OpenSupplierCompletedEvent) Is Nothing) Then
Dim invokeArgs As System.Web.Services.Protocols.InvokeCompletedEventArgs = CType(arg,System.Web.Services.Protocols.InvokeCompletedEventArgs)
RaiseEvent OpenSupplierCompleted(Me, New OpenSupplierCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState))
End If
End Sub
WebRequest Class
Partial Public Class BusinessUnits
Inherits System.Web.Services.Protocols.SoapHttpClientProtocol
Protected Overrides Function GetWebRequest(ByVal uri As Uri) As System.Net.WebRequest
Try
'System.Net.HttpWebRequest.Create(uri) '
Dim request As HttpWebRequest = CType(MyBase.GetWebRequest(uri), HttpWebRequest)
request.Headers.Add("Accept-Encoding", "gzip, deflate")
Return New HttpWebRequestCompressed(request)
Catch ex As Exception
End Try
End Function
End Class
In HttpWebRequestCompressed class
Public Class HttpWebRequestCompressed
Inherits System.Net.WebRequest
Dim request As HttpWebRequest
Public Sub New(ByVal request As WebRequest)
Me.request = CType(request, HttpWebRequest)
End Sub
Public Overrides Function GetResponse() As WebResponse
Return New HttpWebResponseDecompressed(Me.request)
End Function
Public Overrides Function GetRequestStream() As Stream
Return New GZipStream(Me.request.GetRequestStream(), CompressionMode.Compress)
End Function
GetRequestStream executes only when Invoke method calls.
Invoke method is working as expected and no issues.
On Invoke Async the call is not going to Server, and we are getting error in client side as,
"This method is not implemented by this class."
What exactly I am missing here in Async call? Unable to get the method invoke in server only when Async call is happening.
Thank you for supporting.
Regards
Sangeetha
Related
I have a function that check validity of inserted data of a form, and in this function I have to ask some confirmation from user, and this confirmation need to be asked outside of the function, so if I hit one of this confirmations, I create the message and send out the validation function, user confirms or not and the function would called again
so here is the problem: I need to put some checkpoints in my function so when I call the validation function I jump to that checkpoint with the selected confirmation from user and run the validation function from that checkpoint
1: is this possible at all?
2: any ideas to do this?
Edit 1: I'm doing this validation in my business layer and can not show any message boxes from there, I just create the message and return it to the UI layer and the answer get from the user and function call again with this answer but I don't want to run the function from beginning and need to run it from where I left
Public Class BL
Private Queue As Queue(Of String)
Public Sub New()
Dim checkpoints = New String(){"CheckPoint1","CheckPoint2","CheckPoint3"}
checkpoints.ToList.ForEach(Function(item) <b>Queue.Enqueue(item)</b>)
End Sub
Public Function Func(ByVal res As Response,ParamArray ByVal params As String()) As Response
Dim response As Response
Dim chk = Queue.Dequeue()
GoTo chk
CheckPoint1:
'Do some stuff
response = New Response(Response.ResponseType.Message,"Are you sure you wanna do this?")
Return response
CheckPoint2:
If(res.Type = Response.ResponseType.ResponseBack)
Dim r As DialogResult = Convert.ChangeType([Enum].Parse(GetType(DialogResult),res.Message),GetType(DialogResult))
If (r= DialogResult.OK)
'Do stuffs on DialogResult.Yes
Else
'Do stuffs on DialogResult.No
End If
'Do other stuffs with database
End If
' Do other stuff
response = New Response(Response.ResponseType.Message,"You should do this!!OK?")
Return response
CheckPoint3:
'Do stuff like CheckPoint1
End Function
End Class
Public Class Response
Friend Enum ResponseType
Message
Result
ResponseBack
None
End Enum
Friend Message As String
Friend Type As ResponseType
Friend Sub New(ByVal type As ResponseType,msg As String)
Message=msg
Type= type
End Sub
End Class
Public Class Form1
Public Sub New()
' This call is required by the designer.
InitializeComponent()
Dim BL As New BL()
' Add any initialization after the InitializeComponent() call.
Dim rese As Response
Do
rese =BL.Func(Nothing)
BL.Func(new Response(Response.ResponseType.ResponseBack,if(MessageBox.Show(rese.Message).ToString())))
Loop Until rese.Type <> Response.ResponseType.Result
MessageBox.Show(if(rese.Message="True","OK","ERROR"))
End Sub
End Class
This is not an objective answer but could help. You need some sort of class that contains question and answers. Your validation class would return a list of question (are you sure?).
Class ValidationOutput
ValidationId
Message
Result
End Class
After calling your validation function, you get a list of validation that need extra information from the user. This can be handle outside of the validation function. When you get the extra information, call the validation again and pass the same list as parameter. When validating, look at the list to see if all the extra information needed is there.
I believe your business logic should not deal with user interactions and split to two parts.
However, if you prefer this way, you can use callbacks. Define a delegate parameter for your validation/business method and call that delegate when you need confirmation. According to return value continue to save operation or not.
You can check link below for delegate passing to a method.
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/delegates/how-to-pass-procedures-to-another-procedure
This should work for you:
Public Class BL
Private Queue As Queue(Of String)
Private _checkpoints As Dictionary(Of String, Func(Of Response, Response)) = New Dictionary(Of String, Func(Of Response, Response)) From
{
{ "CheckPoint1", Function (res) New Response(Response.ResponseType.Message, "Are you sure you wanna do this?") },
{ "CheckPoint2", Function (res)
If (res.Type = Response.ResponseType.ResponseBack)
Dim r As DialogResult = CType(Convert.ChangeType([Enum].Parse(GetType(DialogResult), res.Message), GetType(DialogResult)), DialogResult)
If (r = DialogResult.OK)
'Do stuffs on DialogResult.Yes
Else
'Do stuffs on DialogResult.No
End If
'Do other stuffs with database
End If
' Do other stuff
Return New Response(Response.ResponseType.Message, "You should do this!!OK?")
End Function
},
{ "CheckPoint3", Function (r) New Response(Response.ResponseType.Message, "Are you sure you wanna do this?") }
}
Public Sub New()
_checkpoints.ToList().ForEach(Sub(item) Queue.Enqueue(item.Key))
End Sub
Public Function Func(ByVal res As Response, ParamArray ByVal params As String()) As Response
Dim chk = Queue.Dequeue()
Return _checkpoints(chk).Invoke(res)
End Function
End Class
Basically this creates a Dictionary(Of String, Func(Of Response, Response)) that maps a String to a Func(Of Response, Response) that returns the Response that you want.
There would be a couple of variations on this that might suit you better, but perhaps you could let me know if this does the job or not for you and I could suggest other options if need be.
Public Class LoginManager
Implements ILoginManager
Private ReadOnly _iLoginRepository As ILoginRepository
Public Sub New()
_iLoginRepository = New LoginRepository()
End Sub
Public Async Sub InsertFailedLoginAttempt(failedLoginAttempt As FailedLogin) Implements ILoginManager.InsertFailedLoginAttempt
'Example of the S in Solid (Single Repsonsibilty)
'Need to call these method async. But await errors
_iLoginRepository.InsertFailedLoginAttemptAsync(failedLoginAttempt)
_iLoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt)
End Sub
End Class
Repsoitory Interface:
Public Interface ILoginRepository
Function IsUserAuthenticatedAsync(ByVal cID As String, ByVal password As String, ByVal IsExternalUser As Boolean) As Task(Of Boolean)
Sub InsertFailedLoginAttemptAsync(ByVal failedLoginAttempt As FailedLogin)
Sub InsertFailedLoginAttemptIntoLoginMasterAsync(ByVal failedLoginAttempt As FailedLogin)
End Interface
Repository Implementation:
Public Class LoginRepository
Implements ILoginRepository
Public ReadOnly _applicationDBContext As New ApplicationDBContext()
Public Async Sub InsertFailedLoginAttemptAsync(failedLoginAttempt As FailedLogin) Implements ILoginRepository.InsertFailedLoginAttemptAsync
Using _applicationDBContext
_applicationDBContext.RepFailedLogins.Add(failedLoginAttempt)
Await _applicationDBContext.SaveChangesAsync()
End Using
End Sub
Public Async Sub InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt As FailedLogin) Implements ILoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync
Using _applicationDBContext
_applicationDBContext.RepFailedLoginMasters.Add(failedLoginAttempt)
Await _applicationDBContext.SaveChangesAsync()
End Using
End Sub
''' <summary>
''' Determine whether a user is authenticated, be it an internal or external user
''' I have condensed two methods into one
''' </summary>
''' <param name="cID"></param>
''' <param name="password"></param>
''' <param name="IsExternalUser"></param>
''' <returns></returns>
Public Async Function IsUserAuthenticatedAsync(cID As String, password As String, IsExternalUser As Boolean) As Task(Of Boolean) Implements ILoginRepository.IsUserAuthenticatedAsync
If (IsExternalUser And String.IsNullOrEmpty(password)) Then
Throw New ArgumentNullException("External user requires password")
End If
Dim user As Chaser
Dim toRet As Boolean
Using _applicationDBContext
'Two ways to use LINQ
'First is LINQ Lambda sybntax(little harder to read)
user = Await _applicationDBContext.Chasers.Where(Function(x) x.CID = cID).FirstOrDefaultAsync()
'Second is LINQ Query syntax(looks more like SQL just more verbose
'user = From x In _applicationDBContext.Chasers
' Where x.CID = cID
' Select x
End Using
If IsNothing(user) Then
toRet = False
ElseIf Not IsExternalUser And Not IsNothing(user) Then
toRet = True
ElseIf IsExternalUser And user.Hash_Password = password Then
toRet = True
End If
Return toRet
End Function
End Class
I'm trying to call the InsertFailedLoginAttemptAsync repository method in my manager. It is an async method but I am unable to await the method. How can I make this method awaitable?
I believe it has something to do with the interface and not making it an async method like in C# but I'm unable to do this.
Subs should not be async. Event handlers are the only exception to that rule. You await Task which can only be returned from a Function. If the intention is to make that interface async then all the members need to be functions that return a Task or its derivative.
Async is something that bubbles all the way through when used. That said the ILoginManager along with the ILoginRepository should be refactored (if possible) to follow the proper syntax.
Reference: Async/Await - Best Practices in Asynchronous Programming
Fixed via Nkosi's reply:
Interface:
Public Interface ILoginRepository
Function IsUserAuthenticatedAsync(ByVal cID As String, ByVal password As String, ByVal IsExternalUser As Boolean) As Task(Of Boolean)
Function InsertFailedLoginAttemptAsync(ByVal failedLoginAttempt As FailedLogin) As Task
Function InsertFailedLoginAttemptIntoLoginMasterAsync(ByVal failedLoginAttempt As FailedLogin) As Task
End Interface
Manager method:
Public Async Function InsertFailedLoginAttempt(failedLoginAttempt As FailedLogin) As Task Implements ILoginManager.InsertFailedLoginAttempt
'Example of the S in Solid (Single Repsonsibilty)
Await _iLoginRepository.InsertFailedLoginAttemptAsync(failedLoginAttempt)
Await _iLoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt)
End Function
I am trying to build a new class from where I can call functions with a background worker from a web service in a windows Phone 8.1 silverlight app.
calling page
LoginPage.xaml.vb
Partial Public Class LoginPage
Private sub Logon()
WebServiceHelper.a(WebServiceHelper.Functions.Logon)
LoginFinish()
End Sub
End Class
WebserviceHelper
WebServiceHelper.vb
Public Class WebServiceHelper
Public Shared Sub a(ByVal _Task As Functions)
If _Task = Functions.Logon Then
_Service.BeginLogonWindowsPhone(usr, pass, New AsyncCallback(AddressOf ResultBackGroundTask), result)
End If
End Sub
Public Shared Sub ResultBackGroundTask(ByVal result As Object)
If _Task = Functions.Logon Then
ResultObject = result
End If
End Sub
End Class
The problem is when I call webservice.a() the AsyncCallback ResultBackGroundTask doesn’t fire in time. Instead LoginFinish is called resulting in an error because the resultobject isn’t initialized yet.
I've tried:
Task.Factory.FromAsync(_Service.BeginLogonWindowsPhone, ResultBackGroundTask, usr, pass, Nothing)
But I get an error:
Argument not specified for parameter 'asyncState' of
'Public Function BeginLogonWindowsPhone(userName As String, password As String, callback As System.AsyncCallback, asyncState As Object) As System.IAsyncResult'.
The function I try to call is:
<System.ServiceModel.OperationContractAttribute(AsyncPattern:=true, Action:="http://test.com/LogonWindowsPhone", ReplyAction:="*"), _
System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults:=true)> _
Function BeginLogonWindowsPhone(ByVal userName As String, ByVal password As String, ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
This function is automatically generated in the webservice reference.
I use the Webservice to connect with the clients database, for security reasons.
An example: http://msdn.microsoft.com/en-us/library/gg328075.aspx
I am looking to design a request and response system for a project. The request and responses are both classes.
I don't use interfaces because I do use Command by its self.
Example of use:
dim result as Response = ExecuteCommand(of Response)(new Read())
dim result as DiffResponse = ExecuteCommand(of DiffResponse)(new Read())
Example of design:
Class Command
Private buffer as new List(of byte)
Sub New(byval command As byte)
buffer.add(command);
End Sub
Overrideable get_request() As byte()
Return buffer.toarray
End Function
End Class
Class Read
Inherits Command
Sub New()
MyBase.New(&h01)
End Sub
End Class
Class Response
Private buffer As New List(Of Byte)
Sub New(ByVal data() As Byte)
{
buffer.addrange(data)
}
End Class
Now I want to be able to have multiple types of Response so example:
Class DiffResponse
Inherits Response
Sub New(data As Bytes())
MyBase.new(data)
' Custom processing
End Sub
End Class
The DiffResponse class might have custom getter functions and variables.
Presently I do something like this:
Public Function ExecuteCommand(Of response)(ByVal command As Command) As response
Return GetType(response).GetConstructor(New Type() {GetType(Byte())}).Invoke(New Object() {Me.WritePacket(command.get_request)})
End Function
Is this the best way of doing it?
In C#, I can do this:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Class1 c1 = new Class1();
c1.OnNeedInt += new Class1.NeedInt(c1_OnNeedInt);
int i = c1.GetInt();
}
int c1_OnNeedInt()
{
return 1;
}
}
public class Class1
{
public delegate int NeedInt();
public event NeedInt OnNeedInt;
public int GetInt()
{
return OnNeedInt == null ? 0 : OnNeedInt();
}
}
Notice the line int i = c1.GetInt();. I can't seem to get VB.NET 4.0 to do something similiar. Any help?
I thinks its even easier than most people think...
Class MyClass
Public Event MyEvent(ByRef MyVariable as String)
Private Sub DoSomething()
Dim SomethingINeed as String = String.Empty
RaiseEvent MyEvent(SomethingINeed)
'SomethingINeed will now contain "Goodbye Cruel World"
End sub
End Class
Then in the class that monitors the event...
Class MyOtherClass
Private Sub New()
AddHandler MyClass.MyEvent, Addressof MyEventHandler
End Sub
Private Sub MyEventHandler(ByRef StringToPassBack as String)
StringToPassBack = "Goodbye Cruel World"
End Sub
End Class
It's all about the ByRef keywords in both the event declaration and the eventhandler sub.
That's not possible in vb.net, events must be raised with the RaiseEvent statement. It doesn't return a value. It is a pretty questionable practice anyway, an event can have zero or multiple subscribers. No telling what the return value might be. Just use a delegate instead:
Class Page
Public Sub New()
Dim obj As New Class1
Dim dlg As New Func(Of Integer)(AddressOf obj.GetInt)
Dim i As Integer = dlg()
End Sub
End Class
Class Class1
Public Function GetInt() As Integer
Return 42
End Function
End Class
In VB, you don't need to check to see if anyone is attached to your event handler. You can just call RaiseEvent and if anyone is listening to it, it will work. However, the event isn't intended to return a value. You could try sticking it into an event arg and pass that around, but that gets messy.
#HansPassant's solution is close, but not quite what you were asking for. Altering his solution a bit:
Delegate Function FetchIt() As Integer
Class Page
Public Sub New()
Dim obj As New Class1
Dim i As Integer = obj.GetInt(AddressOf c1_OnNeedInt)
End Sub
Function c1_OnNeedInt() As Integer
Return 42
End Function
End Class
Class Class1
Public Function GetInt(fetcher As FetchIt) As Integer
Return fetcher()
End Function
End Class
Alternatively, you could do this without the custom delegate using Lambda's:
Class Page
Public Sub New()
Dim obj As New Class1
Dim dlg As New Func(Of Integer)(AddressOf c1_OnNeedInt)
Dim i As Integer = obj.GetInt(dlg)
End Sub
Function c1_OnNeedInt() As Integer
Return 42
End Function
End Class
Class Class1
Public Function GetInt(fetcher As Func(Of Integer)) As Integer
Return fetcher()
End Function
End Class
I found an answer to my issue. In the base class that my ASP.NET user controls inherit, I have this:
Dim _Connection As MyConnection
Public Property Connection As MyConnection
Get
If _Connection Is Nothing Then
RaiseEvent OnNeedConnection(_Connection)
End If
Return _Connection
End Get
Set(value As MyConnection)
_Connection = value
End Set
End Property
Public Delegate Sub NeedConnection(ByRef Connection As MyConnection)
Public Event OnNeedConnection As NeedConnection
In my web form codebehind, I wire it up manually to this:
Sub ServeConnection(ByRef Connection As MyConnection)
Connection = oConn
End Sub
The actual connection is hosted on the webform's codebehind, but I have several user controls that need to use this connection. Any time any of the user controls need the connection, their base class requests it and the host page serves it. This is made possible by the ByRef keyword.
This is the closest C# equivalent I could put together.