Default values missing for ServiceStack.XmlServiceClient response - nunit

While using TestCaseSource in unit testing for multiple ServiceStack service clients, deserialized to a string format for the XmlServiceClient does not match the deserialized for JsonServiceClient or JsvServiceClient. The serialization is using the SerializeAndFormat extension method from the ServiceStack.Text.TypeSerializer class.
Using the OnDeserializing fuctionality doesn't seem to provide the same formatted string, as it is missing the default values.
The same JsConfig scope is used with excludeDefaultValues set to false prior to calling the SerializeAndFormat method. The Json and Jsv results match, including the default values, but the xml service client's result does not include them. The object that is not deserializing correctly is a property of a property of the response object and is decorated with this attribute [Serializable].
The response is decorated with [DataContract], [Serializable] and the property objects are both decorated with [Serializable].
How should the objects be decorated so that the serialized response is consistent for all three clients?
[DataContract]
[Serializable]
public class CustomResponse : IMeta, IHasResponseStatus
{
[DataMember(Order = 5)]
public Dictionary<string, string> Meta { get; set; }
[DataMember(Order = 100)]
public DataView Result { get; set; }
[DataMember(Order = 1)]
public Summary Summary { get; protected set; }
[DataMember(Order = 8)]
public ResponseStatus ResponseStatus { get; set; }
}
[Serializable]
public class Summary : IResponseStatus
{
public IEnumerable<HateoasLinks> Links { get; set; }
[DataMember(Order = 5)]
public string Message { get; protected set; }
[DataMember(IsRequired = false)]
public int? Offset { get; set; }
[DataMember(IsRequired = false)]
public int? Limit { get; set; }
public string RequestFormat { get; private set; }
[DataMember(IsRequired = false)]
public int? Results { get; protected set; }
public Parameters Params { get; protected set; }
}
[Serializable]
public class Parameters
{
[DataMember(Order = 1)]
public string Status { get; set; } = "OK";
public string Sort { get; set; } = string.Empty;
public string Filter { get; set; } = string.Empty;
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
[DataMember(EmitDefaultValue =true)]
public int? Offset { get; set; } = 0;
public int? Limit { get; set; } = 10;
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
if (!this.Limit.HasValue)
{
this.Limit = 10;
}
if (!this.Offset.HasValue)
{
this.Offset = 0;
}
}
}
results in:
{
summary:
{
links: [],
message: OK,
params:
{
status: OK,
sort: "",
filter: "",
},
isSuccess: False,
status: 200,
requestTime: 2014-03-14,
currentPage: 1
},
result:
{
}
}
but should be
params:
{
status: OK,
sort: "",
filter: "",
offset: 0,
limit: 10
}

ServiceStack uses .NET DataContract Serializer for XML so it’s limited to the behaviour and features it provides.
JsConfig only applies to ServiceStack implemented Text Serializers, primarily designed for JSON/JSV and partially used by CSV.

Related

Failing to pass a complex object from one page to another in .Net Maui

I am trying to pass a complex object from MainPage to a ProductsPage, the object is a model with 4 class lists. Of the 4 class lists only 2 are passing data to the ProductsPage, the other 2 are not. I dont know where i am going wrong, i am using MVVM
My MainPageViewModel is as below
public partial class MainPageViewModel : BaseViewModel
{
public ObservableCollection<LogInModel> LogInModels { get; } = new();
public MainPageViewModel()
{
}
[ObservableProperty]
LogInModel logInModel;
[RelayCommand]
async Task GoToRetailAsync()
{
if (LogInModels.Count != 0)
LogInModels.Clear();
LogInModels.Add(logInModel);
await Shell.Current.GoToAsync($"{nameof(ProductsPage)}", true,
new Dictionary<string, object>
{
{"shiptoo",LogInModels[0].cat },
{"group",LogInModels[0].grp },
{"products",LogInModels[0].prod },
{"shipto",LogInModels[0].shp }
});
}
}
}
the failing class lists are shiptoo and group
Below is my ProductsViewModel
namespace Tenga.ViewModel
{
[QueryProperty("Products", "products")]
[QueryProperty("Group","group")]
[QueryProperty("Shiptoo","shiptoo")]
[QueryProperty("Shipto", "shipto")]
public partial class ProductsViewModel : BaseViewModel
{
public ProductsViewModel()
{
}
[ObservableProperty]
List<Shiptoo> shppp;
[ObservableProperty]
List<Group> groups;
[ObservableProperty]
List<Products> products;
[ObservableProperty]
List<Shipto> shipto;
}
}
Below is my LogInModel
namespace Tenga.Model
{
public class LogInModel
{
public string OTP { get; set; }
public string CustomerNumber { get; set; }
public string CustomerName { get; set; }
public string Balance { get; set; }
public string OpenToBuy { get; set; }
public string CreditLimit { get; set; }
public string LoginStatus { get; set; }
public string Error { get; set; }
public List<Shipto> shp = new List<Shipto>();
public List<Shiptoo> cat = new List<Shiptoo>();
public List<Group> grp = new List<Group>();
public List<Products> prod = new List<Products>();
}
public class Shipto
{
public string ShipCode { get; set; }
public string ShipDescription { get; set; }
}
public class Products
{
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
public string UOM { get; set; }
public string ConversionFactor { get; set; }
public string Category { get; set; }
public string Group { get; set; }
public byte[] Image { get; set; }
}
public class Shiptoo
{
public string ShipCode { get; set; }
public byte[] Image { get; set; }
}
public class Group
{
public string Category { get; set; }
public string Code { get; set; }
public byte[] Image { get; set; }
}
}
I have tried to review the class all seems alright, i have also tried changing the bindings and result is the same, can some one please help before go crazy
Implement IQueryAttributable in your ViewModel.
And use:
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
Model = query[nameof(MyModel )] as MyModel ;
}
Forget about those annotations. This is better. You cant mistake names, you can run code after/before they are set. I migrated all my code to use this.
Edit: While we are on the subject:
Instead of:
{"shiptoo",LogInModels[0].cat },
You should be using some constants. The name of the model usually. (Something like naming conventions when passing Extras in android, but much more simple).

Error "The JSON value could not be converted to System.String. Path: $[1].Interests[1].Meta[9].Content | LineNumber: 0 | BytePositionInLine: 10073."

public Class Employee{
public string Name { get; set; }
[Column(TypeName = "jsonb")]
public List<Section> Sections { get; set; }
}
public Class Sections{
public string Booking { get; set; }
[Column(TypeName = "jsonb")]
public List<Interest> Interests { get; set; }
}
public Class Interest{
public string Title { get; set; }
public List<Meta> Meta { get; set; }
public List<WithAlt> Images { get; set; }
}
public Class Meta{
public string Type { get; set; }
public string Content { get; set; }
}
public Class WithAlt{
public string content { get; set; }
public string Alt { get; set; }
}
I fetch data from the Employee table
Employee while fetching the data Sections Column I got
The JSON value could not be converted to System.String. Path: $[1].Interests[1].Meta[9].Content | LineNumber: 0 | BytePositionInLine: 10073.
Error at
public Task<Employee> CheckEmployee(string name){
// error throw Line
var query= await catalogDbContext.Employee
.Where(i.Name === name)
.FirstOrDefault();
}
Not for all value but some value that List<Section> or
List<Interest> or List<Meta> or List<WithAlt> have null value
When I manually add the value to sections column bellow
{
"Booking": "",
"Interests":[
{
"Title":"",
"Meta":[
{
"Type" : " ",
"Content" : " "
}
],
"Images" : [
{
"content" : " ",
"alt" : " "
}
]
}
],
}
it will not throw the error
Are there any way to define the default value to the above fields using code first approach
when I initialize Sections property like
public List<Section> Sections { get; set; }={};
it shows the following error
Can only use array initializer expressions to assign to array types. Try using a new expression instead.
and also
public List<Section> Sections { get; set; }= new List<Section> Sections();
and
public List<Meta> Meta { get; set; }= = new List<Meta>();
and
public List<WithAlt> Images { get; set; }= new List<WithAlt>();
throw Error "The JSON value could not be converted to System.String. Path: $[1].Interests[1].Meta[9].Content | LineNumber: 0 | BytePositionInLine: 10073."
Can only use array initializer expressions to assign to array types. Try using a new expression instead.
You can convert the json data to Section type rather than List<Section> type.
var json = "{\"Booking\":\"\",\"Interests\":[{\"Title\":\"\",\"Meta\":[{\"Type\":\" \",\"Content\":\" \"}],\"Images\":[{\"content\":\" \",\"alt\":\" \"}]}]}";
var s = JsonConvert.DeserializeObject<Section>(json);
//If you want to set Employee.Sections with json data,try this
Employee e = new Employee { Sections = new List<Section> { s } };
Models(change class name Sections to Section,Interests to Interest):
public class Employee
{
public string Name { get; set; }
[Column(TypeName = "jsonb")]
public List<Section> Sections { get; set; }
}
public class Section
{
public string Booking { get; set; }
[Column(TypeName = "jsonb")]
public List<Interest> Interests { get; set; }
}
public class Interest
{
public string Title { get; set; }
public List<Meta> Meta { get; set; }
public List<WithAlt> Images { get; set; }
}
public class Meta
{
public string Type { get; set; }
public string Content { get; set; }
}
public class WithAlt
{
public string content { get; set; }
public string Alt { get; set; }
}
I just deserialiazed you json , everything is working properly, I couldn' t find any errros
public static void Main()
{
var json = "{\"Booking\":\"\",\"Interests\":[{\"Title\":\"\",\"Meta\":[{\"Type\":\" \",\"Content\":\" \"}],\"Images\":[{\"content\":\" \",\"alt\":\" \"}]}]}";
var jd = JsonConvert.DeserializeObject<Data>(json);
}
classes
public class Data
{
public string Booking { get; set; }
public List<Interest> Interests { get; set; }
}
public class Interest
{
public string Title { get; set; }
public List<Meta> Meta { get; set; }
public List<Image> Images { get; set; }
}
public class Meta
{
public string Type { get; set; }
public string Content { get; set; }
}
public class Image
{
public string content { get; set; }
public string alt { get; set; }
}

