Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to build OdataUntypedSample when upgraded to odata v7 #50

Open
last-Programmer opened this issue Sep 20, 2016 · 28 comments
Open
Labels

Comments

@last-Programmer
Copy link

Hi,

I tried upgrading the odatauntypedsample project to odata libraries version 7 and i am getting build errors

Severity Code Description Project File Line Suppression State
Error CS0234 The type or namespace name 'Library' does not exist in the namespace 'Microsoft.OData.Edm' (are you missing an assembly reference?) ODataUntypedSample D:\Balu\Sgc\ODatav4 Sample\ODataSamples-master\WebApi\v4\ODataUntypedSample\ODataUntypedSample\Controllers\ProductsController.cs 8 Active

Severity Code Description Project File Line Suppression State
Error CS1061 'HttpRequestMessageProperties' does not contain a definition for 'Model' and no extension method 'Model' accepting a first argument of type 'HttpRequestMessageProperties' could be found (are you missing a using directive or an assembly reference?) ODataUntypedSample D:\Balu\Sgc\ODatav4 Sample\ODataSamples-master\WebApi\v4\ODataUntypedSample\ODataUntypedSample\Controllers\ProductsController.cs 41 Active

Is there any breaking change with OData Libraries version 7.

Thanks

@azachert
Copy link

Same thing with DynamicEdmModelCreation.
Is there a plan to update these samples?

@smourier
Copy link

smourier commented Nov 7, 2016

I had the same problem. It seems the new packages contains (a lot of) breaking changes. I finally found a solution. Now that HttpRequestMessageProperties doesn't contain a Model property anymore, to get the model, you just need the new version (should come with the packages update) of HttpRequestMessageExtensions class that contains a GetModel extension method.

So I replaced

var model = Request.ODataProperties().Model;

by

var model = Request.GetModel();

Note I'm unable to find any reference of this change anywhere, and worst, I'm also unable to find the change in the open source available on the supposed repositories here: https://github.com/OData/WebApi/blob/master/OData/src/System.Web.Http.OData/Extensions/HttpRequestMessageExtensions.cs or anywhere else on the Internet :-(

@jlkalberer
Copy link

@smourier thanks for this.

Do you know of any way to set the model in the request?

@joserito
Copy link

joserito commented Jun 2, 2017

Same question? How should we set the model now?
Is there a different approach for this?

@jlkalberer
Copy link

@joserito - I think I ended up just using an older version of OData which isn't ideal...

@last-Programmer
Copy link
Author

Any Update on this please?

@smourier
Copy link

smourier commented Jun 21, 2017

About the initial question, my answer is still valid, you just have to change one line (replace Request.ODataProperties().Model by Request.GetModel()) in the sample, and it works with the newest nuget packages.

About the how to set the model in the request, well, you're still supposed to use routes, like what's done here in the sample:

HttpConfiguration configuration = new HttpConfiguration();
configuration.MapODataServiceRoute("odata", "odata", Model); // sets the model as a Service, available in (request) containers
builder.UseWebApi(configuration);

Note since my original answer, these changes are somewhat documented here (if you want to tweak the whole system): https://odata.github.io/WebApi/13-04-DependencyInjection/ and the code in System.Web.OData dependency that wasn't available back then is now here: https://github.com/OData/WebApi/blob/master/src/System.Web.OData/Extensions/HttpRequestMessageExtensions.cs

@last-Programmer
Copy link
Author

We are using something similar to the code used in
https://github.com/OData/ODataSamples/blob/master/WebApi/v4/DynamicEdmModelCreation/DynamicEdmModelCreation/CustomODataPathRouteConstraint.cs

HttpRequestMessageProperties odataProperties = request.ODataProperties();
odataProperties.Model = model;
odataProperties.PathHandler = PathHandler;
odataProperties.Path = path;
odataProperties.RouteName = RouteName;
odataProperties.RoutingConventions = RoutingConventions;

we can't set the model dynacmically with the new version 7.

Not sure how to achieve the same functionality.

@smourier
Copy link

You could post your question on StackOverflow I guess.

@xuzhg
Copy link
Member

xuzhg commented Jun 23, 2017

@rbmanian75 @smourier @jlkalberer @joserito @azachert

I just added a new ODataUntypedSample project to target the Web API OData v6.0 and ODataLib v7.0.
Would you please try it out and let me know any problem.

@last-Programmer
Copy link
Author

Thank you for the update.

It would be great if you could update this sample also
https://github.com/OData/ODataSamples/blob/master/WebApi/v4/DynamicEdmModelCreation/DynamicEdmModelCreation/CustomODataPathRouteConstraint.cs
in which the model is set dynamically.

because with odatalib 7 it is not possible to set the model dynamically.

Thank you

@jlkalberer
Copy link

Any update on this? Anyone figure out a solution for dynamic models?

