I perform serialization to soap envelop using this:
[Serializable]
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person("Tom", 29);
Person person2 = new Person("Bill", 25);
Person[] people = new Person[] { person, person2 };
SoapFormatter formatter = new SoapFormatter();
using (FileStream fs = new FileStream("people.soap", FileMode.OpenOrCreate))
{
formatter.Serialize(fs, people);
Console.WriteLine("Serialized");
}
using (FileStream fs = new FileStream("people.soap", FileMode.OpenOrCreate))
{
Person[] newPeople = (Person[])formatter.Deserialize(fs);
Console.WriteLine("Deserialized");
foreach (Person p in newPeople)
{
Console.WriteLine("Name: {0} --- Age: {1}", p.Name, p.Age);
}
}
Console.ReadLine();
}
}
I get serialized soap as below:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENC:Array SOAP-ENC:arrayType="a1:Person[2]" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<item href="#ref-3"/>
<item href="#ref-4"/>
</SOAP-ENC:Array>
<a1:Person id="ref-3" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_x003C_Name_x003E_k__BackingField id="ref-5">Tom</_x003C_Name_x003E_k__BackingField>
<_x003C_Age_x003E_k__BackingField>29</_x003C_Age_x003E_k__BackingField>
</a1:Person>
<a1:Person id="ref-4" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_x003C_Name_x003E_k__BackingField id="ref-6">Bill</_x003C_Name_x003E_k__BackingField>
<_x003C_Age_x003E_k__BackingField>25</_x003C_Age_x003E_k__BackingField>
</a1:Person>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How can I get rid of prefixes "x003C" and suffixes "_x003E_k__BackingField"
in my fields "Name" and "Age"?
Thank you very much for your answers
you don't need to use [Serializable] attribute for Person class. remove it and test it again.
You almost certainly don't need it unless you are actually using BinaryFormatter or SoapFormatter.
for more info and knowing reason:
https://stackoverflow.com/a/31498951/7979199
Related
I enable the xml serializer in my .net core 5 web api:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddXmlSerializerFormatters()
//.AddXmlDataContractSerializerFormatters()
.AddJsonOptions(o =>
{
o.JsonSerializerOptions.PropertyNamingPolicy = null;
o.JsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"Routing Evaluator Package Demo Service ({appSettings.Environment})", Version = "v1" });
});
}
My controller takes a parameter
[HttpPost]
public ActionResult<TestResponse> Post(TestRequest request)
{
...
}
And my model looks like this:
[Serializable]
//[DataContract]
public class TestRequest
{
/// <summary>
/// The message addressing information
/// </summary>
//[DataMember]
[XmlArray("Items")]
[XmlArrayItem("Item")]
public Items Items { get; set; }
}
[Serializable]
[XmlRoot("Items")]
//[CollectionDataContract(Name = "Items")]
public class Items : List<Item>
{
}
[Serializable]
//[DataContract]
[XmlRoot("Item")]
public class Item
{
public string key {get;set;}
public string value {get;set;}
}
If I manually serialize an instance of my object, I get results like this:
Object Instance:
var request = new TestRequest()
{
Items = new Items()
{
new Item() {key = "A", value="1"},
new Item() {key = "B", value="2"},
new Item() {key = "C", value="3"}
}
};
Serialization:
using (var str = new MemoryStream())
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(DemoService.ServiceModels.EvaluationRequest));
ser.Serialize(str, request);
str.Flush();
str.Position = 0;
_output.WriteLine(str.ReadAsString());
}
Results:
<?xml version="1.0" encoding="utf-8"?>
<TestRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Item>
<key>A</key>
<value>1</value>
</Item>
<Item>
<key>B</key>
<value>2</value>
</Item>
<Item>
<key>C</key>
<value>3</value>
</Item>
</Items>
</TestRequest>
If I browse to the swagger page, the example it shows is:
<?xml version="1.0" encoding="UTF-8"?>
<TestRequest>
<Items>
<key>A</key>
<value>1</value>
</Items>
</TestRequest>
The sample it supplied is incorrect. It appears that the serializer that swagger is using is not the same as the serializer that the web api is using as specfied by AddXmlSerializerFormatters. Do I need to configure swagger somehow to make them match?
Your model is wrong, it should be like below
[Serializable]
public class TestRequest
{
/// <summary>
/// The message addressing information
/// </summary>
//[DataMember]
[XmlArray("Items")]
[XmlArrayItem("Item")]
public List<Item> Items { get; set; }
}
[Serializable]
public class Item
{
public string key {get;set;}
public string value {get;set;}
}
Using MSSQL with IDENTITY column for IDs,
how can I get entity IDs synchronized with table IDs after calling BulkInsert?
context.BulkInsert(entities);
Neither of both achieves the requested result:
context.BulkSynchronize(entities);
context.BulkMerge(entities);
Assume we have one entity
var newSomething = new Something { Id = 0 };
and the corresponding TSQL table column definition
ID int IDENTITY(1,1)
Entity Framework automatically sets Id after calling SaveChanges()
context.SomethingSet.Add(newSomething);
context.SaveChanges();
Assert.IsTrue(newSomething.Id != 0)
See also How can I get Id of inserted entity in Entity framework?
How does EFPlus provide a way of getting the Id of inserted entities?
Disclaimer: I'm the owner of the project Entity Framework Extensions
The Entity Framework Extensions library should by default already return the ids for inserted entities.
For example, the following code should already work and return ids when using with BulkInsert.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Windows.Forms;
namespace Z.EntityFramework.Extensions.Lab
{
public partial class Form_Request_Ids : Form
{
public Form_Request_DateNull()
{
InitializeComponent();
// CLEAR
using (var ctx = new CurrentContext())
{
ctx.EntitySimples.RemoveRange(ctx.EntitySimples);
ctx.SaveChanges();
}
// TEST
using (var ctx = new CurrentContext())
{
var list = new List<EntitySimple>();
list.Add(new EntitySimple() { Id = 0, IntColumn = 1, CreatedDate = DateTime.Now });
ctx.BulkInsert(list);
}
}
public class CurrentContext : DbContext
{
public CurrentContext()
: base("CodeFirstEntities")
{
}
public DbSet<EntitySimple> EntitySimples { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Types().Configure(x => x.ToTable(GetType().DeclaringType != null ? GetType().DeclaringType.FullName.Replace(".", "_") + "_" + x.ClrType.Name : ""));
base.OnModelCreating(modelBuilder);
}
}
public class EntitySimple
{
public int Id { get; set; }
public int IntColumn { get; set; }
public DateTime CreatedDate { get; set; }
}
}
}
If you still have the issue, try to contact us directly with an example info#zzzprojects.com or post your example here.
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
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
I'm in the process of writing a WCF application which will be consumed by a Silverlight application. I have done most of the design work and I am now doing the implementation, which has made me come up with this question.
Here's an example of something that exists in my application:
[DataContract]
class Person
{
[DataMember]
private Towel mostRecentlyUsedTowel;
[DataMember]
private Gym gym; //the gym that this person attends
...
}
[DataContract]
class Gym
{
[DataMember]
private List<Towel> towels; //all the towels this gym owns
...
}
Here's what I'm getting at: In my application mostRecentlyUsedTowel will be pointing at something in the towels list for the person's gym. Some of my requests will serialize a Person object.
Is the DataContractSerializer smart enough to notice its being asked to serialize the exact same instance of an object twice? If so, how does it deal with it?
If it will just go about serializing the same instance twice, how should I deal with this so I'm not sending unnecessary data over the link?
The following code:
[TestMethod]
public void CanSerializePerson()
{
var towel1 = new Towel() { Id = 1 };
var towel2 = new Towel() { Id = 2 };
var towel3 = new Towel() { Id = 3 };
var gym = new Gym();
gym.towels.Add(towel1);
gym.towels.Add(towel2);
gym.towels.Add(towel3);
var person = new Person()
{
recentlyUsedTowel = towel1,
gym = gym
};
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
var ser = new DataContractSerializer(typeof (Person));
ser.WriteObject(writer, person);
}
throw new Exception(sb.ToString());
}
public class Person
{
public Towel recentlyUsedTowel { get; set; }
public Gym gym { get; set; }
}
public class Gym
{
public Gym()
{
towels = new List<Towel>();
}
public List<Towel> towels { get; set; }
}
public class Towel
{
public int Id { get; set; }
}
will evaluate to:
<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org">
<gym>
<towels>
<Towel><Id>1</Id></Towel>
<Towel><Id>2</Id></Towel>
<Towel><Id>3</Id></Towel>
</towels>
</gym>
<recentlyUsedTowel><Id>1</Id></recentlyUsedTowel>
</Person>
If you added the IsReference property to the DataContract attribute of the Towel class like this:
[DataContract(IsReference=true)]
public class Towel
{
// you have to specify a [DataMember] in this because you are
// explicitly adding DataContract
[DataMember]
public int Id { get; set; }
}
you would get an output like this:
<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org">
<gym>
<towels>
<Towel z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>1</Id>
</Towel>
<Towel z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>2</Id>
</Towel>
<Towel z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>3</Id>
</Towel>
</towels>
</gym>
<recentlyUsedTowel z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
</Person>
Hope this Helps.