1

I'm trying to:

    [EnableQuery]
    [HttpGet]
    [ODataRoute("")]
    public IHttpActionResult Get(ODataQueryOptions<UserODataModel> options)
    {
        var users = _repository.RetrieveOData();
       
        var serialQuery = JsonConvert.SerializeObject(options, jsonOptions);
        
        //save serialQuery somewhere

        return Ok(users);
    }

But got

Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'Microsoft.Owin.Host.SystemWeb.CallStreams.InputStream'.'

"Timeouts are not supported on this stream."

I know there is already a question about serialize Stream:

Newtonsoft Json.net - how to serialize content of a stream?

But in this case i can't "extract stream value" from ODataQueryOptions, or can I?

Some ideia?

Community
  • 1
  • 1
anisanwesley
  • 132
  • 1
  • 9
  • 1
    Do you really need to serialize the entire options object? It's pretty complicated and no doubt contains a lot more stuff than you really need. A simpler answer to your question may be to define a new object into which you copy the relevant option data you want, and it's that instance that you serialize. – Brad Jun 16 '19 at 00:03

2 Answers2

2

Since we work on the same company, if anyone is interested, we found a way, maybe not the pretty way, to serialize an ODataQueryOptions:

    public static ODataQueryOptions DeserializeQueryOptions(SerializedQueryOptions options)
    {
        var uri = new Uri(teste.OriginalUri);
        var model = ODataConfig.Model; //GetEdmModel
        var segment = model.EntityContainer.FindEntitySet(options.EdmType);
        var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));

        var httpConfiguration = new HttpConfiguration();
        httpConfiguration.EnableDependencyInjection();
        var request = new HttpRequestMessage(HttpMethod.Get, uri)
        {
            Properties =
            {
                { HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
            }
        };

        var context = new ODataQueryContext(model, options.EntityType, newPath);
        var oDataQueryOptions = new ODataQueryOptions(context, request);

        return oDataQueryOptions;
    }

    public static SerializedQueryOptions SerializeQueryOptions(ODataQueryOptions options)
    {
        return new SerializedQueryOptions
        {
            OriginalUri = options.Request.RequestUri.AbsoluteUri,
            EdmType = options.Context.NavigationSource.Name,
            EntityType = options.Context.ElementClrType
        };
    }

After you serialize it to an object you can serialize it to a JSON string:

    var queryOptionsSerialized = new SerializedQueryOptions()
    {
        OriginalUri = "http://localhost:25723/odata/users?$skip=0&$top=2&$orderby=fullName&$count=true",
        EdmType = "users",
        EntityType = typeof(UserODataModel)
    };

    var json = JsonConvert.SerializeObject(queryOptionsSerialized);
    var deserialized = JsonConvert.DeserializeObject<SerializedQueryOptions>(json);

    var options = ODataQueryOptionsHelper.DeserializeQueryOptions(deserialized);
anisanwesley
  • 132
  • 1
  • 9
0

In case One is not using OData routing or using an ApiController (not ODataController), modify the way of Obtaining ODataPath to:

ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
ODataPath path = parser.ParsePath();
//var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
Microsoft.AspNet.OData.Routing.ODataPath newPath = new Microsoft.AspNet.OData.Routing.ODataPath(path.FirstOrDefault());

where the serviceRoot is the Url part other that the path defined in the model.