Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
578 views
in Technique[技术] by (71.8m points)

asp.net - Web API Queryable - how to apply AutoMapper?

I've got a simple WebApi method like this decorated with the OData queryable attribute.

    [Queryable]
    public virtual IQueryable<PersonDto> Get()
    {
        return uow.Person().GetAll()); // Currently returns Person instead of PersonD
    }

What I want to do is transform the result of the query from type Person to type PersonDto using AutoMapper before WebAPI converts the result to JSON.

Does anybody know how I can do this? I am aware, I could apply Mapper.Map after the GetAll() call and then convert back to IQueryable, however this would result in the entire table being returned and mapped before the OData filter is applied (not good!).

It would appear that this question ASP.NET Web API return queryable DTOs? covers the same issue (see second response for a better answer), where the suggestion is to use AutoMapper at the end of the chain using a custom MediaTypeFormatter, however I have no idea how to do that based on the example I have seen.

Any help will be gratefully received!

-- Further Info

I've looked at the source code for IQueryable, but unfortunately there I can't see any way of utilising the code for this purpose. I have managed to write an additional filter which appears to work, however it isn't certainly isn't elegant.

public class PersonToPersonDtoConvertAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        HttpResponseMessage response = actionExecutedContext.Response;

        if (response != null)
        {
            ObjectContent responseContent = response.Content as ObjectContent;
            var query = (responseContent.Value as IQueryable<Student>).ToList();
            response.Content = new ObjectContent<IEnumerable<StudentResource>>(query.ToList().Select(Mapper.Map<Person, PersonDto>), responseContent.Formatter);
        }
    }
}

Then I have decorated the action like

    [Queryable]
    [PersonToPersonDtoConvert]
    public IQueryable<Person> Get()
    {
        return uow.GetRepo<IRepository<Person>>().GetAll();
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is a better solution. Try this:

public virtual IQueryable<PersonDto> Get(ODataQueryOptions<Person> query)
{
    var people = query.ApplyTo(uow.Person().GetAll());
    return ConvertToDtos(people);
}

This will make sure the query runs on Person instead of PersonDTO. If you want the conversion to happen through an attribute instead of in code, you'll still want to implement an action filter similar to what you put up.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...