I am in the process of making a web service and would like to apply domain patterns to it. I am having problems making my domain entities have more behavior. I would like to do something like this
public void DoSomethingApi()
{
CustomerRepository customerRepository = new CustomerRepository();
Customer customer = customerRepository.GetCustomer("myId");
customer.DoSomething();
}
to make my customer entity have more behavior I have tried the following:
public class Customer
{
public void DoSomething()
{
// how do I do this?
// I need a repository and a bunch of services todo work here
}
// using double dispatch
public void DoSomething1(DoSomethingService service)
{
service.DoSomething();
}
// using domain services directly
public void DoSomething2()
{
new DoSomethingService().DoSomething();
}
// using event broker and domain events
public void DoSomething3()
{
EventBroker.FireEvent<DoSomethingEvent>();
}
// using Actions
public Action DoSomethingAction4 { get; set; }
}
All methods have pros and cons, but I liked the use of domain events the most. However how do you return a value with domain events? how do you handle rollbacks if the method is in a transaction?
or maybe domain events is really just for notification (fire and forget)...
From how I understand and practice it, a domain event is something that already happened. (In our convention, the event names are always in the past tense). Publishing a domain event just "let's the world know" that something happened. Any event listeners then act accordingly independent of what caused the event. The event carries information of what happened It does not return anything.
As such, a domain event cannot be rolled back. A transaction inside a listener that gets triggered can be rolled back but not the event itself.
Edit: It is as you mentioned - fire and forget.
Related
So we have a scenario where we are creating credit cards. We have CreateCardConsumer that internally implements a strategy that decides which credit card provider API will be used (currently, we have two, let's call them, Provider1 and Provider2).
In case that credit card creation fails, we have the FailedToCreateCard event that gets published in CreateCardConsumer:
public class CreateCardConsumer : IConsumer<CreateCard>
{
public async Task Consume(ConsumeContext<CreateVirtualCard> context)
{
try
{
// Decide which provider to use
}
catch (Provider1Exception e)
{
}
catch (Provider2Exception e)
{
}
catch (Exception e)
{
await context.Publish<FailedToCreateCard>(new(context.Message.CardId));
}
}
}
The issue with this is that when card creation fails, we must inform multiple systems that creation failed (and there, we use the FailedToCreateCard event). We also need to send a notification to our support with error details (which are a different data structure for both providers).
It feels fishy to extend FailedToCreateCard event with the error data for both providers and listen in the consumer that sends an email to the support (in the future there can be more than 2 providers), but it also feels fishy that we do something like
catch (Provider1Exception e)
{
await context.Publish<FailedToCreateProvider1Card>(new(context.Message.CardId, e));
await context.Publish<FailedToCreateCard>(new(context.Message.CardId));
}
catch (Provider2Exception e)
{
await context.Publish<FailedToCreateProvider2Card>(new(context.Message.CardId, e));
await context.Publish<FailedToCreateCard>(new(context.Message.CardId));
}
And the third solution that comes to mind is that we publish FailedToCreateProvider1Card and FailedToCreateProvider2Card from within the service that makes an API call and publish FailedToCreateCard in the consumer.
Does any one of these solution makes sense or there is a fourth one that is a common practice in this scenario?
If you're using a broker like RabbitMQ, MassTransit supports polymorphic messaging. You can read more in the documentation, but by having two interfaces implemented by a single class (which would be published), you can produce a single event that would be routed via either message type.
I am attempting to implement support for an application that serves playlists of music content over chrome cast. In the current implementation the sender application sends each individual track, one at a time, to the receiver, which then plays the track and reports back status. This model does not work terribly well on iOS devices and so I would like to flip the model and make the receiver responsible for fetching new tracks and notifying the client when there is a new track so that they can update their UI.
Currently I have set up the receiver to call MediaManager.setMediaInformation when the new track is loaded and set the broadcast parameter to true. On Android I am using the following code to listen for new media and for updates on the status of existing media:
RemoteMediaPlayer remoteMediaPlayer = getRemoteMediaPlayer();
remoteMediaPlayer.setOnMetadataUpdatedListener(
new RemoteMediaPlayer.OnMetadataUpdatedListener() {
#Override
public void onMetadataUpdated() {
Log.d(LOG_TAG, "Metadata updated");
}
}
});
remoteMediaPlayer.setOnStatusUpdatedListener(
new RemoteMediaPlayer.OnStatusUpdatedListener() {
#Override
public void onStatusUpdated() {
Log.d(LOG_TAG, "Status update");
}
}
});
The OnMetadataUpdatedListener is called when the receiver loads its first track, but each additional track that is loaded only causes the OnStatusUpdatedListener to be called. I can certainly see the new metadata for the track in the OnStatusUpdatedListener once the track has started playing, but from the API documentation it sounds like OnMetadataUpdatedListener should be called when the metadata (and the track) has been updated.
Any suggestions on what I might be doing wrong here or further steps to debug the issue would be greatly appreciated.
Lets take a scenario where an Order is dispatched and optionally a mail can be sent to the customer depending on an attribute in the Order class. The functionality to send an email is in a service "EmailService".
My question is should the Order.Dispatch method call the EmailService to send the email depending on the attribute in the Order class or should the application layer after calling the Order.Dispatch method call the EmailService? Which is the correct way to do this in DDD?
Thank you.
NN
Domain events allow you to decouple concerns. As soon as an order is dispatched, it could raise a domain event informing interested subscribers. This allows you to make the decision to send an email somwewhere else, so that the order aggregate can remain pure. It often also helps to capture the language better; when an order is dispatched, send an email.
public class Order
{
public Order(string id)
{
Guard.ForEmpty(id, "id");
Id = id;
}
public string Id { get; private set; }
public void Dispatch()
{
DomainEvents.Raise(new OrderDispatchedEvent());
}
}
public class MailService : IHandle<OrderDispatchedEvents>
{
private readonly IMailSender _mailSender:
public MailService(IMailSender mailSender)
{
_mailSender = mailSender;
}
public void Handle(OrderDispatchedEvent #event)
{
_mailSender.Send(...);
}
}
I would keep that on the application service layer. The sending bit may be simple enough in the Order.Dispatch as you could pass in an instance of the service but how about first of all composing the e-mail? That is probably somewhat more tricky.
Placing it in the operation script in some application service layer task is one way. You could also respond to a domain event (OrderDispatched for instance) and then send. Another option (when using a service bus) is to publish the OrderDispatchedEvent and have you Order endpoint subscribe to that and then send a SendEMailCommand to the E-Mail endpoint.
But I would not try to handle the sending in the domain itself as it feels more like output generation as opposed to some business operation/calculation that the domain is typically involved with. It is a business requirement but just on another level in the same way reporting works. Although business-related, or process related, it does not necessarily belong in the domain.
Just my ZAR 0.02 :)
DDD is not a recipe so there's no correct way to do something.
If by Dispatch you mean that the Order is on the way to the customer (hint: perhaps more accurate semantics are needed here) then the Application layer which sets the Order status as Dispatched can also ask a NotificationService to notify the customer.
I believe that a Domain Event approach is the best though, so once the Order has been dispatched, the OrderDispatched event will be published and a notification service could subscribe to it and will notify the customer using the EmailService, SMSService etc
But the Order itself has nothing to do with this. Some other domain object decides when an Order should be dispatched, it sends a DispatchOrder command to a Domain service which will do the dispatching and then it will generate the OrderDispatched event. This means that your Order shouldn't have a Dispatch method as it's not the Order that does the dispatching. A simple Status property is enough.
I started to work with SignalR on Visual Studio 2012, so far I got the basic hang of it, I guided myself through this example (You can browse the code in the page). I decided I wanted to add a REST service to said example, so I added a basic service to it and it worked.
The next step I wanted to take was to add a communication between the service and SignalR, so according to what the example showed to me, I only needed to create a HubConnection through the url in my project (in this case, the example uses the url http:localhost:4200). You can check the WorkerRoleHubConfiguration class, it has a method that has the next line:
return RoleEnvironment.GetConfigurationSettingValue("GUI_URL");
Where GUI_URL is http:localhost:4200.
In my service class then I just added a method with the following:
var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
try
{
HubConnection _connection = new HubConnection(url);
IHubProxy _hub = _connection.CreateProxy("SiteMonitR");
_hub.Invoke("displayResult");
}
catch (Exception ex)
{
error = ex.ToString();
}
But that throws an exception, this one.
I don't undertand why I can get the url in the same way the example does, as I'm doing everything as it's done on the Server class.
The goal I'm trying to achieve is that when an endpoint is accesed and something changes in my system, SignalR notifies to the clients connected to it.
I hope anyone can help me understand what's wrong with my work.
EDIT
I'm adding my ServiceConfiguration.Local.cscfg, my ServiceConfiguration.Cloud.cscfg and ServiceDefinition.csdef files as reference here, I think the problem should be around there but to be honest I got no idea as to why this isn't working.
EDIT 2
I'm getting the following exception at this line var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
The exception is:
SEHExcetion occurred. External component has thrown an exception.
The URL is for a GUI - it has to be a web interface for signalr to negotiate the hub connection. In the example, the hub (server) sends updates to connections coming from the configured URL - again a web interface (html page).
The logic to communicate needs to reside in the Server class and be called from the worker role. For example, after making a call to your service in the worker role, then call server.DoSomething("message") to invoke a message to the server. THat code would look something like:
public Class Server
{ ...
public void DoSomething(string message)
{
_hub.Invoke("doSomething", message);
}
...
}
Then in Server.Run() add:
// whenever a DoSomething is called
_hub.On<string>("doSomething", (message) => _hub.Invoke("doSomething", message));
And in SiteMonitRNotificationHub
public class SiteMonitRNotificationHub : Hub
{
...
public void DoSomething(string address)
{
Clients.doingSomething(address);
}
...
}
Finally in the controller script in the web gui:
c.siteMonitorHub
...
.on('doingSomething', function (message) {
c.doSomething(message);
})
and...
this.doSomething= function (message) {
// do something in your web page with message
};
I'm still fairly new to DDD applications. I'm reading Eric Evan's "Domain Driven Design" and have read Employing the Domain Model Pattern by Domain Events Salvation by Udi Dahan...
One thing I can't make out though is how should information about the successful or unsuccesful completion of Domain Events be returned as feedback to the user (i.e. UI Layer)?
For example, we could have the following Application Layer code:
// Application Layer
public void SubmitOrder(OrderData data)
{
var customer = GetCustomer(data.CustomerId);
var shoppingCart = GetShoppingCart(data.CartId);
customer.Purchase(shoppingCart);
}
// Domain Model
public class Customer
{
public void Purchase(ShoppingCart cart)
{
// something done with the cart...
DomainEvents.Raise(new CustomerPurchaseCompleted() { Customer = this, ShoppingCart = cart });
}
}
Now let's say we have the following event handler that sends a confirmation email to the customer if the customer has an email address specified.
public class CustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email != null) {
// send email to args.Customer
}
else {
// report that no email will be sent...
}
}
}
My question is: How should I "bubble up" a feedback message to the UI layer saying that no email will be sent because the customer doesn't have an email set?
The options as I see them today are along the lines of:
Have the UI layer check if the Customer has an email and react accordingly with a message. This seems bad since the UI would be aware that an email is supposed to be sent, which is a application level information.
Throw a UserHasNoEmailException when no email is present and catch that information somewhere. That's really bad because exceptions should not be used to return information, plus it's not a fatal error and should not abort other handlers...
Have SubmitOrder() return some List<FeedbackMessage>. This would require changing the Purchase() and DomainEvents.Raise() methods to also return this list. This leads to the Domain Model knowing what the UI should of should not display...
Neither of these three options seems really good and practical. So how do DDD experts do it?
Thanks.
Another option you have is to implement another event handler which is specifically responsible for notifying the UI that a customer doesn't have an email address. So where CustomerPurchaseCompletedHandler doesn't send an email, this handler would notify the UI. This handler would be part of the UI layer. A good way to notify the UI would be to inject an event aggregator into this handler:
public class NotifyingCustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public IEventAggregator Events { get; set; }
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email == null) {
// notify UI
this.Events.GetEvent....
}
}
}
Overall, this is essentially approach 1. True, the UI layer is now aware that an email is to be sent, however the UI has to have that knowledge regardless because it needs to render a message stating that no email is to be sent. Display a message is a UI concern and by leaving the handler implementation as part of the UI layer you keep it as such. The problem with this approach is that you are checking whether the customer has an email twice. Additionally, the sending of an email is not directly tied to the UI notification.
Another option is to introduce another event to indicate that a purchase was completed for a customer that doesn't have an email. The UI could then subscribe to this event. The downside of this approach is that you are creating an event specifically for a UI requirement not to express domain knowledge.
Events should not report feedback. Events ARE feedback.
In this case the Email is a business requirement. So the customer.Purchase(shoppingCart); should really throw an exception if the email has not been specified.
But let's say that the actual email delivery fails. What I usually do is to create a domain model which I use for notifications. so I do this:
var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);
Which in turn would generate a NotificationCreated event which can be picked up by the UI.