1
votes

I have implemented a custom MediaTypeFormatter in a SelfHosted AspNet WebAPI. I've used Unity.WebApi for dependency resolution. The controller classes only know about the interfaces implemented by the model classes, whereas, repositories give the concrete models as a result of actions.

The custom MediaTypeFormatter is inherited from BufferedMediaTypeFormatter as discussed here: http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters.

The problem is this media type formatter is not working. Even when I use to debug the code, the ReadFormStream method is never hit. Does someone know:

  1. What could be the possible issue?
  2. Do I need to tell the unity container for mapping of interfaces to model classes?
  3. How would I get the reference to the dependency resolver inside the custom media type formatter?

Below is the code to add formatter:


var config = new SelfHostConfiguration("https://xxx.xxx.xxx.xxx:xxxx/");
config.Formatters.Add(new EntityTypeFormatter());

Below is the code for the EntityController:

    public class EntityController : ApiController
    {
        private readonly IEntitiesRepository repository = null;

        public EntityController(IEntitiesRepository repository)
        {
            if (repository == null)
            {
                throw new ArgumentNullException("repository");
            }

            this.repository = repository;
        }

        public IEnumerable<IEntity> Get()
        {
            return (IEnumerable<IEntity>)repository.Get();
        }
    }

Below is the code for the EntityRepository:

    public class EntitiesRepository : IEntitiesRepository
    {
        public IEnumerable<IEntity> Get()
        {
            return new Entities[]
            {
                new Entity
                { 
                    Prop1 = "value for property 1",
                    Prop2 = "value for property 2",
                    Prop3 = "value for property 3"
                },
                new Entity
                { 
                    Prop1 = "value for property 1",
                    Prop2 = "value for property 2",
                    Prop3 = "value for property 3"
                }
            };
        }
        public IEntity Get(long id)
        {
            return new Entity
                {
                    Prop1 = Convert.ToString(id),
                    Prop2 = "value for property 2",
                    Prop3 = "value for property 3"
                };
        }
    }

Below is the implementation of the EntityMediaTypeFormatter class:

public class EntityMediaTypeFormatter : BufferedMediaTypeFormatter 
    {
        public EntityMediaTypeFormatter()
            : base()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        }

        public override bool CanReadType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (type is IEntity)
            {
                return true;
            }
            else if (type.IsGenericType)
            {
                return type.GenericTypeArguments.Single(a => a.GetType().Equals(typeof(IEntity))) != null;
            }

            return false;
        }
        public override bool CanWriteType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (type is IEntity)
            {
                return true;
            }

            return false;
        }

        public override object ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            if (type.IsInterface)
            {
                type = GetConcreteType(type);
            }

            return base.ReadFromStream(type, readStream, content, formatterLogger);
        }
        public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
        {
            //nothing special for now...
            base.WriteToStream(type, value, writeStream, content);
        }

        private Type GetConcreteType(Type type)
        {
            //TODO: Need to find a way to DependencyResolver to get the concrete type
            return typeof(Entity);
        }
    }

Thanking in advance for any help.

1
Regarding 1: I would check if "Content-Type" header is present with the appropriate media type as Web API looks for formatter to read based on the incoming request's media type. It would help if you can share your action and media type formatter code. Also check what does your CanReadType method returns. Based on this ReadFromStream would be invoked.Kiran Challa
@KiranChalla: I've updated the post with code for custom media type formatter. Please let me know if you need to know anything else.user1624372
How are you adding the formatter? are you adding at the end of the formatters' list? do you also have the default xmlmediatypeformatter in the list? what is your Content-Type header value? is it "application/xml"?Kiran Challa
Actually, I am reading entities from the database with EntityFramework. I have plumbed the interfaces with the generated entities in separate partial classes. I am using the browser to test the api action responses (without creating a specific http client and explicity telling it the content-type)user1624372

1 Answers

1
votes

Looks to me like one of the existing formatters is taking priority over yours. Either clear the existing formatter collection before adding yours, or insert yours at position 0.