@AlanWong-MS AlanWong-MS added the P3 label Sep 20, 2017
@lequangnguyenqn
Copy link

I have a same problem using DynamicEdmModelCreation for version 7.0.0.
Hope will have this update soon.

@jlkalberer
Copy link

jlkalberer commented Oct 20, 2017

I have something I think would work as a solution which I was using in conjunction with the dynamic EDM models -- but I can probably replace the dynamic EDM models with this. It basically updates the $filter server-side and removes any fields that aren't whitelisted.

Last night I was thinking of updating it a bit more (to support more than filtering on my Account model) and putting out an example project. Here's the basic code but it only filters on Account as a navigation property at the moment:

public class FilterQueryForRolesPropertyFilter : EnableQueryAttribute
{
    public FilterQueryForRolesPropertyFilter()
    {
        this.PageSize = 100;
        this.AllowedQueryOptions = AllowedQueryOptions.All;
    }

    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
    {
        var result = base.ApplyQuery(queryable, queryOptions);

        var originalRequest = queryOptions.Request;

        Func<SelectExpandClause, ExpandedNavigationSelectItem, SelectExpandClause> fillTypesRecursive = null;
        fillTypesRecursive = (selectExpandClause, parent) =>
        {
            if (selectExpandClause == null)
            {
                return null;
            }

            List<SelectItem> selectItems = new List<SelectItem>();
            if (this.ShouldFilter(parent, typeof(Account)))
            {
                var edmType = parent.PathToNavigationProperty.OfType<NavigationPropertySegment>().Last().EdmType;
                if (edmType.TypeKind == EdmTypeKind.Collection)
                {
                    edmType = ((EdmCollectionType)edmType).ElementType.Definition;
                }

                var source = parent.NavigationSource;
                var parser = new ODataQueryOptionParser(
                    queryOptions.Context.Model,
                    edmType,
                    source,
                    // THIS IS THE MAGICAL FILTERING CODE!!!
                    new Dictionary<string, string> {{"$select", "id, userName"}}
                );

                return parser.ParseSelectAndExpand();
            }

            foreach (var selectItem in selectExpandClause.SelectedItems)
            {
                var expandedItem = selectItem as ExpandedNavigationSelectItem;
                if (expandedItem != null)
                {
                    expandedItem = new ExpandedNavigationSelectItem(
                                       expandedItem.PathToNavigationProperty,
                                       expandedItem.NavigationSource,
                                       fillTypesRecursive(expandedItem.SelectAndExpand, expandedItem),
                                       expandedItem.FilterOption,
                                       expandedItem.OrderByOption,
                                       expandedItem.TopOption,
                                       expandedItem.SkipOption,
                                       expandedItem.CountOption,
                                       expandedItem.SearchOption,
                                       expandedItem.LevelsOption);
                    selectItems.Add(expandedItem);
                }
                else
                {
                    //expandedItem.SelectAndExpand = fillTypesRecursive(expandedItem.SelectAndExpand);
                    selectItems.Add(selectItem);
                }

            }

            return new SelectExpandClause(selectItems, selectExpandClause.AllSelected);
        };

        var clause = originalRequest.ODataProperties().SelectExpandClause;
        if (clause != null)
        {
            originalRequest.ODataProperties().SelectExpandClause = fillTypesRecursive(clause, null);
        }
    
        return result;
    }

    private bool ShouldFilter(ExpandedNavigationSelectItem parent, Type typeToFilter)
    {
        if (parent == null)
        {
            return false;
        }

        var expandType = parent.PathToNavigationProperty.OfType<NavigationPropertySegment>().Last().EdmType;

        string expandedTypeName = null;
        // For single navigation properties
        if (expandType is EdmEntityType)
        {
            expandedTypeName = ((EdmEntityType)expandType).FullTypeName();
        }
        else if (expandType is EdmCollectionType)
        {
            expandedTypeName = ((EdmCollectionType)expandType).ElementType.Definition.FullTypeName();
        }

        return !string.IsNullOrWhiteSpace(expandedTypeName) && typeToFilter.FullName.Contains(expandedTypeName);
    }
}

I'll post an update with link to the code if I get to it. Personally, I'd really like to update my OData code to v7 so this should happen soonish

@jlkalberer
Copy link

jlkalberer commented Oct 22, 2017

Hey everyone, I got motivated over the weekend and I implemented a different way to filter the properties on entities by overriding the behavior of the EnableQueryAttribute instead of using dynamic EDM models. The code is a little rough and could probably be optimized a bit but it handles most of my use-cases.

Please pull the repo and try it out. Let me know if it's missing some features and send a pull request if you can think of any improvements.

@Nkrb
Copy link

Nkrb commented Jan 31, 2018