LiteDB null reference on insert

I ran into this problem where in I get a null reference exception on insert.
I have two object Models UserInfo and UserConfig. On the first trial, UserConfig references a UserInfo instance
public class UserConfigObject : IUserConfig
{
BsonRef("userInfo")]
public IUserInfo UserInfo { get; set; }
public string AssignedJob { get; set; }
public string[] QueueItems { get; set; }
}
public class UserInfoObject : IUserInfo
{
[BsonId]
public int ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string IPAddress { get; set; }
}
And a method to insert the data into the database
public void AddUser(IUserConfig user)
{
var uconCollection = DatabaseInstance.GetCollection<IUserConfig>("userConfig");
var uinCollection = DatabaseInstance.GetCollection<IUserInfo>("userInfo");
uinCollection.Insert(user.UserInfo);
uconCollection.Insert(user);
}
This set up works fine but when I try to change the reference to UserInfo references UserConfig
public class UserInfoObject : IUserInfo
{
[BsonId]
public int ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string IPAddress { get; set; }
[BsonRef("userConfig")]
public IUserConfig UserConfig { get; set; }
}
public class UserConfigObject : IUserConfig
{
[BsonRef("userInfo")]
public IUserInfo UserInfo { get; set; }
[BsonId(true)]
public int ConfigID { get; set; }
public string AssignedJob { get; set; }
public string[] QueueItems { get; set; }
}
With a method call for
public void AddUser(IUserInfo user)
{
var uconCollection = DatabaseInstance.GetCollection<IUserConfig>("userConfig");
var uinCollection = DatabaseInstance.GetCollection<IUserInfo>("userInfo");
uconCollection.Insert(user.UserConfig);
uinCollection.Insert(user);
}
It no longer works, it throws an System.NullReferenceException: 'Object reference not set to an instance of an object.' on uinCollection.Insert(user);
Either v3 or v4, it doesn't work with the latter set up
Had the same problem but with collections. I've tried to save collection of invitations like so:
using var db = new LiteRepository(_connectionString);
var invitations = new List<Invitation>
{
// populate list
};
db.Insert(invitations);
The problem is that T parameter resolved as IEnumerable<Invitation> not just Invitation, so if you are inserting a collection, set type explicitly.
db.Insert<Invitation>(invitations);

How to have a nested DTO?

