Error Reading Serialized Object? WP7 - serialization

I am reading an object from Isolated Storage with the following code:
public static T Load<T>(string name) where T : class, new()
{
T loadedObject = null;
using (IsolatedStorageFile storageFile = IsolatedStorageFile.GetUserStoreForApplication())
using (IsolatedStorageFileStream storageFileStream = new IsolatedStorageFileStream(name, System.IO.FileMode.OpenOrCreate, storageFile))
{
if (storageFileStream.Length > 0)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
loadedObject = serializer.ReadObject(storageFileStream) as T; //####Error Here####
}
if (loadedObject == null)
{
loadedObject = new T();
}
}
Upon reading my object I am getting a SecurityException which reads
"The type 'Microsoft.Xna.Framework.Media.Song' cannot be deserialized in partial trust because it does not have a public parameterless constructor."
My object class being read contains a Song property which is throwing the above error.
Is there some way around this? I would like for my Song property to be stored with my object. Any advice would be greatly appreciated! Thanks!

What is your goal?
Do you want to just play a song in the app?
Do you create your song in the app?
Do you want to have access to the song library?
Do you want to get the song from the web?
#1 Just add a song to your conent in your project. no need to use serialization.
#2 Use memory stream to mainulate it. save it and then load the stream. Use MediaElement.SetSource(Stream stream)
#3 Use MediaPlayerLauncher
#4 Song song = Song.FromUri..
You need to store it in a diffrent way. Exception explatins pretty much all why a Song is a bad choice in this case.
Look at this example.
http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/3080021c-3960-49a0-ac5b-ebf2680592e1

Related

ChronicleQueue - how to read custom object from tailer

I am very new to ChronicleQueue and I am unable to find a straight forward example of how can I read back my custom object from a tailer.
public class MyData extends AbstractMarshallable
I have my class containing some strings and numbers, I am able to write to queue using appender, but there is no straight forward api to call. how can i get a object of MyData from tailer.readDocument api?
Try with below code:
final DocumentContext context = queue.createTailer().readingDocument();
final MyData container = new MyData();
if (context.isPresent()) {
context.wire().getValueIn().marshallable(container);
}
this assumes that appending is performed in the following manner:
try (DocumentContext ctx = appender.writingDocument()) {
ctx.wire().getValueOut().marshallable(myData);
}

Update Document with external object

i have a database containing Song objects. The song class has > 30 properties.
My Music Tagging application is doing changes on a song on the file system.
It then does a lookup in the database using the filename.
Now i have a Song object, which i created in my Tagging application by reading the physical file and i have a Song object, which i have just retrieved from the database and which i want to update.
I thought i just could grab the ID from the database object, replace the database object with my local song object, set the saved id and store it.
But Raven claims that i am replacing the object with a different object.
Do i really need to copy every single property over, like this?
dbSong.Artist = songfromFilesystem.Artist;
dbSong.Album = songfromFileSystem.Album;
Or are there other possibilities.
thanks,
Helmut
Edit:
I was a bit too positive. The suggestion below works only in a test program.
When doing it in my original code i get following exception:
Attempted to associate a different object with id 'TrackDatas/3452'
This is produced by following code:
try
{
originalFileName = Util.EscapeDatabaseQuery(originalFileName);
// Lookup the track in the database
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
if (dbTracks.Count > 0)
{
track.Id = dbTracks[0].Id;
_session.Store(track);
_session.SaveChanges();
}
}
catch (Exception ex)
{
log.Error("UpdateTrack: Error updating track in database {0}: {1}", ex.Message, ex.InnerException);
}
I am first looking up a song in the database and get a TrackData object in dbTracks.
The track object is also of type TrackData and i just put the ID from the object just retrieved and try to store it, which gives the above error.
I would think that the above message tells me that the objects are of different types, which they aren't.
The same error happens, if i use AutoMapper.
any idea?
You can do what you're trying: replace an existing object using just the ID. If it's not working, you might be doing something else wrong. (In which case, please show us your code.)
When it comes to updating existing objects in Raven, there are a few options:
Option 1: Just save the object using the same ID as an existing object:
var song = ... // load it from the file system or whatever
song.Id = "Songs/5"; // Set it to an existing song ID
DbSession.Store(song); // Overwrites the existing song
Option 2: Manually update the properties of the existing object.
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.Artist = song.Artist;
existingSong.Album = song.Album;
Option 3: Dynamically update the existing object:
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.CopyFrom(song);
Where you've got some code like this:
// Inside Song.cs
public virtual void CopyFrom(Song other)
{
var props = typeof(Song)
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(p => p.CanWrite);
foreach (var prop in props)
{
var source = prop.GetValue(other);
prop.SetValue(this, source);
}
}
If you find yourself having to do this often, use a library like AutoMapper.
Automapper can automatically copy one object to another with a single line of code.
Now that you've posted some code, I see 2 things:
First, is there a reason you're using the Advanced.DocumentQuery syntax?
// This is advanced query syntax. Is there a reason you're using it?
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
Here's how I'd write your code using standard LINQ syntax:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
track.Id = existingTrackId;
_session.Store(track);
_session.SaveChanges();
}
Finally, #2: what is track? Was it loaded via session.Load or session.Query? If so, that's not going to work, and it's causing your problem. If track is loaded from the database, you'll need to create a new object and save that:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
var newTrack = new Track(...);
newTrack.Id = existingTrackId;
_session.Store(newTrack);
_session.SaveChanges();
}
This means you already have a different object in the session with the same id. The fix for me was to use a new session.