@smourier I have the following error
Error CS0234 The type or namespace name 'Library' does not exist in the namespace 'Microsoft.OData.Edm' (are you missing an assembly reference?) .
what is the solution for this

@Nkrb
Copy link

Nkrb commented Jan 31, 2018

@rbmanian75 @azachert @jlkalberer @joserito
any one has workaround for this error.
Error CS0234 The type or namespace name 'Library' does not exist in the namespace 'Microsoft.OData.Edm' (are you missing an assembly reference?)

@mgernand
Copy link

mgernand commented Mar 8, 2018

Hi folks! :-)

The new version of the OData Libraries use the default DI container to manage dependencies and services. The model (IEdmModel) is also registered as dependency (for a specific OData route).

To implement a model-per-request pattern (as in the DynamicEdmModelCreation sample) one has to implement a model factory that creates the IEdmModel for a OData route (in the sample for is for the given name of a datasource) for every request. The model to use must then be acquired from a scoped (per-request) container.

I need the dynamic model creation (model-per-request) feature and will look into fixing the sample soon. There are some more obstacles beside the dynamic model creation. I hope to look into the rest ver soon and keep up updated.

Cheers, Matt

See: #65 (comment)

@last-Programmer
Copy link
Author

Waiting to see the samples. We are stuck in upgrading our project for long time because of this issue.

@mgernand
Copy link

Hi folks,

I just added a pull request that fixes the dynamic model creation sample for v6:

Issue: #65
Pull Request: #67

Maybe this helps with this issue too.

Cheers, Matt

@jlkalberer
Copy link

So the key is just this line builder.AddService<IEdmModel>(ServiceLifetime.Scoped, sp =>?

I will give your code a go but I tried using dependency injection. The callback would only run once so the model wasn't being recreated... maybe my scope was just wrong or there is more to the example than I'm seeing.

@last-Programmer
Copy link
Author

By seeing the sample i am trying to upgrade our project. We are using a custom odata query parser where we are parsing the $filter property like this

` HttpRequestMessageProperties odataProperties = this.Request.ODataProperties();

        ODataQueryOptionParser odataQueryOptionParser =
            new ODataQueryOptionParser(
                odataProperties.Model,
                collectionType.ElementType.Definition,
                odataProperties.Path.NavigationSource,
                new Dictionary<string, string>() { ["$filter"] = this.Parameters.Filter });`

Here we are using the odata model from oDataProperties(). We are not sure how to determine the model at this place where we are using custom parser to filter the data.

@jlkalberer
Copy link

@rbmanian75 - check out my example. I actually do this there. I think the code is outdated and has a few bugs but it will give you the general idea.

@last-Programmer
Copy link
Author

I managed to get the model from the new method Request.GetModel(). Thanks

@last-Programmer
Copy link
Author

The sample you have provided when hosted in asp.net gives the following error.(in our project we host odata in asp.net). The error happens in the line configuration.Routes.Remove(routeName); But when self hosted it works fine. Is there anyway we can fix this?
`
This operation is not supported by 'HostedHttpRouteCollection'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NotSupportedException: This operation is not supported by 'HostedHttpRouteCollection'.

Source Error:

Line 35:
Line 36: ODataRoute odataRoute = new ODataRoute(route.RoutePrefix, new CustomODataPathRouteConstraint(routeName));
Line 37: configuration.Routes.Remove(routeName);
Line 38: configuration.Routes.Add(routeName, odataRoute);
Line 39:

Source File: C:\S\SGC\Sgc.Web\OData.Web\Handlers\ODataCustom\DynamicModelHelper.cs Line: 37

`

@last-Programmer
Copy link
Author

last-Programmer commented Mar 16, 2018

To Solve the above mentioned issue there should be a way to specify the customodataroute and customodatapathrouteconstraint in mapodataserviceroute.

Please check this issue also OData/WebApi#826

@piyushparate1
Copy link

piyushparate1 commented May 11, 2018

Hi everyone, In my case "$expand" is not working. Associate/Child records not returned in result.
Can anyone help me or pass on some clue, Many thanks in advance.

Error details: https://stackoverflow.com/questions/50265218/expand-not-working-associate-child-records-not-returned-in-result-update
Source code: https://github.com/piyushparate1/SampleODataUntyped

@daviburg
Copy link

daviburg commented Feb 1, 2019

      I managed to get the model from the new method Request.GetModel(). Thanks

I don't understand this comment. Request.GetModel() (and SetModel) methods were made obsolete long ago and replaced with the very ODataProperties().Model gettable-settable property which is here also removed albeit without a clear replacement.

There is the referred App_Start sample for providing a model on demand through the registered delegate. When we had a HttpRequestMessage it used to be possible to set the edm model for it, and I don't understand how to do the same here. My specific case is complicated by trying this in the context of a unit test for a service with dynamic EDM, upgrading the service from the older odata injection with gettable-settable property to the current approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests