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

BUG: GetFeed of LogRecord fails in Geotab.Checkmate.ObjectModel package version 5.7.2103.1 #154

Open
IanKemp opened this issue Oct 11, 2021 · 3 comments

Comments

@IanKemp
Copy link

IanKemp commented Oct 11, 2021

The following NuGet package call:

            var now = DateTimeOffset.UtcNow;
            LogRecordSearch searchParams = new()
            {
                FromDate = now.AddHours(-1).DateTime,
                ToDate = now.DateTime,
            };

            var gps = await api.CallAsync<IEnumerable<LogRecord>>("GetFeed", typeof(LogRecord), new
            {
                search = searchParams,
            });

yields the following request:

{
    "id": 0,
    "method": "GetFeed",
    "params": {
        "credentials": {
            "database": "<redacted>",
            "sessionId": "<redacted>",
            "userName": "<redacted>"
        },
        "typeName": "Geotab.Checkmate.ObjectModel.LogRecord",
        "search": {
            "fromDate": "2021-10-11T14:36:12.680Z",
            "toDate": "2021-10-11T15:36:12.680Z",
            "observeActiveState": false
        }
    }
}

which results (via Fiddler) in the following response:

{
    "result": {
        "data": [
<records>
        ],
        "toVersion": "0000000003a7c824"
    },
    "jsonrpc": "2.0",
    "id": 0
}

but using the NuGet package, the following exception is raised:

System.Exception: Error getting json response. HttpStatusCode: OK

JsonException: The JSON value could not be converted to System.Collections.Generic.IEnumerable`1[Geotab.Checkmate.ObjectModel.LogRecord]. Path: $.result | LineNumber: 0 | BytePositionInLine: 11.

This essentially makes the package unusable for us at this time.

@IanKemp
Copy link
Author

IanKemp commented Oct 12, 2021

Tried with package version 5.7.2102.1, same issue.

Issue also seems to affect all GetFeed calls, not just LogRecord.

@IanKemp
Copy link
Author

IanKemp commented Oct 12, 2021

Ah, the reason is that I wasn't using FeedResult<T> as the typeparam. So the corrected code would be:

            var gps = await api.CallAsync<FeedResult<LogRecord>>("GetFeed", typeof(LogRecord), new
            {
                search = searchParams,
            });

That said, your NuGet package is very strange - I don't understand why you are forcing the use of magic strings to invoke methods instead of proper strongly-typed methods, which is the entire point of a strongly-typed language like C#:

public interface IApi
{
    Task<FeedResult<TEntity>> GetFeedAsync<TEntity>(object parameters = null, CancellationToken cancellationToken);
}

Implementation of the above would simply delegate to the current CallAsync:

public class API : IApi
{
    public async Task<FeedResult<TEntity>> GetFeedAsync<TEntity>(object parameters = null, CancellationToken cancellationToken = default(CancellationToken))
        where TEntity : Entity
        => await CallAsync<FeedResult<TEntity>>("GetFeed", typeof(TEntity), parameters, cancellationToken);
}

Literally a handful of lines of code that would make the package so much more user-friendly...

@IanKemp
Copy link
Author

IanKemp commented Oct 12, 2021

I've created the following classes to make using this package easier:

    public class ApiGetParameters
    {
        public object Search { get; set; }

        public int ResultsLimit { get; set; } = 50_000;
    }

    public class ApiGetFeedParameters
    {
        public object Search { get; set; }

        public int ResultsLimit { get; set; } = 50_000;

        public string FromVersion { get; set; }
    }

    public static class IApiExtensions
    {
        public static async Task<IEnumerable<TEntity>> GetAsync<TEntity>(this IApi api,
            ApiGetParameters parameters = null, CancellationToken cancellationToken = default)
            where TEntity : Entity
            => await api.CallAsync<IEnumerable<TEntity>>("Get", typeof(TEntity), new
            {
                search = parameters?.Search,
                resultsLimit = parameters?.ResultsLimit,
            }, cancellationToken);

        public static async Task<FeedResult<TEntity>> GetFeedAsync<TEntity>(this IApi api,
            ApiGetFeedParameters parameters = null, CancellationToken cancellationToken = default)
            where TEntity : Entity
            => await api.CallAsync<FeedResult<TEntity>>("GetFeed", typeof(TEntity), new
            {
                search = parameters?.Search,
                resultsLimit = parameters?.ResultsLimit,
                fromVersion = parameters?.FromVersion,
            }, cancellationToken);
    }

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

No branches or pull requests

1 participant