I have a nservice bus project which which i will call connector. My connector receives variouis kinds of messages for example ClientChangeMessage, ClientContactChangeMessage. My connector has not implemented saga so i have handler for each message so for ClientChangeMessage I have ClientChangeMessageHandler which gets fired when connector receives ClientChangeMessage and a ClientContactChangeMessageHandler when i receive a ClientContactChangeMessage.
Now while looking at the sagas implementation i found myself writing the following code (If the Client contact message comes before the ClientChange message i.e the client does not exist in the database):
public class ClientContactChangeMessageHandler : ClientMessageHandler,
IHandleMessages<ClientContactChangeMessage>,
IAmStartedByMessages<ClientContactChangeMessage>,
IHandleMessages<ClientChangeMessage>
{
[SetterProperty]
public IClientContactChangeDb ClientContactChangeDb{get;set;}
[SetterProperty]
public IBusRefTranslator BusRefTranslator{get;set;}
static ClientContactChangeMessageHandler()
{
Logger = LogManager.GetLogger(typeof (ClientContactChangeMessageHandler));
}
static ILog Logger;
public void Handle(ClientContactChangeMessage message)
{
//Some handling logic
}
public void Handle(ClientChangeMessage message)
{
throw new NotImplementedException();
}
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<ClientContactChangeMessage>(s => s.Id, m => m.Id);
ConfigureMapping<ClientChangeMessage>(s => s.Id, m => m.Id);
// Notice that we have no mappings for the OrderAuthorizationResponseMessage message. This is not needed since the HR
// endpoint will do a Bus.Reply and NServiceBus will then automatically correlate the reply back to
// the originating saga
}
}
public class ClientMessageHandler : BaseMessageHandler
{
}
public class BaseMessageHandler : Saga<MySagaData>
{
}
public class MySagaData : IContainSagaData
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
As can be seen from the example I now have to implement the handle for the CLientChangeMessage as well , now i have already defined a handler for my ClientChangeMessage ,do i have to handle it again over here because if further on in time the ClientChangeMessage does come i would expect it to be caught and processed by the ClientChangeMessageHandler nad not by this one.
I would like to store a message if and only if i don't find the local reference for the Client in my database . Looking at the examples for saga on the web i dont't see any particular place or condition where this would be handled. I am hoping i would be storing the message inside the ClientContactChange handle method.
Any help would be much appreciated,
Thanks
UPDATE:
It would seem that i did not understand properly how to implement NService Bus Saga. The mistake which i made here according to me was that I considered A Client Contact change to be a single entity i.e independent of the Client Change message. So therefore i think i ma wrong in implementing the Saga just for client contact change . Here is how I had to change my code:
public class ClientSaga : Saga<ClientSagaState>,
IAmStartedByMessages<ClientChangeMessage>,
IAmStartedByMessages<ClientContactChangeMessage>,
IHandleTimeout<ClientSagaState>
{
[SetterProperty]
public IClientContactChangeDb ClientContactChangeDb{get;set;}
[SetterProperty]
public IBusRefTranslator BusRefTranslator{get;set;}
public void Handle(ClientContactChangeMessage message)
{
//Some handling logic
//Check if client is not in database then store the state
this.ClientContactChange=message;
//if client is in the data base then
MarkAsComplete();
}
public void Handle(ClientChangeMessage message)
{
//Update or create the client depending on the situation
//check for dependencies
if(this.ClientContactChange !=null)
{
//Handle the contact change
}
}
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<ClientContactChangeMessage>(s => s.ClientRef, m => m.ClientRef);
ConfigureMapping<ClientChangeMessage>(s => s.ClienttnRef, m => m.Id);
// Notice that we have no mappings for the OrderAuthorizationResponseMessage message. This is not needed since the HR
// endpoint will do a Bus.Reply and NServiceBus will then automatically correlate the reply back to
// the originating saga
}
}
public class ClientSagaState: IContainSagaData
{
//i dont need these three fields
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
// the fields which i needed
public Guid ClientRef {gee; set;}
public ClientChangeMessage ClientChange {get;set;}
public ClientContactChange ClientContactChange {get;set;}
}
Since both handlers handle the same message type, both will be called. If you like you could specify the order in which they get called using ISpecifyMessageHandlerOrdering. Furthermore, you can short circuit this chain based on a condition which may solve the secondary issue.
If that does not work, you may want to consider versioning the message to support both scenarios in a graceful way.
Related
Little introduction: we have a complex entity and overgrown business logic related to it. With various fields that we can change and fields that updates from external project management software (PMS) like MS Project and some others.
The problem is that it's hard to centralize business logic for changing every fields cause that changes can offend other fields some fields are calculated but should be calculated only in several business scenarios. And different synchronization processes uses different business logic that depends on external data of specific PMS.
At this moment we have such ways to change the fields in our solution:
Constructor with parameters and private parameterless constructor
public class SomeEntity
{
public string SomeField;
private SomeEntity ()
{
}
public SomeEntity (string someField)
{
SomeField = someField;
}
}
Private set with public method to change field value
public class SomeEntity
{
public string SomeField {get; private set;}
public void SetSomeField(string newValue)
{
// there may be some checks
if (string.IsNullOrEmpty(newValue))
{
throw new Exception();
}
SomeField = newValue;
}
}
Event methods that perform operations and set some fields
public class SomeEntity
{
public string SomeField { get; private set; }
public string SomePublishedField { get; private set; }
public void PublishEntity(string publishValue)
{
SomeField = publishValue;
SomePublishedField = $"{publishValue} {DateTime.Now()}";
}
}
Public setters
public class SomeEntity
{
public string SomeField { get; set; }
}
Services that implements business logic:
public class SomeService : ISomeService
{
private DbContext _dbContext;
private ISomeApprovalsService _approvalsService;
public async Task UpdateFromMspAsync (MspSomeEntity mspEntity,
CancellationToken cancellationToken = default)
{
var entity = await _dbContext.SomeEntities
.Include (e => e.Process)
.SingleAsync (e => e.MspId == mspEntity.Id, cancellationToken);
switch mspEntity.Status:
case MspStatusEnum.Cancelled:
entity.Process.State = ProcessStateEnum.Rejected;
entity.Status = EntityStatusEnum.Stopped;
break;
case MspStatusEnum.Accepted:
_approvalsService.SendApprovals (entity.Process);
entity.Status = EntityStatusEnum.Finished;
break;
await _dbContext.SaveChangesAsync (cancellationToken);
}
}
State machine inside entity
public class SomeEntity
{
private StateMachine<TriggerEnum, StateEnum> _stateMachine;
public SomeEntity()
{
ConfigureStateMachine();
}
public string SomeField1 { get; set; }
public string SomeField2 { get; set; }
public string SomeField3 { get; set; }
private void ConfigureStateMachine()
{
_statusStateMachine.Configure(StateEnum.Processing)
.OnEntry(s=>SomeField1 = null)
.Permit(TriggerEnum.Approve, StateEnum.Approved);
_statusStateMachine.Configure(StateEnum.Approved)
.OnEntry(s=> SomeField1 = SomeField2 + SomeField3)
.Permit(TriggerEnum.Publish, StateEnum.Finished)
.Permit(TriggerEnum.Cancel, StateEnum.Canceled);
// etc
}
public void Trigger (TriggerEnum trigger) => _statusStateMachine.Fire(trigger);
}
State machine as service to prevent buisness logic leaks inside of entity.
var machine = _services.GetService<IStateMachine<SomeEntity, TriggerEnum>>();
var entity = await _dbContext.SomeEntities.FirstAsync();
IAttachedStateMachine<TriggerEnum> attachedMachine = machine.AttachToEntity(entity);
attachedMachine.Trigger(TriggerEnum.Publish);
It's wrong by architecture to have so many ways of changing values and we want to refactor this but to change approach, best practice must be chosen.
Please share your experience of resolving similar situation.
Update: found approach for DDD that called "aggregation root". It's looks good but only on paper (in theory) and works good with simple examples like "User, customer, shopping cart, order". On practice on every private setter you will create setter method (like in #2 of my examples). Also different methods for every system you work with. Not even talking about business logic inside database entity that violates SOLID's "single responsibility principle".
I am developing a Blazor app and in this app, I need to store the state of a List of user-selected Items.
when the user presses the 'Save Changes' button I would like to store the list in the state.
So far I have written the four mandatory classes that are written in the Fluxor doc:
ServiceState:
public record ServiceState
{
public List<ServiceModel> SelectedService { get; init; }
}
ServiceFeature
public override string GetName() => nameof(ServiceState);
protected override ServiceState GetInitialState()
{
return new ServiceState
{
SelectedService = new List<ServiceModel>()
};
}
SelectServiceAction:
public class SelectServiceAction
{
public List<ServiceModel> _serviceList;
public SelectServiceAction(List<ServiceModel> choosenServices)
{
_serviceList = choosenServices;
}
}
and SelectServiceReducer:
public class SelectServiceReducer
{
[ReducerMethod]
public static ServiceState OnSelectService(ServiceState state, SelectServiceAction action)
{
return state with
{
SelectedService = action._serviceList
};
}
}
I have tried many things and nothing seems to work the List stored in the state appears always empty
but the funny thing is that in the SelectServiceAction class:
public SelectServiceAction(List<ServiceModel> choosenServices)
{
_serviceList = choosenServices;
}
if I put a breakpoint in the last } _serviceList contains correctly all the items that were contained in the list I passed to the dispatcher. It seems like the problem is in the ServiceState itself,
Do you happen to know what am I doing wrong?
If you need me to show more code, I will post it
I thank you kindly in advance.
I found a way to do this. I don't know if this is the best way but here we are.
Your SelectServiceAction should have a ServiceModel in the constructor. I also changed the name of your method. I think its good to place the verb in the method name because you're likely to have a remove as well.
public class SelectServiceAddAction
{
public ServiceModel _service {get; set; }
public SelectServiceAddAction(ServiceModel service)
{
_service = service;
}
}
then in your reducer you call the method.
public static class SelectServiceReducer
{
[ReducerMethod]
public static ServiceState OnSelectService(ServiceState state, SelectServiceAddAction action)
{
var SelectedService = state.SelectedService;
SelectedService.Add(action._service);
return state with
{
SelectedService = SelectedService
};
}
}
Also consider changing "SelectedService" to a name that involves the state such as "CurrentSelectedServices" hope this helps!
Preface: This code is used within a windows desktop application, client / server application, where the server sends and receives messages to/from the client using SMessage based classes
I have the following interface
public interface IMessage
{
string ID { get; }
string R_ID { get; set; }
DateTime Send { get; }
}
Here is the concrete implementation of this interface:
[Serializable]
public class SMessage : IMessage
{
public string ID { get; set; }
public string R_ID { get; set; }
public DateTime Send{ get; set;}
public SMessage()
{
R_ID = "";
ID = Guid.NewGuid().ToString();
Send = DateTime.UtcNow;
}
public SMessage(SMessage msg)
{
ID = msg.ID;
Send = msg.UTCSend;
R_ID = msg.R_ID;
}
}
I have released software to the world using the above interface and now I need to add a piece of additional data to this interface "Where"
public interface IMessage
{
string ID { get; }
string R_ID { get; set; }
DateTime Send { get; }
string Where { get; }
}
My question : Will adding this piece of data break existing clients in the field?
If so, how I can I update the interface / concrete classes so existing clients don't break?
Thanks
Additional info:
The SMessage is the base class for other messages that are sent within the application:
public class InstallMessage : SMessage
{
}
public class ChangeState : SMessage
{
}
How can I keep from breaking existing clients?
So, if I do this:
public interface IMessage2 : IMessage
{
string Where { get; }
}
And this:
public class SMessage : IMessage2
{
// the correct implementation for IMessage2 is added and omitted here for brevity
}
So what I am unsure about is how do I handle the case where I don't know if the message is from IMessage2 or not? ( NOTE: this code is in the client and server applications )
EXISTING CODE IN THE FIELD:
public void ReceiveChange( ChangeState msg )
{
string x = msg.ID.ToString();
}
NEW CODE THAT WILL BE SENT OUT WITH NEXT VERSION:
public void ReceiveChange( ChangeState msg )
{
string x = msg.ID.ToString();
// do I need to do some converting to keep from breaking ?
IMessage2 iMsg = msg as IMessage2;
if( iMsg2 != null )
{
string y = iMsg2.Where;
}
}
Thanks
Your interface's consumers won't complain, but the implementations will.
If you want to avoid this, then create a new interface that extends from the old one:
public interface INewMessage : IMessage
{
string Where { get; set; }
}
If in an WebAPI scenario.
It will only break existing clients if you have a dependency upon the newly added fields in a method that accepts IMessage as a parameter.
public void ServiceMethod(IMessage message) {
if (message.Where == null)
throw new ArgumentException("message.Where is null");
}
you can add things to interfaces and as long as you have code to properly handle the missing information existing clients will be fine.
The proper way to handle this though is to 'version' your services and data contracts. I find namespace versioning the easiest to maintain. You would define a new namespace (say v2) and redefine everything that actually changes, methods, data contracts, etc. And then in your routing, route the v2 messages (http://acme.com/api/v2/messages) to the new namespace or if not specially routed (http://acme.com/api/messages) route it to the old namespace.
If in a directly referenced library.
Then yes - it will break existing clients. Unless your factory that produces concrete implementations can determine which the client wants. Something similar to the WebAPI routing - but for directly referenced libraries. But this is extremely difficult.
Yes, it will break the existing clients if they implmented their own classes that use IMessage that do not derive from SMessage. This is the reason why Microsoft has not updated interfaces in the .NET framework between versions to add new features. For example in .NET 4.5 DbDataReader got new async methods that returned tasks but they could not update IDataReader because that would have broken anyone who implemented IDataReader without deriving from DbDataReader.
If you don't want to break the code of people who created classes with IMessage but without using SMessage you must either create a new derived interface that has the additional field (For example this is what COM objects do, you will often see ISomeInterface, ISomeInterface2, ISomeInterface3 etc.) or not update the interface at all and only update concrete implementations that other people may have derived from.
First let's define 'UserContext' as being a number of properties required to execute the receiving message in the correct context of the user, so it is a bit more than just a string. In my case this also includes data on which application 'instance' the user was working.
As I see it there are 2 main options to provide a 'UserContext' for a message:
As a Header
As a base class for the message
When using a Header, I need to provide my own serialization, when using a base class, Rebus will solve the serialization for me.
So I spiked using a base class using a little sample program:
public class UserContext
{
public string Name { get; set; }
public int UserId { get; set; }
public Guid AppId { get; set; }
}
public class UserContextMessageBase
{
public UserContext UserContext { get; set; }
}
public class SimpleMessage : UserContextMessageBase
{
public string Data { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
using (var adapter = new BuiltinContainerAdapter())
using (var timer = new Timer())
{
//adapter.Register(typeof(UserContextHandler));
adapter.Register(typeof(SimpleMessageHandler));
var bus = Configure.With(adapter)
.Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
.MessageOwnership(d => d.FromRebusConfigurationSection())
//.SpecifyOrderOfHandlers(o => o.First<UserContextHandler>())
.CreateBus()
.Start();
timer.Elapsed += delegate
{
bus.Send(new Messages.SimpleMessage { Data = Guid.NewGuid().ToString() });
};
timer.Interval = 10000;
timer.Start();
Console.WriteLine("Press enter to quit");
Console.ReadLine();
}
}
}
internal class UserContextHandler : IHandleMessages<UserContextMessageBase>
{
protected UserContext _context;
public void Handle(UserContextMessageBase message)
{
var old = Console.ForegroundColor;
if (_context != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Context is already populated");
}
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("Processing UserContextMessageBase");
// create the correct Context to process the message
_context = message.UserContext;
Console.ForegroundColor = old;
}
}
internal class SimpleMessageHandler : **UserContextHandler**, IHandleMessages<SimpleMessage>
{
public void Handle(SimpleMessage message)
{
// allow to use the _context to process this message
Console.WriteLine("Received SimpleMessage {0}", message.Data);
}
}
But when I run the program, I see that the SimpleMessage is getting processed twice. Is this 'by design' or perhaps a bug?
On the other hand, I can uncomment the registration for the UserContextHandler, and not inherit the SimpleMessageHandler from the UserContextHandler, but then I would have to stuff the UserContext into the MessageContext, and use it as such from the SimpleMessageHandler.
In my opinion, both approaches are valid - personally, I'd lean towards using headers because they're less noisy, and because that's really what they're there for :) but, as you correctly state, that requires that you somehow take care of "serializing" the user context into one or more headers, deserializing it again upon receiving each message.
The header approach could be done pretty elegantly, though, in the MessageSent and MessageContextEstablished events for sending and receiving respectively, staying out of your message handlers, and then the user context could be made available in the message context.
The other approach with using a message base class is definitely valid too, and I can see that you're hit by the fact that the lookup for the incoming message will get a new handler instance for each lookup - therefore, the pipeline will contain two handler instances, and the message will then be dispatched "as much as possible" (i.e. once for each compatible type/supertype) to each handler instance, thus resulting in effectively handling the message twice.
In your case, I suggest you do as you hint at towards the end: Make the UserContextHandler a separate handler that you ensure gets to be first in the pipeline, thus allowing it to stash the user context in MessageContext.GetCurrent().Items for all subsequent handlers to extract.
I'd love to cook an example, though, showing a way to do exactly what you need, but by using headers (possibly in the form of simply a ;-separated list of key-value pairs, or something similar), but I'm afraid I cannot promise that such an example would be available within the next few days.
Let me know if it works out for you :)
Update: I've added a sample to Rebus' sample repo that demonstrates how an ambient user context can be picked up and passed around in a message header, including a few nifties around configuration and DI - it's called UserContextHeaders - check it out :)
Environment is Visual Studio 2012, ServiceStack, ASP.NET Web Application Project (followed https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice)
Looking through some of the classes in ServiceStack.Examples, I noticed that most of the services contain only one method. Either some override on Execute() or, if a REST service, some override of OnPost/Get/Put/Delete().
How should I approach making a full API set, if I have tens of functions I need implemented RegisterUser(), RemoveUser(), AddFriend(), RemoveFriend() ... One service per method?
public RegisterUserService : IService<User> { public object Execute(User> dto) { ... } }
public RemoveUserService : IService<User> { public object Execute(User> dto) { ... } }
public AddFriendService : IService<Friend> { public object Execute(Friend dto) { ... } }
public RemoveFriendService: IService<RequestDTO4> { public object Execute(Friend dto) { ... } }
I'm pretty lost on how to begin implementing a full API set. I've read the first and second wiki page on 'Creating your first webservice', which I've copied to make 1 service method. But now I want to make 10 or 40 service methods and I'm not sure how to do that.
I noticed that implementing from IRestService<T> allows you up to 4 methods instead of the one Execute() method, simply because each method corresponds to a different HTTP verb. So is there something like that I could write? Basically something like:
public MyService : IService/IRestService/ServiceBase?<User>
{
public object AddUser(User user) { }
public object RemoveUser(User user) { }
public object ModifyUser(User user) { }
}
Just looking for something that doesn't necessarily have to contain all methods in one service class, but as many as reasonably possible ... do I really have to create 1 service for each service method?
Note on pursuing a strictly RESTful architecture: I only read up a little on REST, but it seems like I'd have to strictly follow rules like: treat everything as a resource even if you have to re-design your models, no verbs in the URL names (/Friends, not /GetFriends because REST gives you OnGet(), OnPost(), OnPut(), and OnDelete() ... basically I'm interested in the easiest, quickest, and most painless way of implementing a a few dozen service methods. It's a personal project, so the requirements won't vary too much.
Thanks in advance for guiding me through this first step.
EDIT: Just saw this related question: How to send commands using ServiceStack?
Mythz said there's no "ServiceStack way" to design. The guy's question is pretty much like mine. I'm wondering how to stack a lot of service methods in a service.
EDIT 2: Just saw Need help on servicestack implementation, and Separate or combined ServiceStack services?.
I just tested the code below successfully with working routes:
[Route("/registerUser/setEmail/{Email}")]
[Route("/registerUser/setPassword/{Password}")]
[Route("/registerUser/setPhoneNumber/{PhoneNumber}")]
[Route("/lalal2395823")]
[Route("/test3234/test23423511")]
public class RegisterUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nickname { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
But what I'd like is for each [Route("path")] to go to a different method, instead of having them all parsed in Execute() and having to parse which string isn't null or empty.
My Solution
I decided to take Rickard's advice and make a proper REST API, because it seems simpler and cleaner in the end.
This is now my class using the new ServiceStack API (new as of 9/24/12):
using UserModel = Project.Model.Entities.User;
[Route("/User", "POST")]
[Route("/User/{FirstName}", "POST")]
[Route("/User/{FirstName}/{LastName}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}/{PhoneNumber}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}/{PhoneNumber}/{Email}", "POST")]
public class CreateUser : IReturn<UserModel>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nickname { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class CreateUserService : Service
{
public object Post(CreateUser request)
{
try
{
using (var session = FluentNHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var user = new UserModel()
{
FirstName = request.FirstName,
LastName = request.LastName,
Nickname = request.Nickname,
PhoneNumber = request.PhoneNumber,
Email = request.Email,
Password = request.Password,
};
session.SaveOrUpdate(user);
transaction.Commit();
return user;
}
}
}
catch
{
throw;
}
}
}
This is now a lot simpler with ServiceStack's new API Design released in (v3.9.15+).
#Rickard makes a lot of good points on how to re-structure your service so it's more REST-ful which is now easier to achieve with ServiceStack's new API which is now less restrictive and more flexible where the same service can handle multiple different Request DTOs and you're no longer restricted in the Response Type you can return.
Following the HTTP way you have to turn your way of thinking upside down. You need to think in terms of resources, i.e. users, friends, etc. Using HTTP you already have a finite set of methods, namely Get, Put, Post, and Delete.
Hence, the service API design could look like this:
RegisterUser() => POST /users
RemoveUser() => DELETE /users/{userid}
AddFriend() => POST /users/{userid}/friends
RemoveFriend() => DELETE /users/{userid}/friends/{friendid}
ModifyUser() => PUT /users/{userid}
etc.
To implement for example RemoveFriend in ServiceStack you could do like this:
public class UserFriendService : RestServiceBase<UserFriendRequest>
{
public override object OnPost(UserFriendRequest request)
{
// pseudo code
var user = GetUser(request.UserId);
var friend = GetUser(request.FriendId); // FriendId is a field in the HTTP body
user.Friends.Add(friend);
return HttpResult.Status201Created(user, ...);
}
//...
}
[Route("/users/{userId}/friends")]
public class UserFriendRequest
{
public string UserId { get; set; }
public string FriendId { get; set; }
}