How to pass multiple attributes to WebApi? - vb.net

I have a webapi made in VB.NET where I can get all data, data by month and data by year. Now I am trying to add the functionality to get data by data-range, in the constructor the method looks as the following:
Public Function TotaliDataData(ByVal inizio As String, ByVal fine As String) As IEnumerable(Of Totali)
Dim SQLConnect As String = "Server=127.0.0.1;Port=3306;Database=00168780351;Uid=root;Pwd=block;"
Dim cn As New MySqlConnection(SQLConnect)
Dim cmd As New MySqlCommand("SELECT NPV_TT, NCASSA_TT, DATA_TT, AZZ_TT, SUM(NSC_TT) AS NSC_TT, SUM(VENDITE_TT) AS VENDITE_TT, RESI_TT, ANNULLI_TT, SCONTI_TT, FATTURE_TT, NC_TT FROM totali WHERE DATA_TT BETWEEN '" & inizio & "' AND '" & fine & "' GROUP BY MONTH(DATA_TT);", cn)
cn.Open()
Dim reader As MySqlDataReader = cmd.ExecuteReader()
Dim totali As List(Of Totali) = ConvertReader(reader)
cn.Dispose()
Return totali
End Function
Here is my TotaliController.VB:
Public Class TotaliController
Inherits ApiController
Public Function GetTotali() As IEnumerable(Of Totali)
Dim Totali As Totali = New Totali
Return Totali.GetTotali()
End Function
Public Function GetTotaliByYear(ByVal anno As String) As IEnumerable(Of Totali)
Dim Totali As Totali = New Totali
Return Totali.TotaliAnno(anno)
End Function
Public Function GetTotaliByMonth(ByVal mese As String) As IEnumerable(Of Totali)
Dim Totali As Totali = New Totali
Return Totali.TotaliMese(mese)
End Function
Public Function TotaliDataData(ByVal inizio As String, ByVal fine As String) As IEnumerable(Of Totali)
Dim Totali As Totali = New Totali
Return Totali.TotaliDataData(inizio, fine)
End Function
Public Function GetDetails(ByVal annod As String) As IEnumerable(Of Totali)
Dim Totali As Totali = New Totali
Return Totali.GetDetails(annod)
End Function
End Class
Then I was trying to call localhost:port/api/totali/?inizio=2019-11-10&fine=2019-12-20 but it doesn't enter even inside the debug of controller while if I try to get data by month or year with single parameter it works fine..
So how could I pass multiple parameters to WebApi?
UPDATE:
When I try to run localhost:port/api/totali/?inizio=2019-11-10&fine=2019-12-20 it calls the default GetTotali() method from controller which returns all data from the DB.
Global:
Public Class WebApiApplication
Inherits System.Web.HttpApplication
Protected Sub Application_Start()
GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
GlobalConfiguration.Configuration.Formatters.
JsonFormatter.MediaTypeMappings.Add(New RequestHeaderMapping("Accept", "text/html", StringComparison.InvariantCultureIgnoreCase, True, "application/json"))
End Sub
End Class
WebApiConfig
Public Module WebApiConfig
Public Sub Register(ByVal config As HttpConfiguration)
' Servizi e configurazione dell'API Web
' Route dell'API Web
config.MapHttpAttributeRoutes()
config.Routes.MapHttpRoute(
name:="DefaultApi",
routeTemplate:="api/{controller}/{id}",
defaults:=New With {.id = RouteParameter.Optional}
)
End Sub
End Module

Apparently methods names in WebApi controller have to start with REST prefix so by changing the name of method TotaliDataData to GetTotaliDataData solved the problem.

Related

Having issues when 2 users are working with the same program

Public Class DataAccess
Dim dataAcc As New DataAccess
Public Shared dtx As New DataTable
Private Shared ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Shared Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
I use that part to create the connection just like the example #Mary posted. Then:
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim numTicket As String = txtNoTicket.Text
Dim dtx As New DataTable
Dim pk As String
pk = txtNoTicket.Text
Dim con2 As New SqlConnection
Dim cmd2 As New SqlCommand
Dim dr As SqlDataReader
Dim dtx2 As DataTable
Dim status As Boolean = False
'If Not Integer.TryParse(ticket.Text, pk) Then
If String.IsNullOrEmpty(pk) Then
'ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "showDisplay();", True)
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
dtx = DataAccess.AddOneRecord(pk)
So when adding tickets the issue is the ticket 1 user adds, gets added to the other user even though they use different sessions and different computers. The program is in test fase right now.
You can get rid of Shared in the DatAccess class. Then each instance of the class will have its own data. Now you must declare an instance of the class and call the method on that instance.
Public Class DataAccess
Dim dataAcc As New DataAccess
Public dtx As New DataTable
Private ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim dtx As New DataTable
Dim pk = txtNoTicket.Text
If String.IsNullOrEmpty(pk) Then
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
Dim datAcc As New DataAccess
dtx = datAcc.AddOneRecord(pk)
End If
End Sub

