43 messaggi dal 29 agosto 2007
Ciao mi sto cimentando con vb.net all'invocazione di metodi di un ws con tecnologia REST; Il servizio che devo richiamare devo utilizzare il metodo Http POST con content-type = multipart/form-data.
Devo uplodare 3 file:

PARAMFILE per il file di parametri
INDEXFILE per il file di indice
DATAFILE per il file di dati

La richiesta di ha bisogno di passare informazioni sia tramite l'url, che tramite l'upload dei file. In particolare nell'url deve essere riportato il codice identificativo, mentre nel pacchetto
multipart da comporre vanno inseriti i tre file.

Il problema è che non conosco la sintassi per inserire i tre file nel pacchetto multipart.

Sinora sono riuscita solo ad utilizzare il metodo Login

Dim wrequest As Net.HttpWebRequest
wrequest = Net.WebRequest.Create(sURL)
wrequest.Method = "POST"
wrequest.ContentType = "application/x-www-form-urlencoded"
Dim wResponse As Net.HttpWebResponse = wrequest.GetResponse()

Potete darmi una mano ? anche un'esempio di codice oppure un link dal quale avere info ?

Grazie

TheNet
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
se puoi utilizzare il framework 4.5 dai un'occhiata a questi esempi che usano la classe HttpClient, che ha una API più semplice da usare rispetto a quella dell'HttpWebRequest.
http://stackoverflow.com/questions/16416601/c-sharp-httpclient-4-5-multipart-form-data-upload

E' comunque fattibile anche con HttpWebRequest, come vedi in questo esempio (un po' meno leggibile rispetto agli altri).
http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data


ciao,
Moreno

Enjoy learning and just keep making
43 messaggi dal 29 agosto 2007
Purtroppo per me è tutto più o meno incomprensibile ...

Grazie

TheNet
43 messaggi dal 29 agosto 2007
In sostanza dovrei convertire questa routine java in vb.net :

