NServiceBus Saga can't find handler because it's using the wrong ID - handler

I am using NSB 4. I have a saga that has the following
BaseSaga<OrderSagaData>,
IAmStartedByMessages<OrderMessage>,
IHandleMessages<VendorCreatedMessage>, ....
BasSaga just wraps saga. I don't know why I've got bigger fish to fry right now.
I then have
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<VendorCreatedMessage>(m => m.SagaId).ToSaga(s => s.Id);
my OrderSagaData looks like this
[Serializable]
public class OrderSagaData : IContainSagaData
{
[Unique]
public virtual Guid Id { get; set; }
public virtual Guid MessageId { get; set; }
VendorCreatedMessage
[Serializable]
public class VendorCreatedMessage
{
public Guid SagaId { get; set; }
public Guid MessageId { get; set; }
Then finally in my logs I get
Could not find a saga for the message type Messages.Vendors.VendorCreatedMessage with id 7af7dff2-bf03-4ebd-9e6c-a27a01125ceb. Going to invoke SagaNotFoundHandlers.
The message is the correct namespace and all, but the id (7af7) is not only the wrong id but I can't find it anywhere else. It's not in the vendor service logs or in the saga logs. When I look at the queue the vendor service is sending the correct SagaId.
I'm very confused and don't know where it's getting strange (7af7) id or why it's not using the proper sagaid.
Any help would be appreciated.

Related

How do we send a message with Object type or a abstract class to the masstransit message

Currently, I want to pass an object type to the message to avoid reading the DB twice.
But my solution which has the RabbitMQ is not a reference to the domain entities, it only has the abstract class and the interface of the entities.
So, Is there any way to pass an abstract class or interface to the message of the RabbitMQ?
Thank you for your advices!
public interface IDomainEntity
{
// The rest of the code
}
public abstract class Person
{
// The rest of the code
}
public class Employee
{
// The rest of the code
}
public class Employee: IDomainEntity, Person
{
// The rest of the code
}
public class RefreshEmployeeCache : CorrelatedBy<Guid>
{
public Guid EmployeeId { get; set; }
public Person Employee { get; set; } // or public IDomainEntity Employee { get; set; } Can we use this or an althernative way?
public bool IsDeleted { get; set; }
public Guid CorrelationId { get; set; } = Guid.NewGuid();
}
You should be able to cast the message to an object, which should use the Publish(object message) overload (or the Send(object message) overload), allows whatever concrete type is present to be published.
Consumers can implement IConsumer<Person>, providing access to the properties of Person. The subclass type would only be available if it is known to the consumer and requested specifically.

Masstransit RabbitMQ publisher fails to publish "correct" contract

I have been playing around for a while with Masstransit and RabbitMQ creating message contracts to enable communication between two .NET core web API's and I have stumbled across the following.
Suppose I have the contract specified below in both projects:
public class Profile : BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public DefaultMode Mode { get; set; }
public string SuperMode { get; set; }
public ExtraClient? Client { get; set; }
}
Whenever I publish a message
await _publishEndPoint.Publish<Profile>(profileUpdate);
The other end (consumer on the receiver/subscriber API) is able to get only primitive type fields, for example, Name, Description and IsActive.
The rest of the fields are parsed as null even though I am well aware that prior publishing the properties of profileUpdate have proper values.
Has anyone faced something similar?
Is it because of the inheritance?
Kind regards,
Edit#1: Syntax
Edit#2: Posting more information
As requested here is my consumer class:
public class ProfileUpdateConsumer : IConsumer<Profile>
{
private readonly IProfilesHub _profileHub;
public ProfileUpdateConsumer(IProfilesHub profileHub)
{
_profileHub = profileHub;
}
public async Task Consume(ConsumeContext<Profile> context)
{
await _profileHub.BroadcastProfileUpdate(context.Message);
}
}
And here is my publisher class:
public class ProfilePublisher : IPublisher
{
private readonly IPublishEndpoint _publishEndPoint;
public ProfilePublisher(IPublishEndpoint publishEndpoint)
{
_publishEndPoint = publishEndpoint;
}
public async Task PublishProfileUpdate(object profileUpdate)
{
await _publishEndPoint.Publish<Profile>(profileUpdate);
}
}
I know it's been a while, but for anyone who might come across this.
After discussing with #Chris Patterson ,
I did a manual conversion of the one data type to the other, and made sure that all fields are there.
This worked, even though I still feel quite puzzled as to what was causing this behavior.

Parameter xxx of domain operation entry xxx must be one of the predefined serializable types

I get this webservice error sometimes on a SL5 + EF + WCF app.
"Parameter 'role' of domain operation entry 'AddUserPresentationModelToRole' must be one of the predefined serializable types."
here is a similar error, however his solution doesn't work for me.
I have the codegenned DomainService which surfaces the database entities to my client:
[EnableClientAccess()]
public partial class ClientAppDomainService : LinqToEntitiesDomainService<ClientAppUserEntitlementReviewEntities>
{
public IQueryable<Account> GetAccounts()
{
return this.ObjectContext.Accounts;
}
//..etc...
and my custom service which is surfacing a Presentation model, and db entities.
[EnableClientAccess]
[LinqToEntitiesDomainServiceDescriptionProvider(typeof(ClientAppUserEntitlementReviewEntities))]
public class UserColourService : DomainService
{
[Update(UsingCustomMethod = true)]
public void AddUserPresentationModelToRole(UserPresentationModel userPM, Role role, Reviewer reviewer)
{
...
}
public IDictionary<long, byte> GetColourStatesOfUsers(IEnumerable<RBSUser> listOfUsers, string adLogin)
{
//....
}
}
and the PresentationModel:
public class UserPresentationModel
{
[Key]
public long UserID { get; set; }
public byte UserStatusColour { get; set; }
public string MessageText { get; set; }
[Include]
[Association("asdf", "UserID", "UserID")]
public EntityCollection<Account> Accounts { get; set; }
public DateTime AddedDate { get; set; }
public Nullable<long> CostCentreID { get; set; }
public DateTime? DeletedDate { get; set; }
public string EmailAddress { get; set; }
public long EmployeeID { get; set; }
public string FirstName { get; set; }
public Nullable<bool> IsLeaver { get; set; }
public string LastName { get; set; }
public DateTime LastSeenDate { get; set; }
public string LoginDomain { get; set; }
public string LoginName { get; set; }
public byte WorldBuilderStatusID { get; set; }
}
Also cannot get the solution to reliably fail. It seems whenever I change the service slightly ie make it recompile, everything works.
RIAServices unsupported types on hand-built DomainService - seems to be saying the same thing, that decorating the hand built services with the LinqToEntitiesDomainServiceDescriptionProvider should work.
Possible answer here will post back here too with results.
From Colin Blair:
I am a bit surprised it ever works, I don't think I have seen anyone trying to pass additional entiities into a named update before. It might be a bug in RIA Services that it is working at all. What are you trying to accomplish?
Side note, you have a memory leak with your ObjectContext since it is not getting disposed of correctly. Is there a reason you aren't using the LinqToEntitiesDomainSerivce? It would take care of managing the ObjectContext's lifetime for you.
Results:
1) This makes sense. Have refactored out to more sensible parameters now (ints / strings), and all working.
2) Have brought together my 3 separate services into 1 service, which is using the LinqToEntitiesDomainSerivce. The reason I'd split it out before was the assumption that having a CustomUpdate with a PresentationModel didn't work.. and I had to inherit off DomainService instead. I got around this by making a method:
// need this to avoid compile errors for AddUserPresentationModelToRole.. should never be called
public IQueryable<UserPresentationModel> GetUserPresentationModel()
{
return null;
}