Populate class from query on VB Net

Help translate C# code from this link Simplest way to populate class from query in C# to VB Net.
Option Infer On
Imports System.Reflection
Private Sub Main()
Dim connectionString = "..."
Dim records = (New Query(connectionString)).SqlQuery(Of TVChannel)("select top 10 * from TVChannel")
End Sub
Private Class TVChannel
Public Property number() As String
Public Property title() As String
Public Property favoriteChannel() As String
Public Property description() As String
Public Property packageid() As String
Public Property format() As String
End Class
Public Class Query
Private ReadOnly _connectionString As String
Public Sub New(ByVal connectionString As String)
_connectionString = connectionString
End Sub
Public Function SqlQuery(Of T)(ByVal query As String) As List(Of T)
Dim result = New List(Of T)()
Using connection = New SqlConnection(_connectionString)
connection.Open()
Using command = connection.CreateCommand()
command.CommandText = query
Using reader = command.ExecuteReader()
Dim columns = Enumerable.Range(0, reader.FieldCount).Select(Function(f) reader.GetName(f)).ToArray()
Dim properties = GetType(T).GetProperties()
Do While reader.Read()
Dim data = New Object(reader.FieldCount - 1){}
reader.GetValues(data)
Dim instance = DirectCast(Activator.CreateInstance(GetType(T)), T)
For i = 0 To data.Length - 1
If data(i) Is DBNull.Value Then
data(i) = Nothing
End If
Dim [property] = properties.SingleOrDefault(Function(x) x.Name.Equals(columns(i), StringComparison.InvariantCultureIgnoreCase))
If [property] IsNot Nothing Then
[property].SetValue(instance, Convert.ChangeType(data(i), [property].PropertyType))
End If
Next i
result.Add(instance)
Loop
End Using
End Using
End Using
Return result
End Function
End Class
but, I got error on this line
Dim instance = DirectCast(Activator.CreateInstance(GetType(T)), T)
System.MissingMethodException: 'No parameterless constructor defined for this object.'
This is a much better pattern to follow. It addresses at least four issues in the original code (sql injection, Nothing vs null, constructor access, unnecessary allocations):
Public Module SQL
Private ReadOnly _connectionString As String = "..."
Public Iterator Function Query(Of T)(ByVal query As String, translate As Func(IDataRecord, T), ParamArray data() As SqlParameter) As IEnumerable(Of T)
Using connection As New SqlConnection(_connectionString), _
command As New SqlCommand(query, connection)
If data IsNot Nothing Then command.Parameters.AddRange(data)
connection.Open()
Using reader As SqlDataReader = command.ExecuteReader()
While reader.Read()
Yield translate(reader)
End While
reader.Close()
End Using
End Using
End Function
End Module
Call it like this:
Private Sub Main()
Dim records = SQL.Query("select top 10 * from TVChannel",
Function(r)
'Yes, you're doing the mapping manually now for each query.
'But this lets you properly account for things NULL, column name mismatches, computed properties, etc.
Return New TVChannel With {
.number = r["number"],
.title = r["title"],
.favoriteChannel = r["favoriteChannel"],
.description = r["description"],
.packageid = r["packageid"],
.format = r["format"]
}
End Function,
Nothing)
For Each channel As TVChannel In records
Console.WriteLine($"Channel {channel.number}, {channel.title}")
Next
End Sub

VB.NET connection to MySQL Add Model

I'm very new to .NET. I am trying to use a code example from the first person that posted a response, here: Connect to remote MySQL database using VB.NET 2010
I would like to instantiate the MySqlVB model object but when I add the following code into the controller, I get a not found error. I don't know how to resolve this.
The error is: Warning 1 Namespace or type specified in the Imports 'MySql.Data.MySqlClient' doesn't contain any public member or cannot be found. Make sure the namespace or the type is defined and contains at least one public member. Make sure the imported element name doesn't use any aliases.
What I need is to run a MySQL query and to return the dataset to the controller. Can someone show me how to do this, please?
I'm using VB 2010 Express to do this.
This is the controller
Public Class Form1
Private Sub PrintBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PrintBtn.Click
Dim data As New MySqlVB
With data
If .Connection Then
MessageBox.Show("Database Conneted.")
Else
MessageBox.Show(.ErrorMessage)
End If
End With
End Sub
End Class
And this is my model object
Imports MySql.Data.MySqlClient
Public Class MySqlVB
Private _connection As New MySqlConnection
Private _errormessge As String
Private _servername As String = "xxx.xxx.xxx.xxx"
Private _databasename As String = "testdb"
Private _userid As String = "theuser"
Private _password As String = "thepass"
Public WriteOnly Property ServerName() As String
Set(ByVal value As String)
_servername = value
End Set
End Property
Public WriteOnly Property DatabaseName() As String
Set(ByVal value As String)
_databasename = value
End Set
End Property
Public WriteOnly Property UserID() As String
Set(ByVal value As String)
_userid = value
End Set
End Property
Public WriteOnly Property Password() As String
Set(ByVal value As String)
_password = value
End Set
End Property
Public ReadOnly Property ErrorMessage() As String
Get
Return _errormessge
End Get
End Property
Public Function Connection() As Boolean
Try
_connection.ConnectionString = "Server=" & _servername & ";Port=3306;Database=" & _databasename & ";User ID=" & _userid & ";Password=" & _password & ""
_connection.Open()
If _connection.State = ConnectionState.Open Then
_connection.Close()
Return True
End If
Catch ex As Exception
_errormessge = ex.Message
Return False
End Try
End Function
End Class
Assuming you have fixed your reference to MySql.Data.MySqlClient I think your class could use some work.
Public Class DataAccess
Private ConnectionString As String
Public Sub New(UserName As String, Password As String)
Dim builder As New MySqlConnectionStringBuilder With {
.Server = "xxx.xxx.xxx.xxx",
.Database = "testdb",
.UserID = UserName,
.Password = Password
}
ConnectionString = builder.ConnectionString
Debug.Print(ConnectionString) 'just to see what the builder created
End Sub
Public Function TestConnecion() As Boolean
Using cn As New MySqlConnection(ConnectionString)
Try
cn.Open()
Catch ex As Exception
Debug.Print(ex.Message) 'just to see what is wrong with connection
Return False
End Try
End Using
Return True
End Function
Public Function GetData() As DataTable
Dim dt As New DataTable
Using cn As New MySqlConnection(ConnectionString)
Using cmd As New MySqlCommand("Select * From SomeTable")
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
End Using
Return dt
End Function
End Class
Assuming you have a DataGridView to display data and 2 text boxes for user id and password, you can use your class in your form like this.
Private Sub FillGrid()
Dim daClass As New DataAccess(txtUser.Text, txtPassword.Text)
Dim dt = daClass.GetData
DataGridView1.DataSource = dt
End Sub
Of course you will need to add error handling. Also you need to salt and hash passwords. Plain text passwords should never be stored.

Set SqlParameter in VB.NET?

