Soap WebService : Add attribute to an object based on a criteria - c#

I have a Soap WS that returns an object
[DataContract(Namespace = Configuration.Namespace)]
public class GetAccountResponse
{ [DataMember]
public List<Account> accounts { get; set; }
}
[DataContract(Namespace = Configuration.Namespace)]
public class Account
{ [DataMember(Name = "GUIDAccount")]
public Guid? accountid { get; set; }
[DataMember]
public List<Contract> Contracts { get; set; }
}
[DataContract(Namespace = Configuration.Namespace)]
public struct Contract
{
[DataMember(Name = "IDContrat")]
public string contrat { get; set; }
[DataMember(Name = "Phone")]
public string phone { get; set; }
}
I need to add a new attribute to the contract,but only on certain request criteria .
[DataMember(Name = "state")]
public string state { get; set; }
Response :
//all the time
return new GetAccountResponse
{
accounts = myaccounts.Values.ToList()
};
//my request matches a critertia the obejcts with the new
attribute
if(//mycriteria)
return new GetAccountResponse //object with state attribute
{
accounts = myaccounts.Values.ToList()
};
How I can achieve this by using the same objects GetAccountResponse?

Maybe you can try setting the EmitDefaultValue property of the DataMemberAttribute to false.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-member-default-values?redirectedfrom=MSDN
E.g:
[DataContract]
class MyDC
{
[DataMember]
public string DM1;
[DataMember(EmitDefaultValue = false)]
public string DM2;
[DataMember]
public string DM3;
}
Then setting this property to null:
[OperationContact]
public MyDC GetMyDC()
{
MyDC mdc = new MyDC();
if (condition)
{
// Code to prevent DM2 from being deserialized
mdc.DM2 = null;
}
return mdc;
}
This way, that property doesn't get written to the output stream on serialization.
source: Can I prevent a specific datamember from being deserialized?

Related

FromForm attribute not deserializing DataMember attributes with underscore or hyphen in Name property

I am trying to create a controller action that accepts a custom model as a parameter.
[HttpPost]
public void SendEvent([FromForm]WebHookRequest value)
{
SiteNotification notification = Mapper.Map<SiteNotification>(value);
if (notification != null)
{
Task.Run(() => { _siteNotifier.NotifySite(notification); });
Response.StatusCode = 200;
}
else
{
// Set the status code that mailgun expects on failure
Response.StatusCode = 406;
}
}
All values in the following model class are properly deserialized, except for OriginUrl and OriginMessageId, which are assigned null in the value parameter properties. I'm thinking that this might have something to do with the underscores in the DataMember(Name = "origin_message_id"). I have tried changing the underscores to hyphens and the same thing happened.
[DataContract]
public class WebHookRequest
{
[DataMember(Name = "event")]
public string Event { get; set; }
[DataMember(Name = "recipient")]
public string Recipient { get; set; }
[DataMember(Name = "domain")]
public string Domain { get; set; }
[DataMember(Name = "origin_url")]
public string OriginUrl { get; set; }
[DataMember(Name = "origin_message_id")]
public string OriginMessageId { get; set; }
[DataMember(Name = "timestamp")]
public string TimeStamp { get; set; }
[DataMember(Name = "token")]
public string Token { get; set; }
[DataMember(Name = "signature")]
public string Signature { get; set; }
}
How can I get the controller to properly deserialize the x-www-form-urlencoded keys that contain underscores or hyphens?

How to stop abstract class attributes to be pass in end result - WebAPI?

I have following scenario where I am getting OrderBase obstract class from ThirdParty library. And I have to inherit this abstract class into my model Order to get base attributes. Only below base attributes are required to be return as part of response.
Id
Name
OrderHistory
But actually it return all the base attributes as part of response due to inheritance. So is there any way by which we can restrict no of base attributes to be pass in the result without introduction of intermediate model(s) and mappings.
Code Sample- Third Party:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public string ClosingDate { get; set; }
}
public class DatabaseObject
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ClosingDate { get; set; }
public string OrderHistory { get; set; }
}
Model:
[DataContract]
[Serializable]
public class Order : OrderBase
{
public Order(DatabaseObject dbObject)
: base(dbObject)
{
this.OrderHistory = dbObject.OrderHistory;
}
[DataMember]
public string OrderHistory { get; set; }
}
API Code:
public class OrderController : ApiController
{
public Order GetOrder()
{
var dbObj = new DatabaseObject
{
Id = "O001",
Name = "Masala Packets",
ClosingDate = "01/02/2016",
Description = "Payment Successful",
OrderHistory = "",
Price = 10000
};
var orderObj = new Order(dbObj);
return orderObj;
}
}
Current JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets",
"Description": "Payment Successful",
"Price": 10000.0,
"ClosingDate": "01/02/2016"
}
Expected JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets"
}
You're serializing your domain models directly. That may not be a good idea. It's better to create a view model to send your serialized data and you will have complete control of what to serialize as well as better separation of concerns. Something like an OrderDTO
public class OrderDTO {
public string Id { get; set; }
public string Name { get; set; }
public string OrderHistory { get; set; }
}
In your web api method:
public class OrderController : ApiController
{
public OrderDTO GetOrder()
{
// return an OrderDTO instead;
}
}
Or you can use JsonIgnore property to exclude properties from serialization in case you want to expose your domain classes:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
[JsonIgnore]
public string Description { get; set; }
[DataMember]
[JsonIgnore]
public decimal Price { get; set; }
[DataMember]
[JsonIgnore]
public string ClosingDate { get; set; }
}
Use the [ScriptIgnore] attribute on the property you don't want to serialize as JSON.
If you don't want to do this in the parent class, you should shadow or overload the property in your child class and add the attribute there.
How to exclude property from Json Serialization

DataContractJsonSerializer serialization error: Consider using a DataContractResolver or add any types not known statically to the list

I am extending object that is being serialized with System.Runtime.Serialization.Json.DataContractJsonSerializer with two additional properties that are strings (not a complex types) by inheritance. .Net version used is .NET 4.
Serialization mechanism works fine for the base object but fails for object with two additional properties which seems very peculiar to me.
I am using [DataContract] attributes on both base and inherited object and all properties on both of them have [DataMember] attributes with names.
Both objects are internal but I don't see how this could affect serialization of child object.
While debugging I have observed base object to step in to the try block and get serialized, and child to blow up on line serializer.WriteObject(ms, sourceObject);
Adding known type attribute [KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))] on inherited object results in same error in same place.
Why can't I substitute base object with inherited one?
ChildObject:
namespace OnTheMoveLibrary.DataControls
{
[DataContract]
[KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))]
internal class OnTheMoveTreeBusinessComponentJavaScriptInitObject : OnTheMoveBusinessComponentJavaScriptInitObject
{
[DataMember(Name = "MasterRecordId")]
public string MasterRecordId { get; set; }
[DataMember(Name = "ParentRecordId")]
public string ParentRecordId { get; set; }
}
}
BaseObject:
namespace OnTheMoveLibrary.DataControls
{
[DataContract]
internal class OnTheMoveBusinessComponentJavaScriptInitObject : OnTheMoveValidatable
{
public OnTheMoveBusinessComponentJavaScriptInitObject()
{
this.SqlStatementObject = new OnTheMoveSelectStatement();
this.PreDefaults = new PreDefaultsObject();
this.ParentAssociations = new List<ParentAssociation>();
this.CalculatedFields = new List<OnTheMoveCalculatedField>();
this.BusinessComponentEvents = new List<BusinessComponentEvent>();
}
[DataMember(Name = "sqlStatementObject")]
public IOnTheMoveSelectStatement SqlStatementObject { get; set; }
[DataMember(Name = "calculatedFields")]
public List<OnTheMoveCalculatedField> CalculatedFields { get; set; }
[DataMember(Name = "knockoutContextName")]
public string KnockoutContextName { get; set; }
[DataMember(Name = "observable")]
public bool Observable { get; set; }
[DataMember(Name = "integrationObjectNameForNewRecords")]
public string IntegrationObjectNameForNewRecords { get; set; }
[DataMember(Name = "singleRecordNewFlag")]
public bool SingleRecordNewFlag { get; set; }
[DataMember(Name = "recordIndex")]
public int? RecordIndex { get; set; }
[DataMember(Name = "primaryTableName")]
public string PrimaryTableName { get; set; }
/// <summary>
/// The index within the query string of the "RecordId" parameter to use as a parent to insert new records, defaulting to 0
/// For example, if we have a recordid of "A123,B123" in the querystring, and set ParentQSRecordIdIndex=1, then B123 is used as the parent object when saving
/// </summary>
[DataMember(Name = "parentRecordIdQueryStringIndex")]
public int? ParentRecordIdQueryStringIndex { get; set; }
[DataMember(Name = "parentAssociations")]
public List<ParentAssociation> ParentAssociations { get; set; }
[DataMember(Name = "applyBindings")]
public bool ApplyBindings { get; set; }
[DataMember(Name = "PreDefaults")]
public PreDefaultsObject PreDefaults { get; set; }
/// <summary>
/// Gets or sets a list of <see cref="BusinessComponentEvent">BusinessComponentEvents</see>.
/// </summary>
[DataMember(Name = "businessComponentEvents")]
public List<BusinessComponentEvent> BusinessComponentEvents { get; set; }
[DataMember(Name = "automaticLeadingWildcards")]
public bool? AutomaticLeadingWildcards { get; set; }
[DataMember(Name = "automaticTrailingWildcards")]
public bool? AutomaticTrailingWildcards { get; set; }
[DataMember(Name = "enableAggregateFields")]
public bool? EnableAggregateFields { get; set; }
public override void ValidateProperties()
{
this.ValidateProperty("SqlStatementObject", this.SqlStatementObject != null ? this.SqlStatementObject.ToString() : null);
this.SqlStatementObject.ValidateProperties();
}
}
}
Serialization Mechanism:
public static string ObjectToJson<TValue>(TValue sourceObject)
{
string result = null;
Type type = typeof(TValue);
if (type == typeof(object))
{
return CallObjectToJsonWithSpecificType(sourceObject);
}
Type[] knownTypes = new[] { typeof(OnTheMoveSelectStatement), typeof(OnTheMoveCustomSelectStatement) };
var serializer = new DataContractJsonSerializer(type, knownTypes);
var ms = new MemoryStream();
try
{
serializer.WriteObject(ms, sourceObject);
result = Encoding.UTF8.GetString(ms.ToArray());
}
finally
{
ms.Close();
}
return result;
}
Figured it out myself.
Instead of adding base class type in attribute to the class that inherits
[DataContract]
[KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))]
internal class OnTheMoveTreeBusinessComponentJavaScriptInitObject : OnTheMoveBusinessComponentJavaScriptInitObject
one has to do the opposite - add to base class attribute with child class type (which breaks all the Object Oriented design since base class should never know about who inherits from it).
[DataContract]
[KnownType(typeof(OnTheMoveTreeBusinessComponentJavaScriptInitObject))]
internal class OnTheMoveBusinessComponentJavaScriptInitObject : OnTheMoveValidatable

datacontractserializer deserialize list<> always empty

I'm deserializing data received from a web-service.
The problem is that the deserialization of List returns an empty list and no exception are generated. Can you help me figure out why?
We have tried several possible syntax. The code below is the closest to the correct solution but we cannot deserialize correctly as a list of classes.
<ArrayOfBatch xmlns="http://schemas.datacontract.org/2004/07/myns" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<MaasBatch>
<BatchName>All Users</BatchName>
<Users>
<MaasUsers>
<firstName>bob</firstName>
<lastName>thetest</lastName>
<sourceEmail>bob#source.com</sourceEmail>
<sourceTenantID>111</sourceTenantID>
<targetEmail>bob#target.com</targetEmail>
<targetTenantID>222</targetTenantID>
</MaasUsers>
</Users>
</MaasBatch>
</ArrayOfBatch>
Code:
List<MAASBatch> lstMaasBatches = null;
try
{
string target = string.Empty;
using (var response = request.GetResponse())
{
Stream streamReader = response.GetResponseStream();
DataContractSerializer serializer = new DataContractSerializer(typeof(List<MAASBatch>));
lstMaasBatches = (List<MAASBatch>)serializer.ReadObject(streamReader);
streamReader.Close();
}
return lstMaasBatches;
}
catch (Exception exc)
{
return lstMaasBatches;
}
Class:
[DataContract(Name = "MAASBatch", Namespace = "http://schemas.datacontract.org/2004/07/myns")]
[KnownType(typeof(MAASUsers))]
public class MAASBatch
{
[DataMember]
public string BatchName { get; set; }
[DataMember]
public List<MAASUsers> Users { get; set; }
[OnDeserializing]
internal void OnDeserializingCallBack(StreamingContext streamingContext)
{
this.Users = new List<MAASUsers>();
}
}
[DataContract(Name = "MAASUsers", Namespace = "http://schemas.datacontract.org/2004/07/myns")]
public class MAASUsers
{
[DataMember]
public string firstName { get; set; }
[DataMember]
public string lastName { get; set; }
[DataMember]
public string sourceEmail { get; set; }
[DataMember]
public int sourceAgentID { get; set; }
[DataMember]
public string targetEmail { get; set; }
[DataMember]
public int targetAgentID { get; set; }
}
Try to add Order and Name attribute to the Contract class.
Sample:
[DataMember(Order = 1, Name = "firstName")]
The data contract element name is "MAASUsers" but in the xml the element is named "MaasUsers". The data contract serializer is case sensitive so it will NOT match these two up.

Serialization of class derived from List<> using DataContract

I'm trying to serialize a class derived from List<> using DataContract. The problem is that properties of my class won't get serialized.
My classes:
[CollectionDataContract] /*[Serializable]*/ /*[DataContract]*/
public class DownloadRuleCollection : List<DownloadRule> {
[DataMember(EmitDefaultValue = false)]
public string SomeProperty { get; set; }
//this is, in fact, more complex, but this is enough for the example
}
[DataContract]
public class DownloadRule {
[DataMember(EmitDefaultValue = false)]
public string Name { get; set; }
/*
more properties
...
*/
}
Test:
static void Main(string[] args) {
//fill test collection with some data...
var col = new DownloadRuleCollection { SomeProperty = "someText" };
var rule = new DownloadRule { Name = "test01" };
col.Add(rule);
rule = new DownloadRule { Name = "test02" };
col.Add(rule);
rule = new DownloadRule { Name = "test03" };
col.Add(rule);
//serialize
Console.WriteLine("serializing");
Serialize(col, "serializationTest.xml");
Console.WriteLine("serialized");
Console.ReadLine();
}
result:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfDownloadRule xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<DownloadRule>
<Name>test01</Name>
</DownloadRule>
<DownloadRule>
<Name>test02</Name>
</DownloadRule>
<DownloadRule>
<Name>test03</Name>
</DownloadRule>
</ArrayOfDownloadRule>
As you can see, the List's items are serialized (and deserialized) properly, but the List itself does not get serialized. I have tried to use different attributes:
[Serializable], no change;
[DataContract], throws exception during serialization (collections cant use this attribute)
btw I am serializing also private fields, so I cannot use XmlSerializer (or other classes that can't serialize private fields).
Use an IList instead. That should serialize properly.
[CollectionDataContract] /*[Serializable]*/ /*[DataContract]*/
public class DownloadRuleCollection : IList<DownloadRule> {
Here is an example i use and works perfectly:
[DataContract(Namespace="http://schemas.datacontract.org/2004/07/InboundIntegration.HL7Messaging")]
public class Message {
public Message() {
InsuranceList = new List<Insurance>();
MessageId = GuidComb.NewGuid();
}
[IgnoreDataMember]
public Guid MessageId { get; private set; }
#region "Data"
[DataMember]
public string MessageTypeIndicator { get; set; }
[DataMember]
public MessageConfiguration MessageConfiguration { get; set; }
[DataMember]
public Patient Patient { get; set; }
[DataMember]
public Encounter Encounter { get; set; }
[DataMember]
public IList<Insurance> InsuranceList { get; set; }
#endregion
Then insurance class looks like this:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/InboundIntegration.HL7Messaging")]
public class Insurance {
[DataMember]
public string ExternalPayerId { get; set; }
[DataMember]
public string PayerName { get; set; }
[DataMember]
public string GroupNumber { get; set; }
[DataMember]
public string MemberIdOfPatient { get; set; }
[DataMember]
public string PatientRelationshipToInsuredIndicator { get; set; }
[DataMember]
public string CoordinationOfBenefitsPrecedenceIndicator { get; set; }
Ok, so Climber104's solution would work, but I would need to re-implement all of the List's methods, which makes me feel that I am reinventing the wheel.
JaredPar from Jarek Waliszko's thread suggests to use a wrapper class.
The easiest is to use it just for the sake of serialization process, so I used an protected innner wrapper class. This allows me to achieve my goals with just a few lines of code needed.
public class DownloadRuleCollection : List<DownloadRule> {
public string SomeProperty { get; set; }
public void Serialize(string fileName) {
Serializer.Serialize(
new DownloadRuleCollection_SerializationWrapper {
Collection = this,
SomeProperty = SomeProperty
}, fileName);
}
public static DownloadRuleCollection Deserialize(string fileName) {
var wrapper = Serializer.Deserialize<DownloadRuleCollection_SerializationWrapper>(fileName);
var result = wrapper.Collection;
result.SomeProperty = wrapper.SomeProperty;
return result;
}
[DataContract(Name = "DownloadRuleCollection")]
private class DownloadRuleCollection_SerializationWrapper {
[DataMember(EmitDefaultValue = false, Name = "SomeProperty", Order = 0)]
public string SomeProperty { get; set; }
[DataMember(EmitDefaultValue = false, Name = "DownloadRules", Order = 1)]
public DownloadRuleCollection Collection;
}
}
[DataContract]
public class DownloadRule {
[DataMember(EmitDefaultValue = false)]
public string Name { get; set; }
}
public static class Serializer {
public static void Serialize<T>(T obj, string fileName) {
using(XmlWriter writer = XmlWriter.Create(fileName, new XmlWriterSettings { Indent = true }))
new DataContractSerializer(typeof(T)).WriteObject(writer, obj);
}
public static T Deserialize<T>(Stream stream) {
return (T)new DataContractSerializer(typeof(T)).ReadObject(stream);
}
public static T Deserialize<T>(string fileName) {
using(FileStream fs = File.OpenRead(fileName)) {
return Deserialize<T>(fs);
}
}
}

Categories

Resources