How to map and reference entities from other data sources with NHibernate

I'm currently working on and ASP.NET MVC application in which I have a User entity like follows:
public class User
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Role { get; protected set; }
public virtual Location Location { get; protected set; }
}
Where location is just as straightforward:
public class Location
{
public virtual string Id { get; protected set; }
public virtual string Building { get; protected set; }
public virtual string City { get; protected set; }
public virtual string Region { get; protected set; }
}
My complication arises because I want to populate the User from Active Directory and not the database. Additionally, several classes persisted to the database reference a user as a property. I've got an ADUserRepository for retrieval, but I don't know how to integrate these Users into my object graph when the rest is managed by NHibernate.
Is there a way for NHibernate to persist just an id for a User without it being a foreign key to a Users table? Can I map it as a component to accomplish this? I've also looked at implementing IUserType to make the translation. That way it would map to a simple field and ADUserRepository could be put in the chain to resolve the stored Id. Or am I trying to hack something that's not really feasible? This is my first time around with NHibernate so I appreciate any insight or solutions you can give. Thanks.
Update
It appears my best solution on this will be to map the User with an IUserType and inject (preferably with StructureMap) a service for populating the object before its returned. Framed in that light there are a couple of questions here that deal with the topic mostly suggesting the need for a custom ByteCodeProvider. Will I still need to do this in order for IUserType to take a parameterized constructor or do the comments here: NHibernate.ByteCode.LinFu.dll For NHibernate 3.2 make a difference?
using a Usertype to convert user to id and back
public class SomeClass
{
public virtual string Id { get; protected set; }
public virtual User User { get; protected set; }
}
// in FluentMapping (you have to translate if you want to use mapping by code)
public SomeClassMap()
{
Map(x => x.User).Column("user_id").CustomType<UserType>();
}
public class UserType : IUserType
{
void NullSafeSet(...)
{
NHibernateUtil.Int32.NullSafeSet(cmd, ((User)value).Id, index);
}
void NullSafeGet(...)
{
int id = (int)NHibernateUtil.Int32.NullSafeGet(cmd, ((User)value).Id, index);
var userrepository = GetItFromSomeWhere();
return userrepository.FindById(id);
}
}

Polymorphic subscriptions in NServiceBus works only for interfaces?

The simplest way to follow this explanation is a NServiceBus Pub/Sub sample which contains example of "polymorphic subscriptions" (Subscriber2).
Messages: (without changes)
public class EventMessage : IEvent
{
public Guid EventId { get; set; }
public DateTime? Time { get; set; }
public TimeSpan Duration { get; set; }
}
public interface IEvent : IMessage
{
Guid EventId { get; set; }
DateTime? Time { get; set; }
TimeSpan Duration { get; set; }
}
Handler: (without changes)
public class EventMessageHandler : IHandleMessages<IEvent>
{
public void Handle(IEvent message)
{
// ...
}
}
This handler will receive both IEvent and EventMessage messages. But if I will make IEvent a class...
public class IEvent : IMessage
{
Guid EventId { get; set; }
DateTime? Time { get; set; }
TimeSpan Duration { get; set; }
}
...then i will not be able to receive EventMessage but will receive IEvent as before
So i found such simple rule: if you use interface in IHandleMessages<> - it will work, if class - it will not work. Currently i have all messages as classes and i would like to subscribe to parent class message in order to receive all child class messages.
Is it intended behavior?
This is all by design in order to enable multiple inheritance. The reasons to do so are detailed here. Publicly available events between Business Components are recommended to be modeled as interfaces, commands within a business component are recommended to be modeled as classes. Sounds like you want this behaviour, I would switch over to interfaces.