Open Closed

Dapr + Outbox Event Eto Deserialization error #5596


User avatar
0
cables created

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ ✔ Check the samples to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index ✔ The exact solution to your question may have been answered before, and please first use the search on the homepage. ✔

Provide us with the following info:

  • ABP Framework version: v7.2
  • UI Type: Blazor Server
  • Database System: EF Core ( MySQL )
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes
  • Exception message and full stack trace:
System.ArgumentNullException: Value cannot be null. (Parameter 'returnType')
   at System.Text.Json.ThrowHelper.ThrowArgumentNullException(String parameterName)
   at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
   at Volo.Abp.Json.SystemTextJson.AbpSystemTextJsonSerializer.Deserialize(Type type, String jsonString, Boolean camelCase) in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.Json.SystemTextJson\Volo\Abp\Json\SystemTextJson\AbpSystemTextJsonSerializer.cs:line 30
   at Volo.Abp.Dapr.Utf8JsonDaprSerializer.Deserialize(Byte[] value, Type type) in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.Dapr\Volo\Abp\Dapr\Utf8JsonDaprSerializer.cs:line 24
   at Volo.Abp.EventBus.Dapr.DaprDistributedEventBus.PublishManyFromOutboxAsync(IEnumerable`1 outgoingEvents, OutboxConfig outboxConfig) in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.EventBus.Dapr\Volo\Abp\EventBus\Dapr\DaprDistributedEventBus.cs:line 153
   at Volo.Abp.EventBus.Distributed.OutboxSender.PublishOutgoingMessagesInBatchAsync(List`1 waitingEvents) in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.EventBus\Volo\Abp\EventBus\Distributed\OutboxSender.cs:line 128
   at Volo.Abp.EventBus.Distributed.OutboxSender.RunAsync() in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.EventBus\Volo\Abp\EventBus\Distributed\OutboxSender.cs:line 89
   at Volo.Abp.EventBus.Distributed.OutboxSender.RunAsync() in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.EventBus\Volo\Abp\EventBus\Distributed\OutboxSender.cs:line 106
   at Volo.Abp.EventBus.Distributed.OutboxSender.TimerOnElapsed(AbpAsyncTimer arg) in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.EventBus\Volo\Abp\EventBus\Distributed\OutboxSender.cs:line 68
   at Volo.Abp.Threading.AbpAsyncTimer.Timer_Elapsed() in C:\source\AppEngine\AppEngine\abp\framework\src\Volo.Abp.Threading\Volo\Abp\Threading\AbpAsyncTimer.cs:line 105

  • Steps to reproduce the issue:
    • New tierd microservice project
    • Outbox configured for the microservice to be tested
    • Dapr event bus configured for the microservice
    • aggregate root entity that publishes a custom changed event in this microservice
    • dapr and sidecar setup for the microservice that has the aggregate root entity
    • controller and appservice to update this entity
    • using swagger, update the entity
    • see that an event is pushed to the outbox
    • see logs that now show above error
[Serializable]
public class PaymentTerm_UpdatedEto
{
    public PaymentTerm_UpdatedEto() { }

    public PaymentTerm_UpdatedEto(
        Guid paymentTermId,
        PaymentTermEto oldPaymentTerm,
        PaymentTermEto newPaymentTerm)
    {
        Check.NotDefaultOrNull<Guid>(paymentTermId, nameof(paymentTermId));
        Check.NotNull(oldPaymentTerm, nameof(oldPaymentTerm));
        Check.NotNull(newPaymentTerm, nameof(newPaymentTerm));

        PaymentTermId = paymentTermId;
        OldPaymentTerm = oldPaymentTerm;
        NewPaymentTerm = newPaymentTerm;
    }


    public Guid PaymentTermId { get; set; }

    public PaymentTermEto OldPaymentTerm { get; set; }

    public PaymentTermEto NewPaymentTerm { get; set; }
}

[Serializable]
public class PaymentTermEto
{
    public Guid Id { get; set; }
    public Guid? TenantId { get; set; }

    public string Name { get; set; }
}

public class PaymentTerm :
    AuditedAggregateRoot<Guid>,
    IMultiTenant
{
    public PaymentTerm(
        Guid id,
        string name,
        Guid? tenantId = null)
    {
        Id = id;

        SetName(name);

        TenantId = tenantId;
    }


    public string Name { get; protected set; }

    public Guid? TenantId { get; protected set; }


    private void SetName([NotNull] string name)
    {
        Check.NotNullOrWhiteSpace(name, nameof(name));
        Check.Length(name, nameof(name),
            PaymentTermConsts.NameMaxLength, PaymentTermConsts.NameMinLength);

        //do not trigger Entity changed event if the value is the same
        if (Name?.ToLower() != name.ToLower())
        {
            PaymentTermEto eto = null;
            
            if (Name != null)
                eto = ToEto();

            Name = name;

            if (null != eto)
                PublishChangedEvent(eto);
        }
    }
	
	
	private void PublishChangedEvent(PaymentTermEto old)
    {
        ClearDistributedEvents();

        AddDistributedEvent(new PaymentTerm_UpdatedEto(this.Id, old, this.ToEto()));
    }

    private PaymentTermEto ToEto()
    {
        return new PaymentTermEto
        {
            Id = Id,
            TenantId = TenantId,
            Name = Name
        };
    }

}

If i do not use the outbox the event is pushed correctly over the dapr bus. Zipkin shows this.

any help is appreciated, thank you for your time


5 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    You can try adding the EventNameAttribute, for example:

    [Serializable]
    [EventName("payment.term.updated")]
    public class PaymentTerm_UpdatedEto
    {
        public PaymentTerm_UpdatedEto() { }
    
        public PaymentTerm_UpdatedEto(
            Guid paymentTermId,
            PaymentTermEto oldPaymentTerm,
            PaymentTermEto newPaymentTerm)
        {
            Check.NotDefaultOrNull(paymentTermId, nameof(paymentTermId));
            Check.NotNull(oldPaymentTerm, nameof(oldPaymentTerm));
            Check.NotNull(newPaymentTerm, nameof(newPaymentTerm));
    
            PaymentTermId = paymentTermId;
            OldPaymentTerm = oldPaymentTerm;
            NewPaymentTerm = newPaymentTerm;
        }
    
    
        public Guid PaymentTermId { get; set; }
    
        public PaymentTermEto OldPaymentTerm { get; set; }
    
        public PaymentTermEto NewPaymentTerm { get; set; }
    }
    
  • User Avatar
    0
    cables created

    Thanks for your reply. I tested it with the addition of the EventNameAttribute and I receive the same error.

    I did not think that would work anyway, as the error in my initial comment says Value cannot be null. (Parameter 'returnType') and the method that throws is System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)

    If i understand the error correctly, it cannot determine the type to deserialze as from the outbox json blob. This only happens with the abp.dapr addition. without abp.dapr, the type is deserialzed from the outbox just fine. there are no errors showing anywhere else in any process' logs. dapr sidecar and zipkin are working just fine too.

    Update: I've stepped through ABP's code. Volo.Abp.EventBus.Dapr.DaprDistributedEventBus PublishManyFromOutboxAsync -> PublishToDaprAsync -> GetEventType -> EventTypes.GetOrDefault(eventName): EventTypes does not have a key and value for the EventNameAttribute or the full type name (PaymentTerm_UpdatedEto).

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi cables

    Can you try to upgrade to 7.3.x and try again?

    Thanks

  • User Avatar
    0
    cables created

    Hello,

    I have not had a moment to complete your request. I will get back to you soon.

    Thanks!

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    No problem.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11