sending complex structures via WCF RIA services - c#

I'm having a trouble with sending complex structure.
I have two classes. I send through ria services a list of messages, every message contains a list of classes describing people involved in conversation - MailInfo
public class Message
{
[Key]
public string Id { get; set;}
public string ParentId { get; set; }
public List<MailInfo> Email { get; set; }
}
public class MailInfo
{
[Key]
public string Address { get; set; }
}
To send a List of Message I use
[Query]
public IQueryable<Message> GetMessage() {return null;}
[Query]
public IQueryable<MailInfo> GetMailInfo() { return null; }
and eventually
[Invoke]
public List<Message> SomeMethod ()
{ return listofMessages; }
But I cannot have access to Email field of Message. Can I do something? Or just such complex structures are not supported in silverlight yet?

Actually I found out that you cannot send such class object properly. The point is that RIA services disable a setter for non-POCO objects of the class you are going to send.
You can see it in generated code .Web.g.cs.
The only beautiful solution I found out - is to send List EMail as a serialized string. So after that all of your fields in entity would be POCO and you finally get the object.

public class Message
{
[Key]
public string Id { get; set;}
public string ParentId { get; set; }
[Include]
public List<MailInfo> Email { get; set; }
}
public class MailInfo
{
[Key]
public string Address { get; set; }
}
Try using the attribute. If it is linked in your database it should get these for you.

Related

.net core : incomplete JSON response

I'm trying to build simple API for training, in my database I got users (firstname, lastname, email password, list<sports>) and sports ( name, userID).
All is okay when I want to get my users, I got an object populated with sports. But the JSON response is incomplete, it is "cut" in the middle.
[{"firstName":"Nicolas","lastName":"Bouhours","email":"n.bouh#test.com","password":"nico#hotmail.fr","sports":[{"name":"Trail","userId":1
This is my controller :
// GET: api/Users
[HttpGet]
public IEnumerable<User> GetUsers()
{
var users = _context.Users.Include(u => u.Sports).ToList();
return users;
}
And my models :
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
public class SportAppContext : DbContext
{
public SportAppContext(DbContextOptions<SportAppContext> options) : base(options)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Sport> Sports { get; set; }
}
I really don't understand what happen, if you have any idea
I'm running into the same issue right now. You can also change the JSON serialization/configuration settings to ignore self-reference loops, as shown in the accepted answer for this question
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
I had this problem to in one of my projects. This is caused by a self referencing loop.
You need to create some sort of DTO (Data Transfer Object) which will be used to generate your JSON.
In your DTO you remove the inverse relationship so you end up having something like
public class SportDto
{
public string Name { get; set; }
}
public class UserDto
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<SportDto> Sports { get; set; }
}
You then map your user User and Sport models to your UserDto and SportDto
A good tool for doing this mapping is AutoMapper. You can read the docs to see how to get started.
After the mapping is done, you Send the DTOs as your JSON and not your models.
Just to add another yet unique scenario where this can occur. This can also happen if your DAL is returning queryables. In my scenario, I was returning a boxed object from the DAL and had something like this as a linq query
...
RootLevelProp1 = "asd",
RootLevelProp2 = "asd",
Trades = b.Trades.OrderBy(c => c.Time).Select(c => new
{
c.Direction,
c.Price,
c.ShareCount,
c.Time
}) //<---- This was being returned as a queryable to the controller
The Trades query was never being executed even though it's root object had .ToListAsync() called on it. What was happening was that the controller would return the result but only up to the Trades section and the Json would not be terminated properly. I then realized an exception was being caught in some custom middleware I wrote in which it was complaining about the data reader already being open. Without going to deep into my investigation, I assumed it had to do something with the DI and how it was handling the lifecycle of the context. The fix was to just add ToList on the trades. It's an ugly way to pass data from the DAL but this is just a fun project.
In my case this solve my issue on core 3, by using Newtonsoft:
https://learn.microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-3.0#add-newtonsoftjson-based-json-format-support
Prior to ASP.NET Core 3.0, the default used JSON formatters
implemented using the Newtonsoft.Json package. In ASP.NET Core 3.0 or
later, the default JSON formatters are based on System.Text.Json.
Support for Newtonsoft.Json based formatters and features is available
by installing the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet
package and configuring it in Startup.ConfigureServices.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson();
}
The selected answer was correct in my case as well, my JSON response was getting truncated by a reference loop in my JSON response, and setting ReferenceLoopHandling.Ignore did indeed solve my issue. However, this is not the best solution in my opinion, as this maintains the circular references in your model. A better solution would use the [JsonIgnore] attribute within the model.
The issue in your model is here:
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
public User User { get; set; } //This is the cause of your circular reference
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
As you can see, your User navigation property is where this response is truncated. Specifically, it will cause each Sport in the json response to contain all of the user information for each sport entry in the response. Newtonsoft does not like this. The solution is to simply [JsonIngore] the navigation properties that cause this circular reference. In your code this would be:
public class Sport : BaseEntity
{
public string Name { get; set; }
public int UserId { get; set; }
[JsonIgnore]
public User User { get; set; } //fixed
}
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public List<Sport> Sports { get; set; }
}
Faced similar issue, response was getting truncated. Issue was a getter method which trying to formatting date.

object collision with wcf

Could someone explain why this is happening, I have a C# backend that I'm connecting to via WCF. In the back end, i have two classes in the same namespace that have two properties that have the same name. These classes are used in a separate object. The types of the properties are different, one is a string and one is an object but there seems to be some sort of collision when deserializing the object?
It's returning this random error when I call to return the object.
This could be due to the service endpoint binding not using the HTTP
protocol. This could also be due to an HTTP request context being aborted by
the server (possibly due to the service shutting down). See server logs for
more details.
Here are the classes, the property causing the problem is BCIssued
public class Activities
{
public string ApplicationReceived { get; set; }
public string PIMGranted { get; set; }
public Bcgranted[] BCGranted { get; set; }
public object CCCGranted { get; set; }
// public object BCIssued { get; set; }
public object CCCIssued { get; set; }
}
public class CCC
{
public string BCIssued { get; set; }
public string FinalIns { get; set; }
public string LapsedMonths { get; set; }
public object WorkStarted { get; set; }
public object Notified { get; set; }
public object Lapsed { get; set; }
public object Extension { get; set; }
}
Thanks to Rene's post about WCF logging, i was able to turn on logging and found the error on the server side
Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data contract
which is not supported. Consider modifying the definition of collection
'Newtonsoft.Json.Linq.JToken' to remove references to itself.

How does one design his various architecture/business models?

I'm currently learning about various application design approaches and there's one thing I can't really get my head around.
Let's say I have a physical device in my network, an IP surveillance camera. I need a model that represents 'IP surveillance cameras' to work with them in my application, which might look like this:
public class IPCamera {
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
}
Now, if I want to store the IPCamera into a database (e.g. with Entity Framework), I need maybe other/additional properties and thus, another model with:
public int Id { get; set; }
Oh.. I want to access my application with via a WCF service. I can't use the object "IPAddress" here because it's not very serialization friendly, hence I need another model with a custom IP class that stores the IP address as string.
And last, an Android clients wants to access my data. I design a RESTful API using WebApi2. The client isn't interested in the cameras RTSPUri, but wants to know about the current state (is online, is offline).
I'm wondering: How to name all these models that they don't come in conflict? Should I design a model per each purpose/layer/service? And how to link/map them? With the adapter pattern?
I would include everything in your entity and then create view models that only expose the properties that matter to the domain you're accessing your entities through.
Your entity:
public class IpCamera
{
public int Id { get; set; }
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
public bool IsOnline { get; set; }
}
In your WCF service:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public string RtspUri { get; set; }
}
In your api project:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public bool IsOnline { get; set; }
}
And you can just set the IpAddress as a string to send to a receiving client. You can shed away any properties you don't want to expose. Or you can add properties that don't belong to the IpCamera entity and just add them to your view model from another entity.
As #Smith.h.Neil suggested, you should create one base normalized model (entity if you will) to store and several view models (projections).
You can easily map to/from view models using tools like AutoMapper.
As for the naming, I wouldn't use technical suffixes (like *ViewModel) in API layer. Think hard and figure out correct domain (business oriented) name of each projection. Like IpCameraStatus or perhaps just IpCamera (but in another namespace).

