azure-functions-extension icon indicating copy to clipboard operation
azure-functions-extension copied to clipboard

Retrieve from state store could support JSON-serializable datatype

Open jsacapdev opened this issue 4 years ago • 2 comments

Currently, to save an object to the state store, it looks like the following is supported:

        [FunctionName(Constants.CreateNewOrder)]
        public void Run(
            [DaprServiceInvocationTrigger] OrderItem orderItem,
            [DaprState("%StateStoreName%", Key = "{orderItem.id}")] out OrderItem order)
        {
            order = orderItem;
        }

Where OrderItem is automatically desearlised by the functions runtime, and added to the store. The following also looks like it is supported:

        [FunctionName(Constants.CreateNewOrder)]
        public async Task Run(
            [DaprServiceInvocationTrigger] OrderItem orderItem,
            [DaprState("%StateStoreName%", Key = "{orderItem.id}")] IAsyncCollector<OrderItem> store)
        {
            await store.AddAsync(orderItem);
        }

It would be great if this same style was supported for a retrieve. So, the following would be ideal:

        [FunctionName(Constants.RetrieveOrder)]
        public ActionResult<OrderItem> Run(
            [DaprServiceInvocationTrigger] string stateKey,
            [DaprState("%StateStoreName%", Key = "{stateKey}")] OrderItem item)
        {
            return item;
        }

Currently, it looks like this is not supported, because when calling the method, the following is reported back:

== APP == [07/09/2020 13:58:28] Executed 'RetrieveOrder' (Failed, Id=a571dbc7-c326-4eb1-ab15-20a56d0c1e57)

== APP == [07/09/2020 13:58:28] System.Private.CoreLib: Exception while executing function: RetrieveOrder. Anonymously Hosted DynamicMethods Assembly: Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'IngestFunction.Model.OrderItem'.

Let me know if you think this is a good idea and if so, happy to contribute if I can.

jsacapdev avatar Jul 09 '20 14:07 jsacapdev

Just to narrow down the problem, expression binding using simple types is supported and we have a unit test which verifies this (link):

[FunctionName(nameof(GetState1))]
public static string GetState1(
    [DaprServiceInvocationTrigger] string stateKey,
    [DaprState("store1", Key = "{stateKey}")] string existingState)
{
    return existingState;
}

The error you're seeing appears to be a problem converting the state object into a user-defined OrderItem. This is supposed to be supported, but it looks like there is an issue with our test coverage for this specific scenario and there might be a bug here in our converter code.

As a workaround, try using object instead of OrderItem to see if that helps:

[FunctionName(Constants.RetrieveOrder)]
public ActionResult<OrderItem> Run(
    [DaprServiceInvocationTrigger] string stateKey,
    [DaprState("%StateStoreName%", Key = "{stateKey}")] object item)
{
    return (OrderItem)item;
}

cgillum avatar Jul 10 '20 17:07 cgillum

@cgillum just a fyi, changing it to

        [FunctionName(Constants.RetrieveOrder)]
        public ActionResult<OrderItem> Run(
            [DaprServiceInvocationTrigger] RetrieveOrderRequest request,
            [DaprState("%StateStoreName%", Key = "{request.id}")] object item)
        {
            return (OrderItem)item;
        }

didn't work for me, the logs still report back:

== APP == [07/13/2020 14:10:12] Executing 'RetrieveOrder' (Reason='', Id=287696a5-22eb-4e18-8fea-e53a73a5e820)

== APP == [07/13/2020 14:10:12] Executed 'RetrieveOrder' (Failed, Id=287696a5-22eb-4e18-8fea-e53a73a5e820)

== APP == [07/13/2020 14:10:12] System.Private.CoreLib: Exception while executing function: RetrieveOrder. IngestFunction: Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'IngestFunction.Model.OrderItem'.

jsacapdev avatar Jul 13 '20 14:07 jsacapdev

Closing this issue, as this issue is fixed with this PR.

ASHIQUEMD avatar Oct 03 '23 13:10 ASHIQUEMD