I'm new with classes and I want to create a SqlCommandManager class and I can't figure out how to pass SqlParameter on my class.
For example if I want to insert data I would just use my class like client below.
'Client
Dim m_SqlComManager as new SQLCommandManager("MyConnectionString")
m_SqlCommandManager.Commandtext = "INSERT INTO [TableName]([Field1],[Field2])VALUES(#Field1,Field2);"
m_SqlCommandManager.Parameters.AddWithValue("#Field1","SomeValue1")
m_SqlCommandManager.Parameters.AddWithValue("#Field2","SomeValue2")
m_SqlCommandManager.ExecuteNonQuery()
'Here is my class
Imports System.Data.SqlClient
Public Class SQLCommandManager
Private m_SqlParameters As SqlParameter()
Private m_Commandtext As String
Private m_ConStr As String
Public WriteOnly Property SQlParameter() As SqlParameter()
Set(ByVal value As SqlParameter())
value = m_SqlParameters
End Set
End Property
Public Property CommandText() As String
Get
Return m_Commandtext
End Get
Set(ByVal value As String)
value = m_Commandtext
End Set
End Property
Public Sub New(ByVal con As String)
m_ConStr = con
End Sub
Public Sub ExecuteNonQuery()
Using con As New SqlConnection(m_ConStr)
Using com As New SqlCommand
com.Connection = con
com.CommandText = m_Commandtext
'Please help
'How can i insert parameter here from client..
If con.State = ConnectionState.Closed Then
con.Open()
End If
com.ExecuteNonQuery()
End Using
End Using
End Sub
End Class
How how can I set the parameters before the ExecuteNonQuery method?
Thanks in advance..
I would do something like this:
Public Class SqlCommandManager
Private m_SqlParameters As List(Of SqlParameter)
Private m_Commandtext As String
Private m_ConStr As String
Public Sub New()
m_SqlParameters = New List(Of SqlParameter)()
End Sub
Public ReadOnly Property SqlParameters() As List(Of SqlParameter)
Get
Return m_SqlParameters
End Get
End Property
Public Property CommandText() As String
Get
Return m_Commandtext
End Get
Set
value = m_Commandtext
End Set
End Property
Public Sub New(con As String)
m_ConStr = con
End Sub
Public Sub ExecuteNonQuery()
Using con As New SqlConnection(m_ConStr)
Using com As New SqlCommand(m_Commandtext, con)
com.Parameters.AddRange(m_SqlParameters.ToArray())
con.Open()
com.ExecuteNonQuery()
con.Close()
End Using
End Using
End Sub
End Class
What I've changed:
Changed the class name to SqlCommandManager to be in line with Microsoft's recommendations (don't capitalize more than 2 letters in an abbreviation; IO is fine, Sql and Xml should not be all capitalized)
I would use a List(Of SqlParameter) rather than an array - much easier to deal with, much easier to add additional parameters to it
I prefer to pass the CommandText and the SqlConnection right into the constructor of the SqlCommand - that way,you definitely never forget these two vital bits of information!
Just before your .ExecuteQuery, add the parameters defined in your list to the parameter array of the SqlCommand using a single call to .AddRange()

Reference to a non-shared member requires an object reference

I am getting the above error now when I run one of my ASPX pages, written in VB.NET. So I tried following the solution at:
http://msdn.microsoft.com/en-us/library/zwwhc0d0(v=vs.80).aspx
The above link seemed promising, cause it seemed to describe my problem exactly. However, I got the following error from this solution:
Compiler Error Message: BC30456:
'GlobalF2' is not a member of
'GlobalFunctions' Line 88:
DSProductData =
GlobalFunctions.GlobalF2.ComplaintTrendingDrillDown3p(FirstMonthDate,
LastMonthDate, TheLevel, ProductGroup,
TheCategory, ListNumber)
And here is my modified source code causing this error, but based off of Mike Smith's solution:
Namespace GlobalFunctions
Public Class GlobalF
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
Public Class CallingClass
Dim GlobalF2 As New GlobalF
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
End Namespace
I think Mike Smith is correct about not using Shared, cause I think that caused this problem. However, I am a newbie at VB.NET and I'm not sure how else to declare an instance as an object variable and then reference this instance by variable name. Can you help?
OK, ur solution looked very good to me. I want to make sure I implemented it correctly though. Can you compare mine to urs?
Now I get the same error I had initially...Maybe it's overwriting data in the table?
Dim gf As New GlobalFunctions.CallingClass
DSProductData = gf.GlobalF2.ComplaintTrendingDrillDown3p(FirstMonthDate, LastMonthDate, TheLevel, ProductGroup, TheCategory, ListNumber)
...
Public Class CallingClass
Public GlobalF2 As New GlobalF
'Public Function CallingClass(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String)
' Dim cc_new As New CallingClass()
'End Function
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
And the error:
System.ArgumentException: Column
'QXP_SHORT_DESC' does not belong to
table Table.
The offending line:
If pException("QXP_SHORT_DESC") =
TheCategory Then
You can't dim an instance of a class outside a method you can use
public GlobalF2 As New GlobalF
EDIT
I'm not sure exactly what you are attempting to do but pulling all of the extraneous code out.
Class File
Namespace GlobalFunctions
Public Class GlobalF
Public Sub DoSomthing()
Console.WriteLine("hi")
End Sub
End Class
Public Class CallingClass
Public GlobalF2 As New GlobalF
Public x As Int16 = 3
End Class
End Namespace
Main File
Imports System.IO
Module Module1
Public Sub Main()
Dim gf As New GlobalFunctions.CallingClass
gf.GlobalF2.DoSomthing()
End Sub
End Module