2

I'm using the JsonApiDotNetCore library, and I'm trying to push data through SignalR to the clients. Pushing the data is no problem, however, I want to be this data formatted according to the JSON:API specs. As the JsonApiDotNetcore library already does this for general API calls, I'm trying to do the same for the SignalR messages.

I tried to access the IJsonApiOptions, and use the SerializerOptions of it to serialize my data. Unfortunately, this doesn't work. Also not when I add a ResourceObjectConverter to it myself.

Is there any option to do this?

We are currently running on v5.0.3, as of problems on the front-end application which needs a lot of rewrites if we update it.

1 Answer 1

0

I fixed it myself, by using a special converter. I've created a ICustomResponseModelAdapter which uses objects from the library itself, see below the implementation. It's not fully JSON:API format, as we are triggering also some other entities in an endpoint for other entities (For example if Group is changed, it's possible we send an event for a User also)

using System;
using System.Collections.Generic;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Middleware;
using JsonApiDotNetCore.Queries.Internal;
using JsonApiDotNetCore.QueryStrings;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Serialization.Objects;
using JsonApiDotNetCore.Serialization.Response;

namespace xxx.Api.SignalR
{
    public class CustomResponseModelAdapter : ResponseModelAdapter, ICustomResponseModelAdapter
    {
        private readonly IJsonApiRequest _request;
        private readonly IJsonApiOptions _options;
        private readonly ILinkBuilder _linkBuilder;
        private readonly IMetaBuilder _metaBuilder;
        private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor;
        private readonly IEvaluatedIncludeCache _evaluatedIncludeCache;
        private readonly IRequestQueryStringAccessor _requestQueryStringAccessor;
        private readonly ISparseFieldSetCache _sparseFieldSetCache;
        private readonly IResourceGraph _resourceGraph;

        public CustomResponseModelAdapter(IJsonApiRequest request, IJsonApiOptions options, ILinkBuilder linkBuilder, IMetaBuilder metaBuilder, IResourceDefinitionAccessor resourceDefinitionAccessor, IEvaluatedIncludeCache evaluatedIncludeCache, ISparseFieldSetCache sparseFieldSetCache, IRequestQueryStringAccessor requestQueryStringAccessor, IResourceGraph resourceGraph) : base(request, options, linkBuilder, metaBuilder, resourceDefinitionAccessor, evaluatedIncludeCache, sparseFieldSetCache, requestQueryStringAccessor)
        {
            _resourceGraph = resourceGraph;

            _request = request;
            _options = options;
            _linkBuilder = linkBuilder;
            _metaBuilder = metaBuilder;
            _resourceDefinitionAccessor = resourceDefinitionAccessor;
            _evaluatedIncludeCache = evaluatedIncludeCache;
            _sparseFieldSetCache = sparseFieldSetCache;
            _requestQueryStringAccessor = requestQueryStringAccessor;
        }

        public Document ConvertSpecific(object model)
        {
            _sparseFieldSetCache.Reset();

            Document document = new Document();

            Action<ResourceObject, ResourceType, IIdentifiable> addRelations = (ResourceObject resourceObject, ResourceType resourceType, IIdentifiable resource) =>
            {
                foreach (JsonApiDotNetCore.Resources.Annotations.RelationshipAttribute relation in resourceType.Relationships)
                {
                    resourceObject.Relationships ??= new Dictionary<string, RelationshipObject?>();
                    resourceObject.Relationships.Add(relation.PublicName, new RelationshipObject
                    {
                        Links = _linkBuilder.GetRelationshipLinks(relation, resource),
                        Data = default
                    });
                }
            };

            if (model is IEnumerable<IIdentifiable> resources)
            {
                ResourceType resourceType = null;

                List<ResourceObject> resourceObjects = new List<ResourceObject>();
                foreach (IIdentifiable resource in resources)
                {
                    if (resourceType == null)
                        resourceType = _resourceGraph.GetResourceType(resource.GetType());
                    ResourceObject resourceObject = ConvertResource(resource, resourceType, EndpointKind.Primary);

                    // Add relationships
                    addRelations(resourceObject, resourceType, resource);

                    // Add to results
                    resourceObjects.Add(resourceObject);
                }

                // Add to document
                document.Data = new SingleOrManyData<ResourceObject>(resourceObjects);
            }
            else if (model is IIdentifiable resource)
            {
                ResourceType resourceType = _resourceGraph.GetResourceType(model.GetType());

                ResourceObject resourceObject = ConvertResource(resource, resourceType, EndpointKind.Primary);
                // Add relationships
                addRelations(resourceObject, resourceType, resource);

                // Add to document
                document.Data = new SingleOrManyData<ResourceObject>(resourceObject);
            }
            else
            {
                throw new InvalidOperationException("Data being returned must be resources, operations, errors or null.");
            }

            document.JsonApi = GetApiObject();
            document.Links = _linkBuilder.GetTopLevelLinks();
            document.Meta = _metaBuilder.Build();

            return document;
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.