Can I use an extension method with a Structure in VB.NET? - vb.net

I am wondering whether I can use DataContractJsonSerializer to serialize a Structure type, or does it have to be a reference/Class type?
I have the following code:
<Extension()> Public Function ToJSON(ByVal target As Object) As String
Dim serializer = New System.Runtime.Serialization.Json.DataContractJsonSerializer(target.GetType)
Using ms As MemoryStream = New MemoryStream()
serializer.WriteObject(ms, target)
ms.Flush()
Dim bytes As Byte() = ms.GetBuffer()
Dim json As String = Encoding.UTF8.GetString(bytes, 0, bytes.Length).Trim(Chr(0))
Return json
End Using
End Function
And yet if I call it on a Structure type, such as a KeyValuePair(Of T1, T2), I get the following error:
Public member 'ToJSON' on type 'KeyValuePair(Of String,Object)' not found.

The error message does not have anything to do with DataContractJsonSerializer or anything inside your method. It cannot find the method itself. That suggests to me that you have forgotten to add a reference to the namespace in which this extension method is defined. I apologise I don’t know the VB equivalent, but in C# it is the using clause I’m talking about.

Related

{"Unexpected JSON token when reading DataTable. Expected StartArray, got Integer. Path 'id', line 1, position 9."}

Receiving below error on deserializing json to dataset.
Unexpected JSON token when reading DataTable. Expected StartArray, got Integer. Path 'id', line 1, position 9
Json Retrieved : {"id":130,"type":"general","setup":"test?","punchline":"test."}
My Code
Dim wc As New WebClient
Try
Dim res As String
For i = 0 To 5
res = wc.DownloadString("https://official-joke-api.appspot.com/random_joke")
Dim jObject = JsonConvert.DeserializeObject(res)
Dim ds As New DataSet
ds = JsonConvert.DeserializeObject(Of DataSet)(res)
MsgBox(ds.Tables.Count)
Next
Catch ex As Exception
MsgBox(ex)
End Try
As user Akshay Gaonkar commented, you can give Newtonsoft.Json a class, named, say, Joke, to deserialise with. You can get around the mismatch of uppercase/lowercase initial letter naming conventions by decorating the properties with <JsonProperty("nameInTheJson")>.
Instead of deserializing the data into a datatable inside a dataset, you could keep it simple and create a List(Of Joke).
This is for a console application:
Imports System.Net
Imports Newtonsoft.Json
Module Program
Class Joke
<JsonProperty("id")>
Property Id As Integer
<JsonProperty("type")>
Property Type As String
<JsonProperty("setup")>
Property Setup As String
<JsonProperty("punchline")>
Property Punchline As String
End Class
Sub Main(args As String())
Dim jokes As New List(Of Joke)
Using wc As New WebClient()
For i = 1 To 5
Dim jokeInfo = wc.DownloadString("https://official-joke-api.appspot.com/random_joke")
jokes.Add(JsonConvert.DeserializeObject(Of Joke)(jokeInfo))
Next
End Using
' Alternative which fetches ten jokes in one go - note the use of (Of List(Of Joke))
'Using wc As New WebClient()
' Dim jokeInfo = wc.DownloadString("https://official-joke-api.appspot.com/jokes/ten")
' jokes = JsonConvert.DeserializeObject(Of List(Of Joke))(jokeInfo)
'End Using
For Each jk In jokes
Console.WriteLine($"{jk.Setup}{vbCrLf}{jk.Punchline}{vbCrLf}")
Next
End Sub
End Module
The Using statement is needed because a WebClient should be disposed of after use to clear up system resources. (You could use the equivalent Try...Finally with wc.Dispose() instead.)
The JSON you showed is invalid. Datatable is expecting array of Object , so the JSON should look like below :
[{"id":130,"type":"general","setup":"test?","punchline":"test."}]

Visual Basic .Net Public Function decodes a one line procedure before it gets executed

I encountered an issue with Function and Procedure while experimenting with some code, as below:
Module mod1
Class ExampleApp
Dim textvalue as String = "dGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgdGV4dC4="
Dim string1 as String = "Convert.FromBase64String(input)"
Public Function DecodeB64(ByVal input As String) As String
Return System.Text.Encoding.UTF8.GetString(string1)
End Function
End Class
End Module
The question is, is it possible to encode the statement inside the Public Function before it gets executed?
I have seen some cases where they implemented it on PHP Scripts, where the whole script is encoded before it gets executed. I have tried my best in applying the same concept by storing "Convert.FromBase64String(input)" to a string variable but I'm encountering an issue like this:
Value of type 'String' cannot be converted to '1-Dimensional array of
Byte'
When I don't apply this concept, the text in base64 gets decoded smoothly. My main goal is that I want to obscure the statement or group of statements as much as possible. What seems to be the problem in this Error?
You have 2 mistakes below in the example code:
First, you should know that Convert.FromBase64String() returns
Byte() array, hence you can't assign it to string variable/field.
Second, Encoding.GetString() requires Byte() array as parameter,
but you're passing string to it, hence InvalidCastException occurred.
The correct usage of them should be like this:
Public Function DecodeB64(ByVal input As String) As String
' make sure the input string is Base64 formatted
Dim bytearray As Byte() = Convert.FromBase64String(input)
' decoding from byte array
Return System.Text.Encoding.UTF8.GetString(bytearray)
End Function
' usage
Dim textvalue as String = "dGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgdGV4dC4="
Dim result As String = DecodeB64(textvalue)
Working example: .NET Fiddle demo

