Can you please explain why the following piece of code fails to work?
static void Main(string[] args)
{
var simpleObject = new SimpleObjectDTO { Id = 1, Name = "Jacob" };
const string format = "{2} object properties are: Id {0} Name {1}";
Console.WriteLine(format, simpleObject.Id, simpleObject.Name, "Original");
var clone = simpleObject.Clone() as SimpleObjectDTO;
// ReSharper disable PossibleNullReferenceException
Console.WriteLine(format, clone.Id, clone.Name, "Clone");
// ReSharper restore PossibleNullReferenceException
Console.ReadLine();
}
where
[ProtoContract]
public class SimpleObjectDTO : ICloneable
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
public object Clone()
{
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, this);
stream.Flush();
var clone = Serializer.Deserialize<SimpleObjectDTO>(stream);
return clone;
}
}
}
The code runs just fine but the deserialized object has 0 and an empty string
as the appropriate properties' values.
Upd.:
If I serialize into a binary file and then open if for reading thus creating a new stream
the code works. Is there any possibility of avoiding intermediate binary files and using only one stream for both serializing and deserializing?
Thr problem is the stream's position needs to be reset to zero.
As an alternative:
return Serializer.DeepClone(this);
Figured out the issue, forgot to reset the memory stream's position
Related
I wrote my own installer UI with burn bootstrapper. It has a WPF frontend. I have an EXE with 3 MSI pacakges included. So when I try to install it in a disk with not enough space, how can I show an error message dialog in my installer UI? Is there a callback using which I can find if there is enough disk space? Please advice.
I'm looking at doing the same.
The secret is to read and parse the BootstrapperApplicationData.xml.
You can then use InstalledSize attribute from the WixPackageProperties element. This link Getting Display Name from PackageID shows you how do read that file at runtime. Note that you'll have to add in the InstalledSize to the relevant structure.
It'll be up to you to go and check the disk space compared to the sum of those numbers and flag that up to the user prior to install.
This is a copy/paste of the some of my code:
using System.Collections.ObjectModel;
using System.Xml.Serialization;
public class PackageInfo
{
[XmlAttribute("Package")]
public string Id { get; set; }
[XmlAttribute("DisplayName")]
public string DisplayName { get; set; }
[XmlAttribute("Description")]
public string Description { get; set; }
[XmlAttribute("InstalledSize")]
public int InstalledSize { get; set; }
}
[XmlRoot("BootstrapperApplicationData", IsNullable = false, Namespace = "http://schemas.microsoft.com/wix/2010/BootstrapperApplicationData")]
public class BundleInfo
{
[XmlElement("WixPackageProperties")]
public Collection<PackageInfo> Packages { get; set; } = new Collection<PackageInfo>();
}
public static class BundleInfoLoader
{
private static readonly string bootstrapperApplicationData = "BootstrapperApplicationData.xml";
public static BundleInfo Load()
{
var bundleFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var path = Path.Combine(bundleFolder, bootstrapperApplicationData);
var xmlSerializer = new XmlSerializer(typeof(BundleInfo));
BundleInfo result;
using (var fileStream = new FileStream(path, FileMode.Open))
{
var xmlReader = XmlReader.Create(fileStream);
result = (BundleInfo)xmlSerializer.Deserialize(xmlReader);
}
return result;
}
}
I am having an issue trying to send a message to the Azure service bus using the REST API and have it received using the .NET azure service bus client API classes. I can happily send and receive messages using these objects using the SDK alone, but get problems when trying to use the REST api.
I have narrowed the issue down to this minimal repro I think. Basically if I serialize my object with a small amoutn of XML as the payload thee everything works ok. If I add slightly more XML then I get an exception deserializing it. this should cut&paste into a new console application to allow repro of the issue:
using System.IO;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Xml;
using System.Xml.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
GetMessageBytes(Guid.NewGuid());
}
private static byte[] GetMessageBytes(Guid requestId)
{
var payload = XElement.Parse(#"
<blah Type='TransactionRequest' Version='1' xmlns=''>
<SomeData Type='Request' Selection='All'></SomeData>
</blah>");
var invalidPayload = XElement.Parse(#"
<blah Type='TransactionRequest' Version='1' xmlns=''>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
</blah>");
Message<XElement> message = new Message<XElement>()
{
Label = "Label",
RequestId = requestId,
Payload = payload
};
var messageBytes = EncodeMessage(message);
var expectedResponse = DecodeMessage<Message<XElement>>(messageBytes);
message = new Message<XElement>()
{
Label = "Label",
RequestId = requestId,
Payload = invalidPayload
};
messageBytes = EncodeMessage(message);
expectedResponse = DecodeMessage<Message<XElement>>(messageBytes);
Console.WriteLine(expectedResponse);
return messageBytes;
}
private static byte[] EncodeMessage<T>(T message)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
var memoryStream = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memoryStream);
serializer.WriteObject(binaryDictionaryWriter, message);
binaryDictionaryWriter.Flush();
var bytesToPost = memoryStream.GetBuffer();
return bytesToPost;
}
private static T DecodeMessage<T>(byte[] response)
{
var ms = new MemoryStream(response);
var serializer = new DataContractSerializer(typeof(T));
XmlDictionaryReader binaryDictionaryReader = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
var message = serializer.ReadObject(binaryDictionaryReader);
return (T)message;
}
}
[MessageContract(WrapperName = "Message", WrapperNamespace = "http://blah.co.uk/contracts", IsWrapped = true)]
public sealed class Message<T> where T : class
{
[MessageHeader(Namespace = "http://blah.co.uk/contracts", Name = "RequestId")]
public Guid RequestId { get; set; }
[MessageHeader(Namespace = "http://blah.co.uk/contracts", Name = "Label")]
public string Label { get; set; }
[MessageBodyMember(Namespace = "http://blah.co.uk/contracts", Name = "Payload")]
public T Payload { get; set; }
[MessageBodyMember(Namespace = "http://blah.co.uk/contracts", Name = "MonitoringResults")]
public MessageTimestamp MessageTimestamp { get; set; }
}
[DataContract]
public class MessageTimestamp
{
private ICollection<Timestamp> timestamps = new List<Timestamp>();
[DataMember]
public ICollection<Timestamp> GetAllTimestamps
{
get
{
return timestamps.ToList();
}
private set
{
timestamps = new List<Timestamp>(value);
}
}
}
public class Timestamp
{
public Operation Operation { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan TimeTaken
{
get
{
return EndTime - StartTime;
}
}
}
public enum Operation
{
OverallProcessing
}
The error that is thrown is:
There was an error deserializing the object of type
SerialisationIssue.Message1[[System.Xml.Linq.XElement, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]`.
The input source is not correctly formatted.
I have tried serialising large amounts of just XML (ie no Message<XElement> wrapper) and that works ok, so I'm sure its not actually related to the size of the XML, but that consistently make it break.
I've reflected the actual class that is used in the ServiceBus SDK client libraries and tried to use the deserialiser found in there (DataContractBinarySerializer) but that has made no difference and seems to basically do the same thing that I'm doing manually anyway.
Any ideas on how I can find what the actual problem is? And how I might go about fixing it?
So the issue is indeed related to some apparent bug in the XmlBinaryReader as outlined in this connect issue
which can be worked around by writing some whitespace at the end of the serialized data, as suggested in this post
I need to make a query against a document collection that matches several properties.
(Cross post from the mailing list: https://groups.google.com/forum/?fromgroups=#!topic/ravendb/r5f1zr2jd_o)
Here is the document:
public class SessionToken
{
[JsonProperty("jti")]
public string Id { get; set; }
[JsonProperty("aud")]
public Uri Audience { get; set; }
[JsonProperty("sub")]
public string Subject { get; set; }
[JsonProperty("claims")]
public Dictionary<string, string> Claims { get; set; }
}
And here is the test:
[TestFixture]
public class RavenDbTests
{
private IDocumentStore documentStore;
[SetUp]
public void SetUp()
{
this.documentStore = new EmbeddableDocumentStore() { RunInMemory = true };
this.documentStore.Initialize();
}
[Test]
public async void FirstOrDefault_WhenSessionTokenExists_ShouldReturnSessionToken()
{
var c = new SessionToken()
{
Audience = new Uri("http://localhost"),
Subject = "NUnit",
Claims = new Dictionary<string, string>()
{
{ ClaimTypes.System, "NUnit" }
}
};
using (var session = this.documentStore.OpenAsyncSession())
{
await session.StoreAsync(c);
await session.SaveChangesAsync();
// Check if the token exists in the database without using Where clause
var allTokens = await session.Query<SessionToken>().ToListAsync();
Assert.That(allTokens.Any(x => x.Subject == "NUnit" && x.Audience == new Uri("http://localhost")));
// Try getting token back with Where clause
var token = await session.Query<SessionToken>().Customize(x => x.WaitForNonStaleResults()).Where(x => x.Subject == "NUnit" && x.Audience == new Uri("http://localhost")).ToListAsync();
Assert.IsNotNullOrEmpty(token.First().Id);
}
}
}
The last Assert is the one that is failing.
I must admit Im not sure whether this is a bug or a failure on my part.
As far as I understand, this is supposed to work.
PS. I´ve tried with a standalone document store as well as embedded without running in memory, but with same result.
You are getting stale results. In a unit test, you need to allow time for indexing to occur.
Add .Customize(x=> x.WaitForNonStaleResults()) to your queries and the test should pass.
Also, I think you left the Id property off your question when you cut/paste because it doesn't compile as-is.
UPDATE
Per discussion in comments, the issue was that you were applying the [JsonProperty] attribute to the Id property. Since the Id property represents the document key, and is not serialized as part of the JSON document, you can't apply the [JsonProperty] attribute to it.
I want to create a composite Windows Workflow Activity (under .NET 4) that contains a predefined ReceiveAndSendReply Activity. Some of the properties are predefined, but others (particularly ServiceContractName) need to be set in the designer.
I could implement this as an Activity Template (the same way ReceiveAndSendReply is implemented), but would rather not. If I later change the template, I'd have to update all previously created workflows manually. A template would also permit other developers to change properties that should be fixed.
Is there a way to do this from a Xaml Activity? I have not found a way to assign an Argument value to a property of an embedded Activity. If not, what technique would you suggest?
I haven't done this using a composite XAML activity and am getting some errors when I try but doing so through a NativeActivity is no problem. See the example code below.
public class MyReceiveAndSendReply : NativeActivity
{
private Receive _receive;
private SendReply _sendReply;
public string ServiceContractName { get; set; }
public string OperationName { get; set; }
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
_receive = _receive ?? new Receive();
_sendReply = _sendReply ?? new SendReply();
_receive.CanCreateInstance = true;
metadata.AddImplementationChild(_receive);
metadata.AddImplementationChild(_sendReply);
_receive.ServiceContractName = ServiceContractName;
_receive.OperationName = OperationName;
var args = new ReceiveParametersContent();
args.Parameters["firstName"] = new OutArgument<string>();
_receive.Content = args;
_sendReply.Request = _receive;
var results = new SendParametersContent();
results.Parameters["greeting"] = new InArgument<string>("Hello there");
_sendReply.Content = results;
base.CacheMetadata(metadata);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(_receive, ReceiveCompleted);
}
private void ReceiveCompleted(NativeActivityContext context, ActivityInstance completedInstance)
{
context.ScheduleActivity(_sendReply);
}
}
I'm personally committed to .net distributed caching solutions, but I think this question is interesting across all platforms.
Is there a distributed caching solution (or generic strategy) that allows to both store objects in the cache while maintaining the integrity of the references between them?
To exemplify - Suppose I have an object Foo foo that references an object Bar bar and also and object Foo foo2 that references that same Bar bar. If I load foo to the cache, a copy of bar is stored along with it. If I also load foo2 to the cache, a separate copy of bar is stored along with that. If I change foo.bar in the cache, the change does not impact foo2.bar :(
Is there an existing distributed cache solution that will enable me to load foo, foo2 and bar into the cache while maintaining the foo.bar foo2.bar references?
First and foremost
I do not know of any distributed system, and I do not pretend to build one. This post explains how you can simulate this behavior with .NET and C# using the IObjectReference interface with serializable objects.
Now, lets go on with the show
I do not know of such a distributed system, but you can somewhat easily achive this with .NET using the IObjectReference interface. Your implementation of ISerializable.GetObjectData would need to call SerializationInfo.SetType to point out a proxy class that implements IObjectReference, and would be able (with help from data provided by your GetObjectData method) to get a reference to the real object that should be used.
Example code:
[Serializable]
internal sealed class SerializationProxy<TOwner, TKey> : ISerializable, IObjectReference {
private const string KeyName = "Key";
private const string InstantiatorName = "Instantiator";
private static readonly Type thisType = typeof(SerializationProxy<TOwner, TKey>);
private static readonly Type keyType = typeof(TKey);
private static readonly Type instantiatorType = typeof(Func<TKey, TOwner>);
private readonly Func<TKey, TOwner> _instantiator;
private readonly TKey _key;
private SerializationProxy() {
}
private SerializationProxy(SerializationInfo info, StreamingContext context) {
if (info == null) throw new ArgumentNullException("info");
_key = (TKey)info.GetValue(KeyName, keyType);
_instantiator = (Func<TKey, TOwner>)info.GetValue(InstantiatorName, instantiatorType);
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
throw new NotSupportedException("This type should never be serialized.");
}
object IObjectReference.GetRealObject(StreamingContext context) {
return _instantiator(_key);
}
internal static void PrepareSerialization(SerializationInfo info, TKey key, Func<TKey, TOwner> instantiator) {
if (info == null) throw new ArgumentNullException("info");
if (instantiator == null) throw new ArgumentNullException("instantiator");
info.SetType(thisType);
info.AddValue(KeyName, key, keyType);
info.AddValue(InstantiatorName, instantiator, instantiatorType);
}
}
This code would be called with SerializationProxy.PrepareSerialization(info, myKey, myKey => LoadedInstances.GetById(myKey)) from your GetObjectData method, and your LoadedInstances.GetById should return the instance from a Dictionary<TKey, WeakReference> or load it from cache/database if it isnt already loaded.
EDIT:
I've wrote some example code to show what I mean.
public static class Program {
public static void Main() {
// Create an item and serialize it.
// Pretend that the bytes are stored in some magical
// domain where everyone lives happily ever after.
var item = new Item { Name = "Bleh" };
var bytes = Serialize(item);
{
// Deserialize those bytes back into the cruel world.
var loadedItem1 = Deserialize<Item>(bytes);
var loadedItem2 = Deserialize<Item>(bytes);
// This should work since we've deserialized identical
// data twice.
Debug.Assert(loadedItem1.Id == loadedItem2.Id);
Debug.Assert(loadedItem1.Name == loadedItem2.Name);
// Notice that both variables refer to the same object.
Debug.Assert(ReferenceEquals(loadedItem1, loadedItem2));
loadedItem1.Name = "Bluh";
Debug.Assert(loadedItem1.Name == loadedItem2.Name);
}
{
// Deserialize those bytes back into the cruel world. (Once again.)
var loadedItem1 = Deserialize<Item>(bytes);
// Notice that we got the same item that we messed
// around with earlier.
Debug.Assert(loadedItem1.Name == "Bluh");
// Once again, force the peaceful object to hide its
// identity, and take on a fake name.
loadedItem1.Name = "Blargh";
var loadedItem2 = Deserialize<Item>(bytes);
Debug.Assert(loadedItem1.Name == loadedItem2.Name);
}
}
#region Serialization helpers
private static readonly IFormatter _formatter
= new BinaryFormatter();
public static byte[] Serialize(ISerializable item) {
using (var stream = new MemoryStream()) {
_formatter.Serialize(stream, item);
return stream.ToArray();
}
}
public static T Deserialize<T>(Byte[] bytes) {
using (var stream = new MemoryStream(bytes)) {
return (T)_formatter.Deserialize(stream);
}
}
#endregion
}
// Supercalifragilisticexpialidocious interface.
public interface IDomainObject {
Guid Id { get; }
}
// Holds all loaded instances using weak references, allowing
// the almighty garbage collector to grab our stuff at any time.
// I have no real data to lend on here, but I _presume_ that this
// wont be to overly evil since we use weak references.
public static class LoadedInstances<T>
where T : class, IDomainObject {
private static readonly Dictionary<Guid, WeakReference> _items
= new Dictionary<Guid, WeakReference>();
public static void Set(T item) {
var itemId = item.Id;
if (_items.ContainsKey(itemId))
_items.Remove(itemId);
_items.Add(itemId, new WeakReference(item));
}
public static T Get(Guid id) {
if (_items.ContainsKey(id)) {
var itemRef = _items[id];
return (T)itemRef.Target;
}
return null;
}
}
[DebuggerDisplay("{Id} {Name}")]
[Serializable]
public class Item : IDomainObject, ISerializable {
public Guid Id { get; private set; }
public String Name { get; set; }
// This constructor can be avoided if you have a
// static Create method that creates and saves new items.
public Item() {
Id = Guid.NewGuid();
LoadedInstances<Item>.Set(this);
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context) {
// We're calling SerializationProxy to call GetById(this.Id)
// when we should be deserialized. Notice that we have no
// deserialization constructor. Fxcop will hate us for that.
SerializationProxy<Item, Guid>.PrepareSerialization(info, Id, GetById);
}
#endregion
public static Item GetById(Guid id) {
var alreadyLoaded = LoadedInstances<Item>.Get(id);
if (alreadyLoaded != null)
return alreadyLoaded;
// TODO: Load from storage container (database, cache).
// TODO: The item we load should be passed to LoadedInstances<Item>.Set
return null;
}
}