Using VS 2010, VB.NET, HTTPClient, .NET 4.0, and Windows Forms.
I am trying to get a windows application to consume JSON coming from a Web API that I have created. Web API works great and I can view the results from a browser. Found this article that I have been trying to get working only using VB.NET instead of C#.
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-wpf-application
The critical part of the code is this function:
private void GetProducts(object sender, RoutedEventArgs e)
{
btnGetProducts.IsEnabled = false;
client.GetAsync("api/products/2").ContinueWith((t) =>
{
if (t.IsFaulted)
{
MessageBox.Show(t.Exception.Message);
btnGetProducts.IsEnabled = true;
}
else
{
var response = t.Result;
if (response.IsSuccessStatusCode)
{
response.Content.ReadAsAsync<IEnumerable<Product>>().
ContinueWith(t2 =>
{
if (t2.IsFaulted)
{
MessageBox.Show(t2.Exception.Message);
btnGetProducts.IsEnabled = true;
}
else
{
var products = t2.Result;
_products.CopyFrom(products);
btnGetProducts.IsEnabled = true;
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
I have tried to convert this to VB.NET but I am having issues with the t.Result saying "'Result' is not a member of 'System.Threading.Tasks.Task'."
Here is my attempt to convert it to VB.NET:
Private Sub GetProducts(sender As Object, e As RoutedEventArgs)
btnGetProducts.IsEnabled = False
client.GetAsync("api/products/2") _
.ContinueWith(Of HttpResponseMessage) _
(Function(t)
If t.IsFaulted Then
MessageBox.Show(t.Exception.Message)
btnGetProducts.IsEnabled = True
Else
'***************************************************************
Dim response = t.Result 'This is the line that is giving me grief. Error Msg: 'Result' is not a member of 'System.Threading.Tasks.Task'.
'***************************************************************
If response.IsSuccessStatusCode Then
response.Content.ReadAsAsync(Of IEnumerable(Of SendNotice)).ContinueWith _
(Function(t2)
If t2.IsFaulted Then
MessageBox.Show(t2.Exception.Message)
btnGetProducts.IsEnabled = True
Else
Dim products = t2.Result
_lstSN.CopyFrom(products)
btnGetProducts.IsEnabled = True
End If
End Function, TaskScheduler.FromCurrentSynchronizationContext())
End If
End If
End Function, TaskScheduler.FromCurrentSynchronizationContext())
End Sub
Any idea why I am getting this error and what am I missing in my code to allow me to catch the returning JSON data?
Thanks!
This is because VB.NET type inference is not great in Visual Studio 2010. You'll need to give the compiler a bit of extra help by specifying the actual type returned by your client.GetAsync(), like so:
client _
.GetAsync("api/products/2") _
.ContinueWith( _
Sub(t As Task(Of HttpResponseMessage))
...
End Sub, _
TaskScheduler.FromCurrentSynchronizationContext())
Note: I've changed your Function to Sub because I didn't see any Return statements.
Try this:
client.GetAsync("api/products/2") _
.ContinueWith(Sub(t)
If t.IsFaulted Then
.
.
.
Try changing your lambda from a Function to a Sub.
Related
to create functionallity in my project I need to convert this C# sample to vb.net
I can only connect (Read/Write) to the backend using this API.
to get the details of a customer from a database:
Customer.BeginFetch(CustomerId, AfterFetchingCustomer);
private void AfterFetchingCustomer(object sender, DataPortalResult<Customer> dataPortalResult)
{
Invoke((Action)(() =>
{
_customer = dataPortalResult.Object;
txtShortName.Text = _customer.ShortName;
}));
}
//This is from the API in C#
public static void BeginFetch(string customerId, EventHandler<DataPortalResult<Customer>> callback, AdministrationContext context = null);
I tried:
Dim Debb Debiteur.CustomerId = "DE16000"
Customer.BeginFetch(Debiteur, AfterFetchingCustomer)
End Sub
Private Sub AfterFetchingCustomer(sender As Object, e As DataPortalResult(Of Customer))
End Sub
''This is from the API in VB:
Public Shared Sub BeginFetch(customerId As String, callback As EventHandler(Of DataPortalResult(Of Customer)), Optional context As AdministrationContext = Nothing)
But still get the errors:
Argument not specified for parameter sender ...
Argument not specified for parameter e ...
How can i get this code validated?
So I can continue to work on this program.
Thanks in advance!
ina c# project i have a static async task written to send emails via tmpt-relay.
the main function is calling this task.
This is working fine.
My Problem is i'm calling this function from a vb.net project, this is also working, email was send but vb.net is hanging in the c#-call
My Code in c#
public class SmoffMail
{
public static string sRet;
public string sendMail(string mailto)
{
RunAsync(mailto).Wait();
return sRet;
}
static async Task RunAsync(string mailto){
MailjetClient client = new MailjetClient("419cce0b9807d1016642156966fc4ec1",
....
sRet = "ok.....";
}
}
From the vb.net i call it like this:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim smail As New smoff.Mailjet.SmoffMail
Dim i As Integer = 0
Dim sRet As String = ""
sRet = smail.sendMail("xxxxxxxh#bluewin.ch")
MsgBox(sRet)
End Sub
End Class
So the function smail.sendMail() was called but is hanging, the next line in code ( msgbox ) is nerver attempt.
Thanks for your help
Your C# should look like this:
public class SmoffMail
{
static async Task<string> SendMailAsync(string mailto){
MailjetClient client = new MailjetClient("419cce0b9807d1016642156966fc4ec1",
....
return "ok.....";
}
}
And your VB should look like this:
Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sRet As String = ""
sRet = Await smoff.Mailjet.SmoffMail.SendMailAsync("xxxxxxxh#bluewin.ch")
MsgBox(sRet)
End Sub
End Class
Let your VB go back to drawing the UI while it waits for your 2 gigabyte attachment to upload, otherwise there's no point in having any of this be async
i found the solution, the problem was not my code, it was the API Mailjet.client.
after changing the call to this API it works fine
I'm trying to translate this C# code to VB.net
var messages = animalmgr.ReadFile(thefilename);
//Getting method from manager
if (messages != null)
{
messages.ToList().ForEach(msg => Resultlst.Items.Add(msg));
}
I tried it like this:
Dim message = animalmgr.ReadFile(thefilename)
If (Not (message) Is Nothing) Then
'I don't know how the code below are supposed to be
message.ToList.ForEach(() => { }, Resultlst.Items.Add(msg))
End If
I would appreciate if anyone could help me out. Thanks.
VB lambda functions are a bit different. Here is how it looks in VB.Net:
message.ToList().ForEach(Sub(msg) Resultlst.Items.Add(msg))
I'm seeing some strange behaviour when making a change to the following VB.net code. This is the original sourcecode:
Private Function ValidateSelectedId(ByVal purposeId As String) As Boolean
Dim possiblePurposes As New InfoCollector.Purpose
Dim isPurposeValid As Boolean = False
'Any of the following purposes (but only these)
'should be considered valid
Select Case UCase(purposeId)
Case UCase(possiblePurposes.FirstPurpose), _
UCase(possiblePurposes.SecondPurpose), _
UCase(possiblePurposes.ThirdPurpose), _
UCase(possiblePurposes.FourthPurpose)
isPurposeValid = True
Case Else
isPurposeValid = False
End Select
Return isPurposeValid
End Function
This is the new version. The only change is the addition of a fifth valid purpose:
Private Function ValidateSelectedId(ByVal purposeId As String) As Boolean
Dim possiblePurposes As New InfoCollector.Purpose
Dim isPurposeValid As Boolean = False
Select Case UCase(purposeId)
Case UCase(possiblePurposes.FirstPurpose), _
UCase(possiblePurposes.SecondPurpose), _
UCase(possiblePurposes.ThirdPurpose), _
UCase(possiblePurposes.FourthPurpose), _
UCase(possiblePurposes.FifthPurpose)
isPurposeValid = True
Case Else
isPurposeValid = False
End Select
Return isPurposeValid
End Function
I compiled this new version on my local PC and tested the functionality, and it worked fine. After checking this into our central code repository, and building it on the server however, the usage failed (it appeared to be ignoring the new purpose). While trying to figure out what is missing, I decompiled the .DLL found on the server, and this is what it gave me (Note: I've changed the variable names and reformatted slightly):
Private Function ValidateSelectedId(ByVal purposeId As String) As Boolean
Dim ValidateSelectedId As Boolean
Dim possiblePurposes As Purpose = New Purpose()
Dim isPurposeValid As Boolean = False
Dim str As String = Strings.UCase(purposeId)
If (Operators.CompareString(str, Strings.UCase(possiblePurposes.FirstPurpose), False) <> 0) Then
If (Operators.CompareString(str, Strings.UCase(possiblePurposes.SecondPurpose), False) <> 0
AndAlso (Operators.CompareString(str, Strings.UCase(possiblePurposes.ThirdPurpose), False) = 0
OrElse Operators.CompareString(str, Strings.UCase(possiblePurposes.FourthPurpose), False) <> 0)) Then
If (Operators.CompareString(str, Strings.UCase(possiblePurposes.FifthPurpose), False) = 0) Then
Return True
End If
isPurposeValid = False
End If
End If
Return isPurposeValid
End Function
I also tried decompiling this into C#, which might be a little easier to read for some of us:
private bool ValidateSelectedId(string purposeId)
{
bool ValidateSelectedId;
Purpose possiblePurposes = new Purpose();
bool isPurposeValid = false;
string str = Strings.UCase(purposeId);
if (Operators.CompareString(str, Strings.UCase(possiblePurposes.FirstPurpose), false) != 0)
{
if (Operators.CompareString(str, Strings.UCase(possiblePurposes.SecondPurpose), false) != 0
&& (Operators.CompareString(str, Strings.UCase(possiblePurposes.ThirdPurpose), false) == 0
|| Operators.CompareString(str, Strings.UCase(possiblePurposes.FourthPurpose), false) != 0))
{
if (Operators.CompareString(str, Strings.UCase(possiblePurposes.FifthPurpose), false) == 0)
{
return true;
}
isPurposeValid = false;
}
}
return isPurposeValid;
}
This however, seems to be doing something like the inverse of what I wanted, and not at all what the original source code is saying!
I can't see how the original source code could have been compiled to this. Could there be something wrong with my decompiler (I'm using Just Decompile from Telerik)? If so, how come the logic works on my local PC, but not on the server?
Could there actually be some kind of bug in the compile-process? Or am I being a complete Id**t, and simply misunderstanding the logic in the decompiled code?
Any relevant theories to explain this will be greatly appreciated.
Silly me.
I eventually discovered the reason this did not work on the server: There was another related bug which had been fixed locally, but not on the server.
Silly decompiler.
I was confused by the result from the decompiler, which was obviously messed up. I've used JustDecompile many times before, but never run across a problem like this. Apparently, it is unable to decompile the code from the above method in any reasonable fashion.
My assumptions are that some form of optimization is done during compilation, which JustDecompile has trouble understanding and displaying properly.
I just wanted to verify that my changes had been published to the server. Instead I was sent on a wild goose chase for a phantom bug. Lesson learned: Use the decompiler when needed, but do not automatically trust everything it tells you.
[Visual C#]
public ICommand MyCommand
{
get
{
if (this.myCommand == null)
{
this.myCommand = new RelayCommand(this.ShowMyCommand);
}
return this.myCommand;
}
}
private void ShowMyCommand(object param)
{
...
}
This code works fine, but when I convert it to Visual Basic:
[Visual Basic]
Private _myCommand As RelayCommand
Public ReadOnly Property MyCommand As ICommand
Get
If Me._myCommand Is Nothing Then
Me._myCommand = New RelayCommand(Me.ShowMyCommand)
End If
Return Me._myCommand
End Get
End Property
Private Sub ShowMyCommand(ByVal param As Object)
...
End Sub
I get the error:
Error 3 Argument not specified for
parameter 'param' of 'Private Sub
ShowMyCommand(param As Object)'.
Any ideas? I am just doing blind conversion so I don't understand what the project does, I am just converting it.
I am a bit on thin ice when it comes to VB, but according to what I know, you need to prefix the method name with the keyword AddressOf in order for it to be usable as a method group for the event.
The following line:
Me._myCommand = New RelayCommand(Me.ShowMyCommand)
Needs to be written as:
Me._myCommand = New RelayCommand(AddressOf Me.ShowMyCommand)
The error message is because the compiler is trying to compile a call to the method, and is thus missing the argument to its parameter.