How to mimic Java's Wildcard types in VB.net?

I have an interface which I defined like this:
Public Interface ISomething(Of T)
' methods
End Interface
I now did an implementation:
Public Class ConcreteThing
Implements ISomething(of SomeClass)
' Implementation
End Class
I have multiple such concrete implementations, and want to have a function which returns any of them based on its parameters. In Java, I would do something like this:
public ISomething<?> getSomething(ParamType p) {
if(p.hasFoo()) return new ConcreteThing();
if(p.hasBar()) return new OtherConcreteThing();
throw new IllegalStateException("p neither has Foo nor Bar");
}
I already searched about this issue and found out that VB.net does not have wildcard types, so I tried:
Public Function GetSomething(p as ParamType) as ISomething(Of Object)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
This compiles, but I get the warning: Runtime errors might occurr when converting 'Foo.ConcreteThing' to 'Foo.ISomething(Of Object)'.
When I try the following, as suggested in a similar question:
Public Function GetSomething(Of T)(p as ParamType) as ISomething(Of T)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
the warning only changes to Runtime errors might occurr when converting 'Foo.ConcreteThing' to 'Foo.ISomething(Of T)'.
So, how do I get this right? Or, if this indeed IS right, how do I have Visual Studio ignore this warning?
I investigated on this issue a little more, discussed it with my colleagues, and I think I found the solution / reason for the warnings.
The warning message is a bit hard to understand and unconcise. What they are trying to say is that, as silly as it sounds, covariance does not work as expected for primitive types, even when using the Out keyword!
Consider an excerpt from this example on MSDN:
' Covariance.
Dim strings As IEnumerable(Of String) = New List(Of String)()
' An object that is instantiated with a more derived type argument
' is assigned to an object instantiated with a less derived type argument.
' Assignment compatibility is preserved.
Dim objects As IEnumerable(Of Object) = strings
This works. Now, change the first IEnumerable to IList:
Dim strings As IList(Of String) = New List(Of String)()
Dim objects As IEnumerable(Of Object) = strings
Works, too. OK, we are lucky, let's change the second:
Dim strings As IList(Of String) = New List(Of String)()
Dim objects As IList(Of Object) = strings
Boom, InvalidCastException. Looking at the signature, this is because the generic parameter in IEnumerable is defined as Of Out T, and IList is only defined As T.
Now, let's define our own.
Interface ISomething(Of Out T)
ReadOnly Property Value As T
End Interface
Class IntThing
Implements ISomething(Of Integer)
Public ReadOnly Property Value As Integer Implements ISomething(Of Integer).Value
Get
Return 42
End Get
End Property
End Class
Now, do this:
Dim s1 As ISomething(Of Integer) = new IntThing()
Works. Now add this:
Dim s2 As ISomething(Of Object) = s1
Boom, InvalidCastException. Now, the funniest part. Add a second implementation of ISomething:
Class StringThing
Implements ISomething(Of String)
Public ReadOnly Property Value As String Implements ISomething(Of String).Value
Get
Return "foo"
End Get
End Property
End Class
And do:
Dim s1 As ISomething(Of String) = New StringThing()
Dim s2 As ISomething(Of Object) = s1
This, on the other hand, works! So, let's go back to the List example.
Dim ints As IEnumerable(Of Integer) = New List(Of Integer)()
Dim objects As IEnumerable(Of Object) = ints
This will get you an InvalidCastException, too.
So, my conclusion is that covariance not only needs the Out keyword, it additionally only works with non-primitive types. .net seems to handle wrapper classes differently to the JVM.
So, never ignore this warning when it pops up. When it does, things will go wonky in an absolutely illogical way! That means, for what I want to achieve, going with simple Objects instead trying to find an equivalent for ISomething<?> is the way to go.
I only use this internally to read a binary file into a more convenient structure to extract the data I pass out via the API in the end, so using Object does not make things very much worse here.
It's weird, I don't get the warning like you do. But I do get an InvalidCastException if I try to run the code.
To get rid of the error (and hopefully your warning as well), you can make the generic type T on ISomething covariant.
Public Interface ISomething(Of Out T) ' Add the "Out" keyword here to make it covariant
' methods
End Interface
Then you should be able to use your GetSomething function as you had attempted:
Public Function GetSomething(p as ParamType) as ISomething(Of Object)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
Relevant documentation: Covariance and Contravariance in Generics
Covariance
Enables you to use a more specific type than originally specified.
You can assign an instance of IEnumerable<Derived> (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable<Base>.
And lower in the Defining Variant Generic Interfaces and Delegates section:
A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler).

