Why is my response being serialized without navigation properties? - c#

Today I ran into a small problem with my code. I have an HttpGet method similar to the following:
[HttpGet]
public IEnumerable<SomeEntity> Get()
{
return db.SomeEntity.ToList();
}
where SomeEntity could be represented as
public class SomeEntity
{
#region DatabaseColumns
[Key]
public int SomeEntityID { get; set; }
public string SomeEntityName { get; set; }
#endregion
#region Navigation Properties
public virtual ICollection<SomeChildEntity> SomeChildEntity { get; set; }
#endregion
}
I noticed that return db.SomeEntity.ToList(); only returned the top level members of the object (not the navigation properties).
This made sense to me considering I was not calling Include. Out of curiosity, I attempted the following:
[HttpGet]
public IEnumerable<SomeEntity> Get()
{
var enumeratedEntity = db.SomeEntity.ToList();
return enumeratedEntity;
}
To my surprise, it returned the entire entity along with its navigation properties.
I also noticed that an HttpGet along these lines also returned the entire object
[HttpGet]
public SomeEntity Get(int id)
{
return db.SomeEntity.Find(id);
}
Can someone please explain, or point me to resources that will explain, why these methods return the entire object without using the Includes method while the first one doesn't?

I'm not 100% on this, so feel free to test and then up or downvote me. When you return an IEnumerable<SomeEntity> you don't define a concrete type. You're returning some generic IEnumerable which the HTTP pipeline then strips the virtual properties out of.
When you call var enumeratedEntity = db.SomeEntity.ToList(); you create a List. That concrete object then gets the virtual properties immediately instantiated. The whole concrete object is then sent down the pipeline including the virtual properties.
You could test this by changing var enumeratedEntity = db.SomeEntity.ToList(); to IEnumerable<SomeEntity> enumeratedEntity = db.SomeEntity.ToList(); and List<SomeEntity> enumeratedEntity = db.SomeEntity.ToList();. You'd then expect to see the 2 behaviors you currently see based on which generic container you use.

Related

FluentValidation not working on collection of outer model objects

I am having trouble getting FluentValidation to work with a collection of objects. My controller POST action takes in an IEnumerable of objects like below. When I post to an action that takes a single EventInputDto, with an incorrectly formatted Url property, my validation occurs successfully. When I post to a collection of EventInputDto, it does not work and does no validation.
If I use regular MVC Attributes (i.e. required / email), they work with collections as well as single objects. How do I get this to work with FluentValidation? I am not working with inner collections so I'm not sure why it does not work as intended.
public async Task<IActionResult> CreateEventCollection([FromBody] IEnumerable<EventInputDto> events)
{
if (!ModelState.IsValid)
{
return UnprocessableEntity(ModelState); //does not work
}
}
My validators are setup using generics because I am using separate models for inputs and updates.
public class EventManipulationValidator<T> : AbstractValidator<T> where T : EventManipulationDto
{
public EventManipulationValidator()
{
RuleFor(manipulationDto => manipulationDto.Title).NotNull().WithMessage("Title cannot be blank")
.Length(1, 50);
RuleFor(manipulationDto => manipulationDto.Message).NotNull().WithMessage("Message cannot be blank")
.Length(1, 1000);
RuleFor(manipulationDto => manipulationDto.ScheduledTime).NotNull().WithMessage("Scheduled Time cannot be blank");
RuleFor(inputDto => inputDto.Url).Matches(#"https://.*windows\.net.*").WithMessage("The url must be valid and stored on Azure");
}
}
As my CreateEventCollection action takes in an IEnumerable of EventInputDto, my validator for EventInputDto is setup as below:
public class EventInputValidator : EventManipulationValidator<EventInputDto>
{
public EventInputValidator()
{
//all property validators are inherited from EventManipulationValidator
}
}
public class EventInputCollectionValidator : AbstractValidator<IEnumerable<EventInputDto>>
{
public EventInputCollectionValidator()
{
RuleForEach(p => p).SetValidator(new EventManipulationValidator<EventInputDto>());
}
}
Below are my models for reference:
EventManipulationDto
public abstract class EventManipulationDto
{
public string Title { get; set; }
public string Message { get; set; }
public string Url { get; set; }
public DateTime? ScheduledTime { get; set; }
}
EventInputDto
public class EventInputDto : EventManipulationDto
{
//all properties inherited from base class
}
After going through the list of open/closed issues on the project GitHub, it seems that not all of my approach is required. There is no need for my `EventInputCollectionValidator. FluentValidation no longer requires explicitly defining an IEnumerable validator like I defined above.
It's enough to define a base AbstractValidator or as in my case an inherited validator from a parent class.
The only change needed to get it to work was in my startup.cs when registering fluentvalidation. I needed to explicitly add ImplicitlyValidateChildProperties = true. Didn't realize this was required as I thought this was for validating child property collections and not the parent collection objects. Works perfectly now.
.AddFluentValidation(fv => {
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = true;
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.ImplicitlyValidateChildProperties = true;
});

Specify a unique identifier attribute for an object across webapi Models

In a POST call to a WebApi I am trying to return a Created(newobject) thing. But there is no signature for Created in ApiController that can only take the object and do the rest.
It works fine if I return something like:
return Created(newobject.blahid.ToString(), newobject);
or if I do a
return CreatedAtRoute("DefaultApi", new { controller = ControllerContext.ControllerDescriptor.ControllerName, id = newobject.blahid.ToString()}, newobject);
I want to simplify this to:
return Created(newobject);
I would need to implement a method in a BaseController
public class BaseController : ApiController
{
protected new CreatedNegotiatedContentResult<T> Created<T>(T content)
{
var id = GetId(content);//need help here
return base.Created(id, content);
}
}
I don't want to worry about the Unique Identifier for an object being called differently in different models e.g. myobjguid, someblahguid etc. I would just want to find it out and mark it as "id".
say if my model is
public class Model_A
{
public List<Model_A> ChildModels { get; set; }
[LookForThisAttribute]//I want something like this
public Guid Model_AGuid { set; get; }
public Guid ? ParentGuid { set; get; }
public List<SomeOtherObject> OtherObjects { set; get; }
}
Is there an attribute([LookForThisAttribute]) or something I can set on all my models to specify that this is the guy to be assumed as THE unique identifier if I ever look for it.
Just like the [Key] attribute in Entity Framework. No matter what you call it, Entity Framework know its going to be the primary key.
So the GetId(T content) method can take the object and return the value of the property that has a [LookForThisAttribute] set?
I ended up writing my own Attribute and then looking up for it in the BaseController.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class UniqueIdAttribute: Attribute
{
}
And in the BaseController Created method:
protected CreatedNegotiatedContentResult<T> Created<T>(T content)
{
var props =typeof(T).GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(UniqueIdAttribute)));
if (props.Count() == 0)
{
//log this
return base.Created(Request.RequestUri.ToString(), content);
}
var id = props.FirstOrDefault().GetValue(content).ToString();
return base.Created(new Uri(Request.RequestUri + id), content);
}
Mark Gravell's post here helped me with getting the value of the property that has my custom attribute:
How to get a list of properties with a given attribute?
Along with a corresponding unit test for the controllers works fine for me.
Now I can just call Created(anyobject); from all ApiControllers without bothering about the different names people put for their IDs as long as they decorate it with my custom attribute.

WCF handling objects

I have a class which is placed in a class library:
public class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
}
Then I have a repository class:
public class Repository
{
public List<UserProfile> GetUsers()
{
using (var context = new DBContext())
{
List<UserProfile> list = context.UserProfiles.ToList();
return list;
}
}
}
business logic class:
public class BusinessLogic
{
public List<UserProfile> GetUserProfiles()
{
Repository repo = new Repository();
List<UserProfile> list = repo.GetUsers().ToList();
return list;
}
}
and finaly WCF:
public interface IService1
{
[OperationContract]
List<UserProfile> GetUserProfiles();
}
public class Service1 : IService1
{
public List<UserProfile> GetUserProfiles()
{
BusinessLogic.BusinessLogic bl = new BusinessLogic.BusinessLogic();
List<UserProfile> list = bl.GetUserProfiles().ToList();
return list;
}
}
Whenever I try to get user profiles from wcf, it returns empty list.
However, if I skip wcf and get List<UserProfile> straight from businesslogic, it works perfectly fine.
I tried to debug. Results: when inside wcf it gets list from businesslogic, it's already empty. But as I said earlier, business logic works perfectly fine (returns necessary information).
There were similar posts but none of them did help me.
How can I make my WCF return a list filled with necessary information?
P.S. I do not want to add a copy of my class UserProfile into wcf with [DataContract] flag
Your object must either be serializable or decorated with that DataContract attribute. Your return type from WCF must also be decorated with the DataContract attribute, and the member containing your List must be marked with the DataMember attribute. This is required by WCF's DataContractSerializer in order to properly serialize the data and return it to the consumer. Converting a class for transmission over the wire requires serialization. There isn't a practical way to get around this with WCF.
Your list is empty because your UserProfile class cannot be serialized.
EDIT:
I just saw you are simply returning a list, which is already serializable, so if you just make your UserProfile class serializable or decorate it with the appropriate DataContract/DataMember classes, it will start working fine.

How do I resolve type dependencies in regards of controller action?

Update
I've managed to create something that is satisfactory. You can see the relevant parts of the code here on PasteBin. If there is there something that I could improve please let me know. I've got a nagging feeling this isn't very efficient.
Clarification
While it certainly seems to work with static dependencies as suggested by d_z, I was hoping, to avoid instantiating objects not utlilized, that I could use something similar to this:
public class HomeController : Controller
{
[Dependency]
protected IBaseData ActionData { get; set; }
public ActionResult Index()
{
return View(ActionData);
}
public ActionResult About()
{
return View(ActionData);
}
}
The data in the IndexData and AboutData instances in reality aren't static. The instance properties are set with data from a database. The DbProvider is injected into these classes.
In the end what I want is to minimize the memory footprint and database accesses.
Original
Let's say we have the following basic controller (with corresponding views):
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
}
We also have two classes with the same interface:
public class IndexData : IBaseData
{
public string Name { get; set; }
public string Index { get; set; }
public IndexData()
{
Name = "Index";
Index = "This is an Index instance";
}
}
public class AboutData : IBaseData
{
public string Name { get; set; }
public string About { get; set; }
public AboutData()
{
Name = "About";
About = "This is an About instance";
}
}
What I'd like is for Unity to inject an instance of one of these classes, depending on which action is executed, into the corresponding view. I've tried to get my head around how to achieve this but I'm stumped. Is this even possible?
What you are requesting makes little sense. Dependency Injection is about injecting (design time) behavior (a.k.a. services). What you are trying to do however is to inject runtime data. So this is not a task that yout IoC container should handle.
Next the view should be completely ignorant of any dependency injection. The controller should return all data that the view needs from its action method. Make sure that your About and Index action methods return the proper instance.
To register several mappings for a type in Unity you have to create named registration like this:
myContainer.RegisterType<IBaseData, IndexData>("Index");
myContainer.RegisterType<IBaseData, AboutData>("About");
So after this in your actions you can resolve an instance accordingly:
Index:
IBaseData data = myContainer.Resolve<IBaseData>("Index");
About:
IBaseData data = myContainer.Resolve<IBaseData>("About");
Or for static dependencies it works like this:
[Dependency("Index")]
IBaseData data { get; set; }
Take a look here and here for details

C#, problem mixing Xml Serialization with Nhibernate

I am working on a program that uses Nhibernate to persist objects, and Xml Serialization to import and export data. I can't use the same properties for collections as, for example, Nhibernate needs them to be Ilists, because it has it's own implementation of that interface, and I can't Serialize interfaces. But as I need both properties to be synchronized, I thought I could use two different properties for the same Field. The properties will be according to what I need for each framework, and they will update the Field accrodingly.
So, I have the following field:
private IList<Modulo> modulos;
And the following properties:
[XmlIgnore]
public virtual IList<Modulo> Modulos
{
get { return modulos; }
set { modulos = value; }
}
[XmlArray]
[XmlArrayItem(typeof(Modulo))]
public virtual ArrayList XmlModulos
{
get
{
if (modulos == null) return new ArrayList();
var aux = new ArrayList();
foreach (Modulo m in modulos)
aux.Add(m);
return aux;
}
set
{
modulos = new List<Modulo>();
foreach (object o in value)
modulos.Add((Modulo)o);
}
}
The first one is working perfectly, being quite standard, but I have some problems with the second one. The get is working great as I am having no problems Serializing objects (meaning it correctly takes the info from the field). But when I need to Deserialize, it is not getting all the info. The debugger says that after the Deserialization, the field is not updated (null) and the Property is empty (Count = 0).
The obvious solution would be using two unrelated properties, one for each framework, and passing the information manually when needed. But the class structure is quite complicated and I think there should be a more simple way to do this.
Any Idea how I can modify my property for it to do what I want? Any help will be appreciated.
The short answer is that you cant.
Typically you would create a DTO ( Data transfer object ) separate from your NHibernate objects. For example:
public class PersonDto
{
[XmlAttribute(AttributeName = "person-id")]
public int Id { get; set; }
[XmlAttribute(AttributeName = "person-name")]
public string Name{ get; set; }
}
On your DTO object you only put the properties that you intend to serialize. You than create a DTO from your domain model when you need to serialize one.
There is a great little library called automapper that makes mapping from your domain objects to your dto's pretty straight forward. See: http://automapper.codeplex.com/
Here is an example of a person class that supports mapping to the above DTO.
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
static Person()
{
Mapper.CreateMap<PersonDto, Person>();
Mapper.CreateMap<Person, PersonDto>();
}
public Person(PersonDto dto)
{
Mapper.Map<PersonDto, Person>(dto, this);
}
public PersonDto ToPersonDto()
{
var dto = new PersonDto();
Mapper.Map<Person, PersonDto>(this, dto);
return dto;
}
}

Categories

Resources