Any collection causes silent failure with 500 status code in Asp.Net MVC 4 RC Web API - asp.net-mvc-4

I'm completely lost on what could be causing this.
I have an ASP.Net MVC 4 RC application and I have a set of Web API controllers. I'm trying to return an object that contains a set of child objects in an IList. Whenever I request the object I get a 500 error back on the browser with no noticeable exception thrown in the debugger. I've tried putting an Application_Error handler in the global.asax and no error is caught there either.
It doesn't matter whether the List is an actual database relation or just a hard coded list of strings, in either case the request fails. If i set the list to null the request succeeds.
If i remove the list the request succeeds and I get an XML (or JSON) representation of the object.
I've also tried this line -
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
To capture the actual exception and still get nothing back.
Here's the current object
public class Authority : IEntity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string County { get; set; }
public virtual string State { get; set; }
public virtual string ContactPostalCode { get; set; }
//public virtual IList<PostalCode> PostalCodes { get; set; }
public virtual IList<string> RandomTrash { get; set; }
public VPA()
{
//PostalCodes = new List<PostalCode>();
RandomTrash = new List<string> {"foo"};
}
}
Note the commented out PostalCodes collection - that is a real many to many database relationship. I commented it out and replaced it with the dummy "RandomTrash" collection and the failure seems to be the same.
I have a feeling this is a serialization failure somehow but I can't figure out how to avoid it. If it helps I'm using NHibernate as the ORM.
Has anyone seen this?

Answering my own question in case anyone runs into this again.
It ended up being Serialization following the grid in a loop. To fix i added 2 attributes to each looping reference in one of the models.
[IgnoreDataMember] For the XML Serializer
[JsonIgnore] For JSON.Net's Serializer.
I added those the PostalCode class on the IList property.
There may be a better solution. The downside of this one is it makes my API one sided. I can request an Authority and get all of it's postal codes, but i can't request a postal code and get all of it's Authorities.

Related

Confused about DTOs when reading and editing. How to desing DTO for filling the form in VUEjs app?

I am trying to develop an enterprise-level application. I have domain and application services. I have created my DTOs for multiple purposes separately. But confused about which way I should use them from the API viewpoint.
I have complex objects lets say,
public class Entity{
public int Id { get; set; }
public string Name { get; set; }
public int? ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer{
public int Id { get; set; }
public string Text { get; set; }
}
And I have corresponding DTOs designed with composition now. It was separated before.
public class EntityBaseDto{
public string Name { get; set; }
}
public class EntityReadDto : EntityBaseDto{
public string Manufacturer { get; set; }
}
public class EntityWriteDto : EntityBaseDto{
public int? ManufacturerId { get; set; }
}
Now the question is,
I have a table which is filled with List<EntityReadDto> which is clear. Before, EntityReadDto also had the ManufacturerDto as fully included with id and text. Whenever I require to edit one of the entries from the table I was able to load the dropdown selected items or list of tags etc with the ids attached to the Manufacturer objects within ReadDtos. Now it is not possible. Since I wanted to simplify the codes I just converted them to strings that are read-only. Now I have created another endpoint to get an editable version of the record when needed. Ex: EntityWriteDto will be used to fill the form when the edit is clicked on a specific item. The manipulation will be carried on that DTO and sent with the PUT type request to edit the record.
I am not sure if this approach is ok for these cases. What is the best practice for this? I have many objects related to the entities from other tables. Is it ok to make a call to get an editable version from the backend or need to have it right away in a VUEjs app?

RavenDB Persisting chain of relationships

I'm working on a collaborative document editing tool that's going to use RavenDB for persistence. In my domain I have a document class that looks like this.
public class Document
{
public string Id { get; private set; }
public string Name { get; set; }
public IRevision CurrentRevision {get; private set; }
public string Contents {get { return CurrentRevision.GenerateEditedContent(); }}
}
As you can see that document then has a CurrentRevision property that points to an IRevision object that looks like this.
public interface IRevision
{
IRevision PreviousRevisionAppliedTo { get; }
IRevision NextRevisionApplied { get; set; }
Guid Id { get; }
string GenerateEditedContent();
}
So the basic idea is that the document's contents are generated on the fly by checking out the current revision, which in turn checks it's parent revision, and so on and so forth.
Out of the box, RavenDB doesn't seem to handle persisting this chain of object references the way I need it to. I've been trying to persist it by just calling Session.Store(document), and hoping that the list of associated revisions would get stored as well. I've looked into some pieces of the RavenDB framework like custom serializers, but I can't figure out a clear path that would allow me to deserialize and reserialize the data as I would like. What's a good way to handle this situation.

What kind of parameters do I have to send to a WCF endpoint to insert an entry into a table that has a relationship with another table?

I'm working with Visual Studio 2012 and developing on C#. I just started started working a WCF web service, I created the database through the Model First approach and so far I've been able to insert, update, delete and get entries into simple tables, but I've come across a problem: I don't know how to send the parameters for a table that has a relationship with another table.
To explain better my doubt here's an example: I have a Regions table, then I have this other table called Clusters, a region has many clusters and a cluster belongs to a region.
The resulting classes created by EF look like this:
public partial class Regions
{
public Regions()
{
this.Clusters = new HashSet<Clusters>();
}
public int RegionId { get; set; }
public string Name { get; set; }
public string Point { get; set; }
public System.DateTime CreatedDateTime { get; set; }
public System.DateTime UpdatedDateTime { get; set; }
public virtual ICollection<Clusters> Clusters { get; set; }
}
public partial class Clusters
{
public int ClusterId { get; set; }
public System.DateTime CreatedDateTime { get; set; }
public System.DateTime UpdatedDateTime { get; set; }
public virtual Regions Region { get; set; }
}
With this kind of relationship, how can I add a new Cluster? My endpoint for adding a new Cluster receives a string which is a JSON string, I deserialize it into a Cluster object. I deserialize like this:
Clusters cluster = new JavaScriptSerializer().Deserialize<Clusters>(data); //data is the JSON string
In this case, the only information I'll be sending into the JSON string will be the Region to which the Cluster belongs to (the DateTime for when it is created the object is being added on the server side), but how do I send the Region information into the JSON so it can be added into the Cluster?
What I mean is, do I have to send a JSON string that looks like this?
{"RegionId":2}
Because if I do that, no entry is made, do I have to something else?
I'm really new to working with EF and WCF web services, any help will be appreciated.
From what I gather, you have two methods of saving your cluseters. The first one is as a byproduct of the saving or regions. If you have basic CRUD WCF endpoints, you can simply construct your Region entity in your client, add the clusters, and then call the save.
var reg = new Region();
//set region properties
//build clusters set
for (int i = 0; i<5; i++)
reg.Clusters.add (new Cluster {CreatedDateTime= DateTime.Now,
UpdatedDateTime = DateTime.Now});
wcfClient.SaveRegion(reg); //<-- if the back-end works with EF, this should be able
//to insert one new region with five new clusters
Your other option is to save clusters through a WCF endpoint that is designed to save clusters themselves. Before doing this, I would recommend that you modify your Clusters entity to explicitly have a RegionId field.
public partial class Clusters
{
public int ClusterId { get; set; }
public System.DateTime CreatedDateTime { get; set; }
public System.DateTime UpdatedDateTime { get; set; }
public int RegionsId {get; set;}
public virtual Regions Region { get; set; }
}
Entity framework should be able to recognize automatically that the RegionsId corresponds to the primary key of the Regions entity. After this, it's just a matter of making sure that every Cluster you create has a proper RegionsId property. When you call your "wcfClient.SaveCluster(cluster)" method, EF would automatically link that cluster to the proper region.

DTOs and WCF RIA

I have a DTO which has a collection within it of another DTO which I populate server-side and send to the client. However, this inner DTO collection is not returned to the client.
I believe I need to use the [Include] and [Association] attributes so that WCF RIA services knows what to do, however my issue with this is there is no real association as such between the main DTO and the inner DTO collection, I am just using it to aggregate data from various sources for return to the client.
Is my understanding wrong in what I am trying to achieve, if not how do I get WCF RIA to send this inner DTO collection.
I should add that I am using automapper and want to achieve it using such.
Here is an example, I want to send back to the client in one chunk;
The competencies that the employee has.
The competencies that the employee requires for their job.
The GAP, which is the difference between 1 and 2.
public class CompetencyRequirementsDto
{
[Key]
public string CompanyId { get; set; }
[Key]
public string EmployeeNo { get; set; }
public string JobId { get; set; }
[Include]
[Association("EmployeeCompetencies","CompanyId, EmployeeNo","CompanyId, EmployeeNo")]
public IList<EmployeeCompetencyDto> EmployeeCompetencies { get; set; }
[Include]
[Association("JobCompetencies","JobId, CompanyId","JobId, CompanyId")]
public IList<JobCompetencyDto> JobCompetencies { get; set; }
[Include]
[Association("CompetencyGap", "JobId, CompanyId", "JobId, CompanyId")]
public IList<JobCompetencyDto> CompetencyGap { get; set; }
} }
Now item 1 works fine, but 2 and 3 don't? What I have found is that my DTO is created ok server side but when it gets to the client CompetencyGap(even when it has no values) has
been given JobCompetencies values.
If you are using ADO.Net Entity data model and using RIA Services against them then you have got an option to create associated metadata.
So to get the reference entities at you client side we need to modify both the our corresponding meta-data and as well as well the function of the domain service class which is fetching your data .
Here I am giving an example...
1. Just add [Include] attribute at the the top of the referenced data for example.
[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
// This class allows you to attach custom attributes to properties
// of the Customer class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class CustomerMetadata
{
// Metadata classes are not meant to be instantiated.
private CustomerMetadata()
{
}
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public string FullName { get; set; }
[Include]
public EntityCollection<Order> Orders { get; set; }
public string Password { get; set; }
}
}
2. Modify the function in the domain service and add include there also for example.
public IQueryable<Customer> GetCustomers()
{
var res = this.ObjectContext.Customers.Include("Orders");
return res;
}
In your case the first part is done you just need to modify your domain service query to get reference entities.

WCF client side List<>

I got a WCF service with a method (GetUserSoftware)to send a List to a client.
the software I have defined like this:
[DataContract]
public class Software
{
public string SoftwareID { get; set; }
public string SoftwareName { get; set; }
public string DownloadPath { get; set; }
public int PackageID { get; set; }
}
the method is going through my db to get all software availeble to the clien, and generates a list of that to send back to the client.
problem is i on the client side the list is turned into an array. and every item in that array dont contain any of my software attributs.
i have debugged my way through the server side. and seen that the list its about to send is correct. with the expected software and attributs in it.
any one know how to work around this or know what i can do ?
Did you forget [DataMemeber] attribute on your properties?
When you use DataContract attribute for a type you have to use DataMember attribute for each property or field you want to serialize and transfer between service and client. Collections are by default created as arrays. If you don't like it you can change this behavior in Add Service Reference window -> Advanced settings where you can select which collection type should be used.
First off, each of the properties that you want to serialize should have the [DataMember] attribute:
[DataContract]
public class Software
{
[DataMember]
public string SoftwareID { get; set; }
[DataMember]
public string SoftwareName { get; set; }
[DataMember]
public string DownloadPath { get; set; }
[DataMember]
public int PackageID { get; set; }
}
Second, the translation to an Array would be handled by the client, not the server.
You can mantain List instead of array on the clien when you add the Service Reference: click the "advanced" button and change the collection type to the one you want.
I was suffering with same problem and now I solved it! It was a ServiceKnownType problem. If you have a in known type loader we have to add runtime Type like;
Type aaa = Type.GetType("System.Collections.Generic.List`1[[ProjectName.BusinessObjects.Bank, ProjectName.BusinessObjects, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null]]");
knownTypes.Add(aaa);
Anyone having same problem can try this. It's working in my environment!