Silverlight POCO returned by RIA services

I am using a Silverlight 5 Business Application using RIA services to return a POCO class from the service side to populate a hierarchical menu.
The original problem I had with the POCO class was that the SubMenuItems property was not getting passed over RIA services although it was populated on the service side.
Original POCO
public class BusinessModelMenuDto
{
[Key]
[Required]
public int ID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
Service call
public IEnumerable<BusinessModelMenuDto> GetCabsHeirarchy()
Following some further investigation I found that the [Include] and [Association] attributes were required on the SubMenuItems to pass the data over. Doing this the first time with the Association of ID => ID did not give the desired results so I added the ParentID property and changed my loading code to populate the Foreign Key as below. I also changed the Associate to map from ID to Parent ID.
Updated POCO class
public class BusinessModelMenuDto
{
[Key]
[Required]
public int ID { get; set; }
public int? ParentID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
[Include]
[Association("SubItems", "ID", "ParentID")]
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
On the server side I am loading two levels of the menu at the moment so the top level item contains a collection of SubItems but there are no further SubItems below that.
The problem I have is that when RIA services sends the collection over the wire the hierarchy is being jumbled. I have confirmed that what I am returned is correctly structured but it does not arrive on the client side correctly. The top level is OK but the second level (SubMenuItems) is mixed up and two furter SubMenuItems levels have appeared.
Any idea what I am doing wrong? I assume that the problem is with the Association or the fact that the same POCO object (BusinessModelMenuDto) is being used for the multiple levels.
We found we had to use Guids for the item Key and assign a unique value to it on the server before passing back to the client.
So your class definition would become:
public class BusinessModelMenuDto
{
[Key]
[Required]
public Guid ID { get; set; }
public Guid? ParentID { get; set; }
public string TextToDisplay { get; set; }
public string ImageSource { get; set; }
[Include]
[Association("SubItems", "ID", "ParentID")]
public IEnumerable<BusinessModelMenuDto> SubMenuItems { get; set; }
}
Then when you create a new element set the ID:
ID = Guid.NewGuid();

Stopping a field change being recorded as a modification to a POCO object

I am developing with silverlight, and RIA services. I have a POCO object defined on the server side like this,
public class AssessmentRoad
{
[Key]
public int Id { get; set; }
[Required]
public int RoadLength { get; set; }
public int RoadId { get; set; }
[Required]
public string RoadName { get; set; }
[Required]
public string Suburb { get; set; }
public bool HasModified { get; set; }
}
The field HasModified is calculated and used on the client side only.
RIA services when I call SaveChanges decides that the entities need saving because the HasModified field has changed.
Is there an attribute I can use to make sure this doesn't happen? Or do I need to use a partial class etc?
On second thoughts perhaps the HasModified field shouldn't be there at all, and this should be wrapped up in a ViewModel instead?
Add this property to a client-side partial class. See http://msdn.microsoft.com/en-us/library/ee707331(v=VS.91).aspx.

Categories