user5166592
user5166592

Reputation:

ASP.NET WebApi JSON Response and Entities with foreign key

I'm working on WebApi project and I have 2 entities in my domain:
Street

public class Street
{
  public int ID { get; set; }
  public string Name { get; set; }
  public int StreetTypeID { get; set; }
  public virtual StreetType StreetType { get; set; }
}

and StreetType:

public class StreetType
{
  public int ID { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Street> Streets { get; set; }
}

I use FluenApi to map these entities:

public class StreetTypeMap : EntityTypeConfiguration<StreetType>
{
  public StreetTypeMap()
  {
     HasKey(t => t.ID);
     Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
     Property(t => t.Name).IsRequired().HasMaxLength(50);
     HasMany(a => a.Streets).WithRequired(p => p.StreetType).HasForeignKey(p => p.StreetTypeID);
     ToTable("StreetType");
   }
 }

and the similar for Street entity.
Now I get JSON:

{
  "id":1,
  "name":"Street1",
  "streettypeid":3
}

How can I get the JSON like:

{
  "id":1,
  "name":"Street1",
  "streettypeid":
   {
    "id":3,
    "name":"Type3"
   }
}

Or some similar structure. How can I accomplish this in .NET?

My Controller:

StreetController : BaseApiController<Street>

and

    public class BaseApiController<T> : ApiController where T : BaseEntity
    {
        protected UnitOfWork unitOfWork = new UnitOfWork();

        protected IRepository<T> repository;

        public BaseApiController()
        {
            repository = unitOfWork.EFRepository<T>();
        }
        public virtual IQueryable<T> Get()
        {
          var entity = repository.Table;

          if (entity == null)
          {
              throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NoContent));
          }
          return entity;
      }

}

Upvotes: 5

Views: 7765

Answers (2)

Roman Marusyk
Roman Marusyk

Reputation: 24589

To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
    Newtonsoft.Json.PreserveReferencesHandling.All;

For more datail please read this article.

Another way is try to use OData in your webapi. You have to install the OData Packages:

Install-Package Microsoft.AspNet.Odata

Then you'll able yo use $expand that causes related entities to be included inline in the response.
You can leave all as is, but I think it will properly to add IgnoreDataMember (do not forget add using System.Runtime.Serialization;)

public class StreetType
{
  public int ID { get; set; }
  public string Name { get; set; }
  [IgnoreDataMember]
  public virtual ICollection<Street> Streets { get; set; }
}

Also need to add attribute to you Get method:

[EnableQuery]
public virtual IQueryable<T> Get()

After that you can create http-request like:

http://blablabla/Street?$expand=StreetType

and get all Streets with their StreetType

Upvotes: 2

Stephen Brickner
Stephen Brickner

Reputation: 2602

You need to create a view model to return that has the included entity.

Edit: here's a complete api controller method including proposed route.

    [HttpGet, Route("/api/streets/{id:int:min(1)}")]
    public IHttpActionResult GetYourJsonData(int id)
    {
        try
        {
            //from your unit of work class
            return uow.GetEntities<Street>(x => x.ID == id)
                .FirstOrDefault()
                .Select(viewModel => new {
                    ID = viewModel.ID,
                    Name = viewModel.Name,
                    StreetTypeID = viewModel.StreetType //consider renaming this to streeytype and not street type id
                });
        }
        catch(Exception)
        {
             return InternalServerError();
        }
    }



//Edit: in your repo class
public IEnumerable<T> GetEntities<T>(Func<T, bool> predicate) where T : class
{
    return yourContext.Set<T>().Where(predicate);
}

Upvotes: 1

Related Questions