How to give the option to change the Textbloack foreground-color,size in Windowsphone7

I am completely new in Windowsphone7.i have develop sample application in that i want give the option to change the font-color,Size,style(Italic/Bold) as Dynamically(like RadEditor) .please help me how to resolve this option.
If you Develop your Application MVVM style then it is not so hard to do this. You just need a property for every setting you want to set dynamically and then bind to this properties. And you create a Settings View where you can set the properties and if you change them you use INotifyPropertyChanged to broadcast that your properties value changed and so every control which is bound to that property will change and redraw.
GalaSoft MVVM
MVVM Codeplex
Easy MVVM sample Application for Windows Phone 7
The link you found to save an image looks ok, but i did it a bit different, actually from the CameraCaptureTask you already get a WritableBitmap Image and you can save it like this.
To save the Image:
private void SaveToIsolatedStorage(WriteableBitmap image, string fileName)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(fileName))
{
myIsolatedStorage.DeleteFile(fileName);
}
using (var stream = myIsolatedStorage.OpenFile(fileName, FileMode.Create))
{
Extensions.SaveJpeg(image, stream, image.PixelWidth, image.PixelHeight,0, 100);
}
}
}
To read the Image:
private WritableBitmap ReadFromIsolatedStorage(string fileName)
{
WriteableBitmap bitmap = new WriteableBitmap(200,200);
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(fileName))
{
using (var stream = store.OpenFile(fileName,FileMode.Open))
{
bitmap.SetSource(stream);
}}
}
return bitmap;
}
I hope this will work because i wrote it from scratch. :)
And in your ViewModel you should have a WritableBitmap Property which is bound to your Image Control on your View.
To use a lot of images and work with them you should read a bit more about this, because somehow SL Images use a lot of memory so you will need to address this problem somehow in the future.

Exposing object of unknown type from a WCF service

[OperationContract]
public object GetDeserializedObject(int partyContactID)
{
PartyContact partyContact = GetPartyContactById(partyContactID);
ContactTermResultQueue resultQueue = GetContactTermResultQueueByID(partyContact.TemplateQueueID);
byte[] contactDataSetArray = resultQueue.QueryResult;
//Getting DataSet from the byte array
BinaryFormatter binaryFormatter = new BinaryFormatter();
Stream mStreamtoRead = new MemoryStream(contactDataSetArray);
object o = binaryFormatter.Deserialize(mStreamtoRead);
mStreamtoRead.Close();
object returnData=null;
if (o.GetType().IsArray)
{
object[] os = o as object[];
var value = from vs in os where (int) (vs.GetType().GetProperty("PartyID").GetValue(vs, null)) == partyContact.PartyID select vs;
if (value.Count() > 0)
{
returnData = value.First();
}
}
return returnData;
}
As I don't know what type of data we are going to have in the database, so wanted to return the object from this service, but it is giving me an exception.
Please let me know how can I achieve this?
Thanks in advance
You can't return object and expect it will work. The reason is that behind this code WCF engine uses serialization. When client receives message it must be able to deserialize it back to some object but to be able to do that it must know what type of object it received.
If you want to send "unknown" data use XElement. Client will receive just XML and it will be its responsibility to deal with it (parse it, deserialize it or whatever).
You can do certain things with the "raw" Message data type - but it's really not pretty programming...
Read about it here:
How to pass arbitrary data in a Message object using WCF
WCF : Untyped messages on WCF operations.

Can I stop my WCF generating ArrayOfString instead of string[] or List<string>

I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)