18 messaggi dal 28 aprile 2006
Nel mio sito di e-commerce sto utilizzando SqlTableProfileProvider per inserire i dati del profilo utente all'interno di una tabella sql.

Sto utilizzando una proprietà di tipo binario per inserire il valore del carrello in un campo di questa tabella.

Ogni volta che tento di inserire questa proprietà ho questo errore: "No mapping exists from object Commerce.ShoppingCart to a known managed provider native type".
Con il default profile provider tutto funziona perfettamente, anche con la presenza di questa proprietà binaria che rappresenta il carrello.

Questo è il codice utilizzato:

In web.config:
<properties>
....
<add name="Cart" serializeAs="Binary" type="Commerce.ShoppingCart" allowAnonymous="true" customProviderData="Carrello;Binary;true"/>
....
</properties>

In Shopping.vb il codice è:
Namespace Commerce
<Serializable()>_
Public Class ShoppingCart
.....
End Class

In sql table:
....
Column Name: Cart
Data Type: varbinary(MAX)
Allow nulls: true
....

Uso la vb class SqlTableProfileProvider. All'interno di questa classe ho provato a serializzare il valore ma penso non sia corretto.

Come posso utilizzare proprietà binarie con questo provider?

Ringrazio chi vorrà aiutarmi.

Marco
hai già letto il whitePaper quà? http://www.asp.net/sandbox/samp_profiles.aspx?tabid=62.

ciao marco

Chi parla senza modestia troverà difficile rendere buone le proprie parole.
Confucio

http://nostromo.spaces.live.com/default.aspx
18 messaggi dal 28 aprile 2006
Ciao,

Si ho già letto il whitePaper dell'autore della classe ma non trovo nulla che possa aiutarmi.

Ho provato anche ad implemetare un metodo per la serializzazione della classe:

In Shopping.vb:
Namespace Serializator
<Serializable()>_
Public Class BinarySerializator

Public Function ToBinary() as SqlTypes.SqlBinary
Dim f as New Runtinme.Serialization.Formatters.Binary.BinaryFormatter
Dim stream as New System.IO.MemoryStream
f.Serialize(stream, Me)