I have this as my entity object:
public partial class RFID_Zones
{
public RFID_Zones()
{
this.RFID_ZonePoints = new HashSet<RFID_ZonePoints>();
}
public int PK_ZoneId { get; set; }
public int PK_FK_ShipId { get; set; }
public string ZoneName { get; set; }
public string Color { get; set; }
public virtual Ship Ship { get; set; }
public virtual ICollection<RFID_ZonePoints> RFID_ZonePoints { get; set;}
}
I am trying to pull all these with this code:
result = _db.RFID_Zones.Where(x => x.PK_FK_ShipId == shipId).Include(x => x.RFID_ZonePoints).ToList();
This works, but I cannot serialize it without getting a circular reference error. Upon Googling I find I should use a Data Transfer Object so I have this:
public class ZoneDto
{
public ZoneDto()
{
this.Zones = new List<RFID_ZonePoints>();
}
public int PK_ZoneId { get; set; }
public int PK_FK_ShipId { get; set; }
public string ZoneName { get; set; }
public string Color { get; set; }
public List<RFID_ZonePoints> Zones { get; set; }
}
And:
var dto = zones.Select(x => new ZoneDto { PK_ZoneId = x.PK_ZoneId, PK_FK_ShipId = x.PK_FK_ShipId,
Color = x.Color, ZoneName = x.ZoneName, Zones = x.RFID_ZonePoints.ToList()});
I still have the issue of the RFID_ZonePoints list. It's a list of a different entity. How can I get those into a data transfer object as well?

seeding one to many relationship with entity framework

I've looked through quite a few threads about seeding a one to many relationship with EF but can't seem to find the answer to what seems like a simple question. How to do it? I have the following code where I'm trying to create an AuctionItem entity and then add AuctionImage entities to it. But I get a null exception for auctionOne.AuctionImages on the line auctionOne.AuctionImages.Add()... Can anyone tell me what I'm doing wrong? Thanks!
protected override void Seed(AuctionDbContext db)
{
var auctionOne = new AuctionItem()
{
AuctionComplete = string.Empty,
AuctionDate = DateTime.Now.AddDays(-1),
CurrentPrice = 2,
EndPrice = 5,
InitialPrice = 1,
InitialQuantity = 1,
LongDescription = "Long description",
PriceDrops = 2,
QuantityRemaining = 2,
ReserveQuantity = 1,
RetailPrice = 4,
ShortDescription = "Short description",
Title = "Auction one"
};
auctionOne.AuctionImages.Add(new AuctionImage
{
Description = "Beautiful picture",
Filename = "picture.jpg"
});
db.AuctionItems.Add(auctionOne);
base.Seed(db);
}
And here are my classes.
public class AuctionItem
{
[Key]
public int AuctionItemID { get; set; }
[Column(TypeName = "varchar"), MaxLength(256)]
public string Title { get; set; }
public decimal InitialPrice { get; set; }
public int InitialQuantity { get; set; }
public DateTime? AuctionDate { get; set; }
[Column(TypeName = "varchar(max)")]
public string ShortDescription { get; set; }
[Column(TypeName = "varchar(max)")]
public string LongDescription { get; set; }
public decimal RetailPrice { get; set; }
public decimal? EndPrice { get; set; }
public decimal CurrentPrice { get; set; }
public int PriceDrops { get; set; }
public int QuantityRemaining { get; set; }
public int ReserveQuantity { get; set; }
[Column(TypeName = "char"), MaxLength(10)]
public string AuctionComplete { get; set; }
[Column(TypeName = "xml")]
public string Metadata { get; set; }
public virtual ICollection<AuctionImage> AuctionImages { get; set; }
}
public class AuctionImage
{
[Key]
public int AuctionImageID { get; set; }
[ForeignKey("AuctionItem")]
public int AuctionItemID { get; set; }
public virtual AuctionItem AuctionItem { get; set; }
[Column(TypeName = "varchar"), MaxLength(256)]
public string Description { get; set; }
[Column(TypeName = "varchar(max)")]
public string Filename { get; set; }
[Column(TypeName = "xml")]
public string MetaData { get; set; }
}
You haven't allocated the collection for AuctionImages before you are referencing it with the Add, which is why you get the null exception. (When the object is first created, the property will have a null value).
For seeding, it's usually just easiest to do something like:
var auctionOne = new AuctionItem()
{
AuctionComplete = string.Empty,
AuctionDate = DateTime.Now.AddDays(-1),
// ...
AuctionImages = new List<AuctionImage> {
new AuctionImage { Description="", Filename="" },
new AuctionImage { Description="", Filename="" }
}
};
If you want to do it as two separate steps, just allocate the AuctionImages property as a new List<> (or other ICollection) before adding to it:
var auctionOne = new AuctionItem()
{
// ...
Title = "Auction one"
};
auctionOne.AuctionImages = new List<AuctionImage>(); // add this
auctionOne.AuctionImages.Add(new AuctionImage
{
Description = "Beautiful picture",
Filename = "picture.jpg"
});
db.AuctionItems.Add(auctionOne);