Calling System.IO.ReadAllBytes by string name

This post is related to Visual Basic .NET 2010
So, I'm wondering if there's any way to call a function from a library such as System.ReadAllBytes by string name.
I've been trying Assembly.GetExecutingAssembly().CreateInstance and System.Activator.CreateInstance followed by CallByName(), but none of them seemed to work.
Example of how I tried it:
Dim Inst As Object = Activator.CreateInstance("System.IO", False, New Object() {})
Dim Obj As Byte() = DirectCast(CallByName(Inst, "ReadAllBytes", CallType.Method, new object() {"C:\file.exe"}), Byte())
Help is (as always) much appreciated
It is System.IO.File.ReadAllBytes(), you missed the "File" part. Which is a Shared method, the CallByName statement is not flexible enough to permit calling such methods. You will need to use the more universal Reflection that's available in .NET. Which looks like this for your specific example, spelled out for clarity:
Imports System.Reflection
Module Module1
Sub Main()
Dim type = GetType(System.IO.File)
Dim method = type.GetMethod("ReadAllBytes")
Dim result = method.Invoke(Nothing, New Object() {"c:\temp\test.bin"})
Dim bytes = DirectCast(result, Byte())
End Sub
End Module

Can I use generics to populate List(of t) with custom classes?

I have several different lists I want to call. They all have the same format for the class:
id, value, description, order. Instead of creating a bunch a classes to return the all of the many lists, I wanted to use generics and just TELL it what kind of list to return. However, I can not figure out how to populate the classes.
Here are 2 examples of function in my calling code. This should indicate the type of list and the stored proc used to get the data:
Public Function getTheEyeColors()
Dim glEyeColors As New GenericList
Return glEyeColors.GetALList(Of EyeColor)("GetAllEyeColors")
End Function
Public Function getTheHairColors()
Dim glHairColors As New GenericList
glHairColors.GetALList(Of HairColor)("GetAllHairColors")
End Function
And here is the code I am trying to use to build the generic list...
Public Function GetALList(Of t)(ByVal storedproc As String) As List(Of t)
Dim lstGenericList As New List(Of t)
Dim oGenericListItem As t
Dim oProviderFactory As New ProviderFactory
Dim oConnection As DbConnection
Dim oReader As System.Data.IDataReader
Dim oFactory As DbProviderFactory
Dim oFileMgt As New FileMgt
Dim oCmd As DbCommand
oFactory = oProviderFactory.GetFactory
oConnection = oProviderFactory.GetProviderConnection(oFactory)
oCmd = oConnection.CreateCommand
oCmd.CommandType = CommandType.StoredProcedure
oCmd.CommandText = storedproc
Using (oConnection)
oConnection.Open()
oReader = oCmd.ExecuteReader()
While oReader.Read
HERE IS WHERE I AM NOT SURE HOW TO POPULATE THE EYECOLOR OR HAIRCOLOR CLASS
lstGenericList.Add(oGenericListItem)
End While
oConnection.Close()
End Using
Return lstGenericList
End Function
You could add two generic constraints; I don't know how to express them in VB, but here's the C# version:
T : new() - there has to be a parameterless constructor
T : ICommonInterface - T has to implement an interface
You then put the common properties (ID, Value, Description, Order) into the interface, and you'll be able to create a new T(), set the properties and add it to the list.
EDIT:
The VB Syntax to specify that it must both be creatable and implement an interface is:
(Of T As {ICommonInterface, New})
The way Jon recommends to do it is probably a better way to go, but another way I've seen this done is the FillObject method in the DotNetNuke architecture. Basically it's a conventions based method that uses reflection to match the properties on an object to the values of a dataset.
I personally don't like this method, but it does mean you don't have to create a new implementation of the code to hydrate the object for each stored procedure.
The code is available in the full source download in the DNN project.
While oReader.Read
HERE IS WHERE I AM NOT SURE HOW TO POPULATE THE EYECOLOR OR HAIRCOLOR CLASS
Check out LinqToSql (System.Data.Linq) . You might be re-inventing it.