Azure Mobile Service TableController not returning inner objects

ε祈祈猫儿з 提交于 2019-12-05 12:59:29

This is default behavior for TableController. In order to achieve what you're looking for, in a fashion way, you should implement OData $expand in your controller.

This article provides a good walk-throughout for the solution
Retrieving data from 1:n relationship using .NET backend Azure Mobile Services

As further extension, I've implemented a custom attribute that you can use in your controller methods to specify which properties the client can request to expand. You may not want to always returned all child relationships (expanded objects)

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class ExpandablePropertyAttribute : ActionFilterAttribute
{
    #region [ Constants ]
    private const string ODATA_EXPAND = "$expand=";
    #endregion

    #region [ Fields ]
    private string _propertyName;
    private bool _alwaysExpand;
    #endregion

    #region [ Ctor ]
    public ExpandablePropertyAttribute(string propertyName, bool alwaysExpand = false)
    {
        this._propertyName = propertyName;
        this._alwaysExpand = alwaysExpand;
    }
    #endregion

    #region [ Public Methods - OnActionExecuting ]
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);
        var uriBuilder = new UriBuilder(actionContext.Request.RequestUri);
        var queryParams = uriBuilder.Query.TrimStart('?').Split(new char[1] { '&' }, StringSplitOptions.RemoveEmptyEntries).ToList();
        int expandIndex = -1;

        for (var i = 0; i < queryParams.Count; i++)
        {
            if (queryParams[i].StartsWith(ODATA_EXPAND, StringComparison.Ordinal))
            {
                expandIndex = i;
                break;
            }
        }

        if (expandIndex >= 0 || this._alwaysExpand)
        {
            if (expandIndex < 0)
            {
                queryParams.Add(string.Concat(ODATA_EXPAND, this._propertyName));
            }
            else
            {
                queryParams[expandIndex] = queryParams[expandIndex] + "," + this._propertyName;
            }

            uriBuilder.Query = string.Join("&", queryParams);
            actionContext.Request.RequestUri = uriBuilder.Uri;
        }

    }
    #endregion
}

Which I use in my controller in this way:

    [ExpandableProperty("Documents", false)]
    public IQueryable<ClientActivity> GetAllClientActivities()
    {
        return Query(); 
    }

I have managed to make complex properties be serialized and sent back to the client. Maybe the solution is not the cleanest, but it works in my case. Hope someone else will find it useful too.

First, create a class that inherits from EnableQueryAttribute and override GetModel method like this:

public class CustomEnableQueryAttribute : EnableQueryAttribute
{
    public override IEdmModel GetModel(Type elementClrType, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)
    {
        var modelBuilder = new ODataConventionModelBuilder();
        modelBuilder.EntitySet<Event>("Events");

        return modelBuilder.GetEdmModel();
    }
}

Then, in your Initialize method of the controller, add these lines:

    protected override void Initialize(HttpControllerContext controllerContext)
    {
        base.Initialize(controllerContext);
        context = new MobileServiceContext();
        DomainManager = new EntityDomainManager<Event>(context, Request, Services);

        //Add these lines
        var service = Configuration.Services.GetServices(typeof(IFilterProvider)).ToList();
        service.Remove(service.FirstOrDefault(f => f.GetType() == typeof(TableFilterProvider)));
        service.Add(new TableFilterProvider(new CustomEnableQueryAttribute()));
        Configuration.Services.ReplaceRange(typeof(IFilterProvider), service.ToList().AsEnumerable());

        Request.Properties.Add("MS_IsQueryableAction", true);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!