5

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;
      }

}

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. Whili I try it I got an error: Could not find a property named 'StreetTypes' on type 'Domain.Entities.Street'."
Which http-request do you use?
Ok, why $expand=StreetTypes? There is no property with the name StreetTypes. In your Street class exists public virtual StreetType StreetType { get; set; }. So, you have to use http://mysite/Street?$expand=StreetType
Oh, yes, you are exactly right. I am very inattentive. Thanks its working!!! Thank you very much. You really help me. Thanks. It was the best simple solution
1

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);
}

10 Comments

Thanks but I can not use dbContext in my controller because there is implemented pattern UnitOfWork and I do not have dbContext
Can you update your question to show what you are using to get data then? Ultimately it will be the same, the data context part will just move inside of your repository that is exposed by your unit of work.
My UnitOfWork is not work with concrete entity. UnitOfWork work with dbcontext: IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
Then you just need to add a predicate. I updated my answer to show you what you'll need to do in your repo.
No problem, I've updated my answer to show you how you would use it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.