views:

285

answers:

3

Yesterday I asked this question. Rubens Farias answered it by pointing to this piece of code he wrote. The following part of it cannot be compiled by MS Visual Studio 2010 Professional Beta 2.

byte[] buffer = 
Encoding.UTF8.GetBytes(
    String.Join("&", 
        Array.ConvertAll<KeyValuePair<string, string>, string>(
            inputs.ToArray(),
            delegate(KeyValuePair item)
            {
                return item.Key + "=" + HttpUtility.UrlEncode(item.Value);
            })));

It gives these errors in Visual Studio. Unfortunately Rubens doesn't reply anymore.

So I have the following questions / requests:

  1. I don't understand this piece of code, please explain what is happening exactly.
  2. Please explain how this part has te be rewritten in order for it to "work" in VS.
  3. Please explain how I should convert it to VB.NET. I have tried it using online converters to no avail.
+1  A: 
byte[] buffer = 
Encoding.UTF8.GetBytes(
    String.Join("&", 
        Array.ConvertAll<KeyValuePair<string, string>, string>(
            inputs.ToArray(),
            delegate(KeyValuePair<string, string> item)
            {
                return item.Key + "=" + System.Web.HttpUtility.UrlEncode(item.Value);
            })));

Try that.

  1. The code appears to be building a GET request list of items e.g. key1=value1&key2=value2. This is done by first converting the inputs array into individual elements of key=value then String.Joining them together with an ampersand. It then returns the UTF8 bytes in an array.

  2. This works (see code).

  3. I'm not a VB.NET programmer, sorry, but I'll have a go in a second.

Codesleuth
Fredrik Mörk has done a good job of converting it. I'm giving up, heh.
Codesleuth
Thanks anyway for the explanation.
iar
+1  A: 

It is converting the inputs list containing Key/Value pairs into a string that looks much like a query string (eg. item1=value1&item2=value2), then converting that into the buffer byte array using UTF8 encoding.

Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim inputs As New List(Of KeyValuePair(Of String, String))
        inputs.Add(New KeyValuePair(Of String, String)("a", "adata"))

        Dim buffer As Byte() = _
            Encoding.UTF8.GetBytes( _
                String.Join("&", _
                Array.ConvertAll(Of KeyValuePair(Of String, String), String)( _
                    inputs.ToArray(), _
                    Function(item As KeyValuePair(Of String, String)) _
                    item.Key & "=" & HttpUtility.UrlEncode(item.Value) _
                )))
    End Sub
End Class
Will
Thanks but it gives the same error messages.
iar
Looks like Fredrik has the last piece of the puzzle for you... Just make sure you have "Imports System.Web" at the top of the file. That might clean up the errors.
Will
I have "Imports System.Web" but it doesn't remove the error that "Name 'HttpUtility' is not declared".
iar
It compiles fine here, after I corrected the 2nd mention of "KeyValuePair" to say "KeyValuePair(Of String, String)". I updated the converted code so it shows the complete class.
Will
+4  A: 
  • KeyValuePair requires two type arguments. In your delegate declaration it says simply KeyValuePair item, with no type arguments. Change this to delegate(KeyValuePair<string,string> item)
  • HttpUtility is declared in the System.Web namespace; add using System.Web; to the using statements in the beginning of the file.

Personally I find it easier and cleaner to use lambda style for this kind of code:

byte[] buffer =
     Encoding.UTF8.GetBytes(
         String.Join("&",
             Array.ConvertAll<KeyValuePair<string, string>, string>(
                 inputs.ToArray(), (item) => item.Key + "=" + HttpUtility.UrlEncode(item.Value))));

Once you have gotten the C# code to work, the DeveloperFusion C# to VB.NET converter does the job:

' Converted from delegate style C# implementation '
Dim buffer As Byte() = Encoding.UTF8.GetBytes( _
    [String].Join("&", _
    Array.ConvertAll(Of KeyValuePair(Of String, String), String)(inputs.ToArray(), _
        Function(item As KeyValuePair(Of String, String)) (item.Key & "=") + HttpUtility.UrlEncode(item.Value))))

' Converted from Lambda style C# implementation '
Dim buffer As Byte() = Encoding.UTF8.GetBytes( _
    [String].Join("&", _
    Array.ConvertAll(Of KeyValuePair(Of String, String), String)(inputs.ToArray(), _
        Function(item) (item.Key & "=") + HttpUtility.UrlEncode(item.Value))))
Fredrik Mörk
+1, ty Fredrik!
Rubens Farias
I still can't get it to work. It says "Name 'HttpUtility' is not declared. I guess it's only available to ASP.NET projects? I've tried to add a reference to system.web, and to system.web.dll, but no go. Same for your suggestion: "using System.Web", I have it already.
iar
@iar: yoy must make sure that the project in which the code lives has a reference to the assembly `System.Web` and that there is a using (or Imports in VB.NET) statement to import the namespace in the code file. An alternative to the using/Imports statement is to qualify the name in the code (`System.Web.HttpUtility.UrlEncode(...`). You still need to add a reference to the `System.Web` assembly though.
Fredrik Mörk
It says "'HttpUtility' is not a member of 'Web'". I have this line of code now: System.Web.HttpUtility.UrlEncode(item.Value). Also "Imports System.Web" on top of the file. When adding a reference using Add reference in the solution explorer, I have no System.Web in the .NET tab. As you'll have noticed by now I'm not a very experienced user yet ;)
iar
@iar: that is probably related to the selected Target Framework (System.Web is not available if the target framework is ".NET Framework 4 Client Profile"). To resolve (for VB.NET project): double click "My Project", select the "Compile" tab, click the "Advanced Compile Options" button (far down on the page) and change Target Framework to ".NET Framework 4".
Fredrik Mörk
You are right about that, thanks.
iar