InputStream parametersStream, String parametersFileName,
InputStream indexStream, String indexMimeType, String indexFileName,
InputStream dataStream, String dataMimeType, String dataFileName) {
try {
MultipartEntity requestEntity = new MultipartEntity();
requestEntity.addPart("PARAMFILE", new InputStreamBody(parametersStream,
"conserve.xml"));
requestEntity.addPart(?INDEXFILE?, new InputStreamBody(indexStream, indexMimeType,
indexFileName));
requestEntity.addPart(?DATAFILE?, new InputStreamBody(dataStream, dataMimeType,
dataFileName));
// creazione request
HttpResponse response = this.restInvoker.callWS(conserveResourceUrl,
HttpMethod.POST, requestEntity);
if (response.getStatusLine().getStatusCode() == 201) {
// chiamata conserve ok
logger.debug("Documento conservato.");
} else
logger.debug("Documento non conservato.");
indexStream.close();
dataStream.close();
parametersStream.close();
}
catch (Exception ex) {//gestire eccezione}
}

Non riesco a trovare MultipartEntity , mi dice tipo non definito ???? che Imports devo aggiungere ?

Ma possibile che sia così complesso ?

TheNet
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao Gabriella,
forza e coraggio, non è complesso ma ci sono alcune parti che devi imparare a conoscere.

Cominciamo eliminando il superfluo.

Non riesco a trovare MultipartEntity , mi dice tipo non definito ???? che Imports devo aggiungere ?

Non la trovi perché è una classe Java che non puoi usare in un programma .NET. Inoltre, non cercare di tradurre linea per linea: cerca invece di capire l'intento di quella routine affinché tu possa riprodurlo nella tua applicazione VB.NET.

In .NET dobbiamo usare delle classi equivalenti e l'esempio che ti avevo linkato usa, per l'appunto, quelle classi.
Anche se sembra complesso a prima vista, quell'esempio ti permetterà di arrivare alla soluzione quindi tanto vale prenderlo di petto e cercare di capire che classi usa e a che scopo.

Se pensi che possa semplificarti la comprensione, crea una nuova applicazione Console in VB.NET in cui cominci a fare dei test usando quel codice. In questo modo non avrai altre distrazioni e potrai concentrarti solo su quello.

Ti presento brevemente le classi usate nell'esempio (mi riferisco a questo).

Se hai bisogno di un aiuto nel convertire il codice C# a VB.NET, usa questo convertitore.
http://converter.telerik.com/

Le classi che ti indico qui sotto sono linkate alla documentazione, in modo che tu possa vedere che i riferimenti e gli Imports da aggiungere (ma Visual Studio ti aiuta in questo perché se fai CTRL + . mentre sei posizionata sul nome della classe ti suggerisce automaticamente gli Imports necessari).
  • La classe HttpClient è quella che si occuperà materialmente di inviare le richieste web al server remoto, grazie al suo metodo PostAsync, che accetta un URL e un contenuto da inviare.
  • Il contenuto sarà un oggetto di tipo HttpContent, che è una classe base per vari tipi di contenuto. Nel nostro caso specifico, il contenuto della richiesta sarà di tipo multipart e perciò si usa la classe MultipartFormDataContent, che è una sorta di contenitore per vari altri tipi di contenuto. Infatti dispone di un metodo Add che userai per aggiungere i 3 diversi tipi di informazione che devi inviare al server, ovvero i parametri, l'indice e i dati che mi sembrano essere tutti e 3 dei file (ti prego di confermarmelo).
  • Se sono veramente dei file, puoi creare 3 istanze di StreamContent che andranno tutte e 3 aggiunte al MultipartFormDataContent mediante il suo metodo Add di cui abbiamo parlato. Quando istanzi uno StreamContent, devi fornirgli un oggetto Stream, che puoi ottenere dal metodo statico File.OpenRead, fornendo il percorso completo del file.
  • Quando finalmente hai preparato l'oggetto MultipartFormDataContent comprensivo di tutte le sue 3 parti, passalo come argomento al metodo PostAsync dell'HttpClient di cui parlavamo all'inizio.
  • Il metodo PostAsync è asincrono. Dimmi se hai mai usato il pattern di programmazione asincrona basato sui task, in caso chiariamo anche quello. Comunque, dal PostAsync otterrai un oggetto di tipo HttpResponseMessage. Esso ha una proprietà Status che dovrai controllare per sapere se è 201, come nella routine Java. Dato che lo status qui non è propriamente un numero intero ma un'enumerazione, dovrai compararlo con HttpStatusCode.Created, che è il significato dello status 201.


Per quanto sembri difficile, non ti demoralizzare. Eventualmente fai domande che ti permettono di fare ogni volta un passo avanti.

ciao,
Moreno

Enjoy learning and just keep making
43 messaggi dal 29 agosto 2007
Innanzitutto lavoro con il framework 2... non so se è utile ...

Ho creato questa routine (che non funziona)

Dim wrequest As Net.HttpWebRequest

Dim boundary As String = IO.Path.GetRandomFileName
Dim header As New System.Text.StringBuilder()
Dim Element As Object
Dim sNames(0 To 2) As String

sNames(0) = strConserveTmpPath & "conserve.xml"
sNames(1) = strConserveTmpPath & "index.xml"
sNames(2) = strConserveTmpPath & "testconservazione1.pdf"

For Each Element In sNames

If File.Exists(Element) Then

header.AppendLine("--" & boundary)
header.Append("Content-Disposition: form-data; name=""files[]"";")
header.AppendFormat("filename=""{0}""", IO.Path.GetFileName(Element))
header.AppendLine()
header.AppendLine("Content-Type: application/octet-stream")
header.AppendLine()

Dim headerbytes() As Byte = System.Text.Encoding.UTF8.GetBytes(header.ToString)
Dim endboundarybytes() As Byte = System.Text.Encoding.ASCII.GetBytes(vbNewLine & "--" & boundary & "--" & vbNewLine)

wrequest = Net.WebRequest.Create(sURL)
wrequest.ContentType = "multipart/form-data; boundary=" & boundary
wrequest.Method = "POST"
wrequest.ContentLength = headerbytes.Length + New IO.FileInfo(Element).Length + endboundarybytes.Length
wrequest.KeepAlive = True
wrequest.Headers("LDSessionID") = strldSessionID

Dim s As IO.Stream = wrequest.GetRequestStream
s.Write(headerbytes, 0, headerbytes.Length)
Dim filebytes() As Byte = My.Computer.FileSystem.ReadAllBytes(Element)
s.Write(filebytes, 0, filebytes.Length)
s.Write(endboundarybytes, 0, endboundarybytes.Length)
s.Close()

End If
Next

Dim wResponse As Net.HttpWebResponse = wrequest.GetResponse()

L'errore che compare

Errore del server remoto: (400) Richiesta non valida.

Come posso capire cosa non è corretto ?

TheNet
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Gabriella,
non so esattamente dove sia il problema. Vedo che hai un ciclo For Each in cui riassegni la wrequest ad ogni giro, e questo non è corretto perché devi creare una sola richiesta che contiene più files al suo interno.
Questa sarebbe sicuramente una questione da sistemare ma io ti consiglio di provare ad applicare gli esempi.

TheNet ha scritto:

Innanzitutto lavoro con il framework 2... non so se è utile ...

Sì, è utile, perché ci indica cosa ci è consentito usare e cosa no.
Tutto il mio post precedente ignoralo perché si applica solo al framework 4.5 e non va bene nel tuo caso.

Col Framework 2.0 segui questo esempio che ti avevo mandato:
http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data#answer-567460
Lì trovi la funzione chiamata "UploadFilesToRemoteUrl" che ti serve per caricare file ad un url remoto. Potrebbe funzionarti senza dover fare modifiche; devi solo convertirla in VB.NET usando questo servizio.

Poi la invochi così:
Dim sNames(0 To 2) As String
sNames(0) = strConserveTmpPath & "conserve.xml"
sNames(1) = strConserveTmpPath & "index.xml"
sNames(2) = strConserveTmpPath & "testconservazione1.pdf"
UploadFilesToRemoteUrl(sURL, sNames, "", new NameValueCollection())


TheNet ha scritto:

Errore del server remoto: (400) Richiesta non valida.

Devi cercare di diagnosticare da sola questo genere di problemi. Installa Fiddler, che serve ad osservare le richieste che il tuo programma rivolge al server. Confrontale con gli esempi di richiesta forniti dall'azienda che ha realizzato il servizio.
Chi non è in possesso di tali esempi non può sapere se la richiesta che stai componendo è giusta o sbagliata.

ciao,
Moreno

Enjoy learning and just keep making
43 messaggi dal 29 agosto 2007
Ho fatto come mi hai detto ... in effetti della routine segnalata non ho dovuto modificare nulla se non aggiungere il parametro da passare al server per l'autenticazione.
Ho dovuto anche aggiungere la funzione :

Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function

Mi segnalava l'errore (nome "InlineAssignHelper" no dichiarato)

Public Shared Sub UploadFilesToRemoteUrl(ByVal url As String, ByVal files As String(), ByVal logpath As String, ByVal nvc As NameValueCollection, ByVal strldSessionID As String)

Dim length As Long = 0
Dim boundary As String = "----------------------------" + DateTime.Now.Ticks.ToString("x")


Dim httpWebRequest2 As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
httpWebRequest2.ContentType = Convert.ToString("multipart/form-data; boundary=") & boundary
httpWebRequest2.Method = "POST"
httpWebRequest2.KeepAlive = True
httpWebRequest2.Headers("LDSessionID") = strldSessionID

Dim memStream As Stream = New System.IO.MemoryStream()

Dim boundarybytes As Byte() = System.Text.Encoding.ASCII.GetBytes((Convert.ToString(vbCr & vbLf & "--") & boundary) + vbCr & vbLf)


Dim formdataTemplate As String = (Convert.ToString(vbCr & vbLf & "--") & boundary) + vbCr & vbLf & "Content-Disposition: form-data; name=""{0}"";" & vbCr & vbLf & vbCr & vbLf & "{1}"

For Each key As String In nvc.Keys
Dim formitem As String = String.Format(formdataTemplate, key, nvc(key))
Dim formitembytes As Byte() = System.Text.Encoding.UTF8.GetBytes(formitem)
memStream.Write(formitembytes, 0, formitembytes.Length)
Next

memStream.Write(boundarybytes, 0, boundarybytes.Length)

Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""" & vbCr & vbLf & " Content-Type: application/octet-stream" & vbCr & vbLf & vbCr & vbLf

For i As Integer = 0 To files.Length - 1

'string header = string.Format(headerTemplate, "file" + i, files[i]);
Dim header As String = String.Format(headerTemplate, "uplTheFile", files(i))

Dim headerbytes As Byte() = System.Text.Encoding.UTF8.GetBytes(header)

memStream.Write(headerbytes, 0, headerbytes.Length)


Dim fileStream As New FileStream(files(i), FileMode.Open, FileAccess.Read)
Dim buffer As Byte() = New Byte(1023) {}

Dim bytesRead As Integer = 0

While (InlineAssignHelper(bytesRead, fileStream.Read(buffer, 0, buffer.Length))) <> 0

memStream.Write(buffer, 0, bytesRead)
End While


memStream.Write(boundarybytes, 0, boundarybytes.Length)


fileStream.Close()
Next

httpWebRequest2.ContentLength = memStream.Length

Dim requestStream As Stream = httpWebRequest2.GetRequestStream()

memStream.Position = 0
Dim tempBuffer As Byte() = New Byte(memStream.Length - 1) {}
memStream.Read(tempBuffer, 0, tempBuffer.Length)
memStream.Close()
requestStream.Write(tempBuffer, 0, tempBuffer.Length)
requestStream.Close()


Dim webResponse2 As WebResponse = httpWebRequest2.GetResponse()

Dim stream2 As Stream = webResponse2.GetResponseStream()
Dim reader2 As New StreamReader(stream2)


MessageBox.Show(reader2.ReadToEnd())

webResponse2.Close()
httpWebRequest2 = Nothing
webResponse2 = Nothing
End Sub

Mi restituisce sempre l'errore "Errore del server remoto : 8400) richiesta non valida"

Ora provo ad utilizzare il programma che mi hai indicato

Grazie

TheNet

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.