Dim buffer(stream.Lenght) as Byte
stream.Read(buffer, 0, CInt(stream.Lenght)

return buffer
EndFunction

End Class

In SqlTableProfileProvider.vb, nella subSetPropertyValues, ho scritto:
....
For each data in columnData
...
param.ParameterName = valueParam
Dim x as Commerce.ShoppingCart = data.Value
param.Value = x.ToBinary()
cmd.parameters.Add(param)
....

Mentre tento di deserializzare, mi da il seguente errore: "Binary Stream '0' does not contain a valid BinaryHeader. Prossible causes are invalid stream or object version change between serialization and deserialization".

Non riesco a capire se la serializzazione sia sbagliata (nel debug l'oggetto serializzato lo vedo con tutti bit a "0"), oppure se sbaglio altro.
2.190 messaggi dal 04 marzo 2004
Contributi | Blog
La configurazione del Profile Provider mi sembra corretta, l'errore é riconducibile ad una non corrispondenza tra il tuo oggetto serializzato ed il tipo nativo che hai specificato nel file di configurazione.

Io penso che sia dovuto ad un problema di serializzazione, infatti dopo:

f.Serialize(stream, Me)

tu cerchi di leggere un array di byte che ancora non hai:

Dim buffer(stream.Lenght) as Byte
stream.Read(buffer, 0, CInt(stream.Lenght)

tra l'altro un oggetto serializzato é un array di byte; io modificherei questo codice in :

Dim _Serialized as byte[]
_Serialized = _stream.GetBuffer()
Dim _SqlBinary as SqlTypes.SqlBinary
_SqlBinary = new System.Data.SqlTypes.SqlBinary(_Serialized)
return _SqlBinary

(ho scritto in vb.net senza saperlo ne provarlo, prendilo come spunto)

Ti consiglio di dividere il tuo problema in processi piú piccoli, prima preoccupati di portare a termine la serializzazione e la deserializzazione, successivamente passa la palla a persistere queste informazioni al profile provider.

Alessio Leoncini (WinRTItalia.com)
.NET Developer, Interactive Designer, UX Specialist, Trainer
18 messaggi dal 28 aprile 2006
Ciao Novecento,

Ti ringrazio dell'aiuto. In effetti la serializzazione come mi hai indicato tu funziona perfettamente:

Questo è il codice finale:

Public Function ToBinary() As SqlTypes.SqlBinary
Dim f As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim stream As New System.IO.MemoryStream
f.Serialize(stream, Me)

Dim buffer(stream.Length) As Byte
buffer = stream.GetBuffer

Dim _SqlBinary As SqlTypes.SqlBinary
_SqlBinary = New System.Data.SqlTypes.SqlBinary(buffer)
Return buffer
End Function

Ho provato a deserializzare il contenuto del campo "carrello", recuperando i dati del profilo "manualmente" attraverso una semplice query che recupera il primo record della tabella Anagrafica, e tutto funziona.

Volendo a questo punto procedere al recupero delle proprietà del profilo attraverso il SqlTableProfileProvider ho un problema nella deserializzazione del carrello.

In particolare mi risulta sempre questo errore: "Unable to cast object of type 'System.Byte[]' to type 'Commerce.ShoppingCart'." all'interno della classe autogenerata di ProfileCommon:
....
Public Overridable Property Carrello() As Commerce.ShoppingCart
Get
Return CType(Me.GetPropertyValue("Carrello"),Commerce.ShoppingCart)
End Get
Set
Me.SetPropertyValue("Carrello", value)
End Set
End Property
....

Capisco bene il problema ma non so come poter indicare al ProfileCommon che questa proprietà "carrello" è del tipo 'Commerce.ShoppingCart', ma prima di fare il cast il valore deve essere deserializzato opportunamente. Quest'ultima operazione non posso certamente farla all'interno della classe autogenerata di ProfileCommon.
Del resto nelle proprietà specificate nel web.config il tipo di "carrello" deve rimanere così:

<add name="Carrello" serializeAs="Binary" type="Commerce.ShoppingCart" allowAnonymous="true" customProviderData="Carrello;Binary;true"/>

Nel carrello posso prevedere un metodo opportuno per la deserializzazione così come ho fatto per la serializzazione ma non so in quale punto invocare il metodo.

Grazie per chi vorra aiutarmi.

Marco
2.190 messaggi dal 04 marzo 2004
Contributi | Blog
La tua domanda é lecita ed interessante; SqlTableProfileProvider nasce per scrivere in "chiaro" le informazioni di profilo sul database (string-Nvarchar , Byte[]-Binary) o per cosí dire, scrivere direttamente dei tipi nativi del clr, infatti nella sua implementazione non viene considerata la proprietá di configurazione serializeAs , come invece fa l'implementazione base del Profile Provider.

Penso che tu debba mettere mano al codice di SqlTableProfileProvider ed estenderlo a "considerare" quella proprietá di configurazione, oppure fai un approccio meno portabile ma comunque efficiente, nel quale definisci un oggetto come portatore delle informazioni di profilo e nella sua implementazione fai:

public class MyProfile : ProfileBase
{
...
public Commerce.ShoppingCart ShoppingCart
{
get {
byte[] _bShoppingCart = ((byte[])(this.GetPropertyValue("ShoppingCart")))
return _bShoppingCart.Deserialize();
}
...

scusami, ti scrivo in c# e senza testare, prendilo sempre come idea.
Modificato da novecento il 30 gennaio 2007 12.03 -

Alessio Leoncini (WinRTItalia.com)
.NET Developer, Interactive Designer, UX Specialist, Trainer
18 messaggi dal 28 aprile 2006
Ti ringrazio per la risposta!
Finalmente ho ottenuto il risultato che volevo, grazie ovviamente al tuo aiuto.
Alla fine ho deciso di "estendere" il SqlTableProfileProvider prevedendo la deserializzazione di proprietà serializzate binarie.
Non so se la mia soluzione sia la migliore possibile, ho fatto diverse prove e tutto sembra funzionare perfettamente.

In particolare all'interno della Sub GetProfileDataFromTable ho modificato in questo modo:
........
Do While i < columnData.Count
Dim val As Object = reader.GetValue(i + 1)
Dim colData As ProfileColumnData = columnData(i)
Dim propValue As SettingsPropertyValue = colData.PropertyValue

'Only initialize a SettingsPropertyValue for non-null values
If Not IsNothing(val) AndAlso Not IsDBNull(val) Then

If Not columnData(i).PropertyValue.Deserialized And
columnData(i).PropertyValue.Property.SerializeAs
= SettingsSerializeAs.Binary Then
Dim f As New BinaryFormatter

Dim stream As New System.IO.MemoryStream

Dim obj As Object

Dim buffer() As Byte = val
stream.Write(buffer, 0, buffer.Length)
stream.Seek(0, IO.SeekOrigin.Begin)

obj = f.Deserialize(stream)

Dim tipo As String = columnData(i).PropertyValue.PropertyValue.GetType.ToString

propValue.PropertyValue = Convert.ChangeType(obj, Type.GetType(tipo))
Else
propValue.PropertyValue = val
End If
propValue.IsDirty = False
propValue.Deserialized = True
End If

i += 1
Loop
..........

Ho cercato di generalizzare il tipo per comprendere eventuali altre proprietà serializzate nel profilo.

Sono bene accetti consigli su eventuali miglioramenti.

Grazie ancora,

Marco

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.