Can domain event be raised in domain service? - c#

I'm wondering if domain event can be raised in domain service? I've got such a code written in C#. Of course it works, but is it correct from DDD point of view?
First example is related to user deletion. In my system Account has multiple users. After user removal AccountUserRemovedDomainEvent is raised. Then subscriber in infrastructure layer handles audit log management. It adds proper log describing this action.
public void RemoveUser(AccountUserEntity user, AccountEntity account)
{
AccountUserRepository.Delete(user);
DomainEvents.Raise(new AccountUserRemovedDomainEvent(user));
}
That's the second example. In that case except creating audit log subscriber in infrastructure layer is sending mail with activation link to the user.
public void SaveAccountUser(AccountUserBasicInformation information, AccountEntity account)
{
var user = Mapper.Map<AccountUserEntity>(information);
account.Users.Add(user);
user.Account = account;
DomainEvents.Raise(new AccountUserAddedDomainEvent(user));
}

A domain event would typically be the result of an action/command being applied to a domain object. As such it probably wouldn't be something that a domain service is concerned with. You may need to have some technical system events/messages but those are a bit different and wouldn't be in domain services.
I like to have a method return the domain event(s) which facilitates testing, instead of a singleton that raises the events. If you end up with a domain service that interacts with multiple domain objects you may opt for returning the events but chances are, when using event sourcing anyway, that you'd need to the event streams that the events have to be added. Depending on your implementation the aggregate can keep track of new events also. In both scenarios you have a container for the event(s) so no need to return/raise them anyway.

Related

Context property of SignalR Hub does not give me Http Context by using GetHttpContext method

In my application I plan to use SignalR in order for the backend code to send messages to the logged in user based on the conditions that arise on the server.
In particular I want the SignalR to call methods on the JS client whenever something happens on the backend. This could be periodic calculations happening on the backend that suddenly pass a threshold and I need to invoke something on the JS client for a particular User. The particular User is the key element here. Only the User that should know about this.
I'm assuming this should be very simple with SignalR but I have some problem understanding the way to implement this. My solution is as follow;
Each time a user logs in, I create a SignalR Group and add that user to that group.
Each time a user logs out, I remove them from the Group. (I don't know if I can also delete the Group itself)
Now each time something happens on the back end, I use SignalR to push information to a particular User that needs to know about that event by calling a JS client method and sending to the group with the name equal to the Name Identifier of the user of interest.
So to apply this solution, I need to get the information about the User that just logged in inside the C# Hub in order to create the group and join him.
Now my problem is, how to access the information that I need from the User that logs in to the application in the C# Hub . I'm interested in the User Name Identifier of course. I have been thinking that the Context Property in the Hub should give me the information that I need (This is my understanding of the MS Docs) but I cannot make it to work. Please study below code.
// As soon as a User logs in, below method fires. I try to get the information
// in here but no success
public override async Task OnConnectedAsync()
{
var CID = Context.ConnectionId; // this gives a unique connection ID
var user = Context.User; // This returns nothing
var userID = Context.UserIdentifier; // This returns nothing
var httpContextObject = Context.GetHttpContext(); // This returns nothing
await base.OnConnectedAsync();
}
When I call other methods in the C# Hub from JS the method is fired and
information is passed but I still have no access to the information the
Context Property should provide.
Please help me first by confirming or correcting my overall approach and if there are well known best practices available. Secondly please let me know how can I get information that the Context Property provides in the Hub and generally where this information is available and how to access and use them.
Many thanks in advance.
'User' is a claims principle (normally stored in the asp cookie), to get the User form your Identity database use:
var user = await _userManager.GetUserAsync(User);
For future reference, your question is very long, you will get more help if you keep questions brief and to the point.
I've solved my problem by using Authentication with SignalR. I don't need to add a user to any groups to push massages to them. In the Startup class I add Authentication above SignalR service and then the user object is passed to the Hub in the Context property. I can also push to any user by injecting the IHubContext to any class constructor I need.

Authorization in a layered application

I am working on a pretty simple project that is mostly made up of getters and searches and access to certain data is limited depending on the user. I want to use this opportunity to do some best practices when it comes to security, authorization in this case.
The application is activated once at which time a token is generated and used for future requests.
My application has a web api for the endpoint which sits on top of a set of services which sits on top a set of repo's which sits on top of a sql server db. All the controllers do is forward the request down to the service layer.
Here is an example controller:
[ApiAuthorize]
[RoutePrefix("api/Catalogue")]
public class CatalogueController : ApiController
{
private ICatalogueService _catalogueService;
public CatalogueController(ICatalogueService catalogueService)
{
_catalogueService = catalogueService;
}
[HttpGet]
[Route("GetCatalogues")]
public IHttpActionResult GetCatalogues(string branchEan)
{
var catalogues = _catalogueService.GetCatalogues(new GetCataloguesRequest()
{
BranchEan = branchEan
});
return Ok(catalogues);
}
}
My custom authorization attribute checks the token and if valid pulls the user details out from the token and creates a generic principle which is then available in my controllers.
To me the web api is just a way to expose my business\service layer and authorization should be done lower down in my service layer but I can't think of a clean way to get that information down to that layer. In the above example, the service layer will need to check if the user (from the token) has access to that particular branch which means the service layer will need to know who is making the request. The two solutions I can think of is:
1) I am using a request\response pattern for my service layer so I could create an abstract base class called 'Request' as an example which could store all the user details and each request object to the service layer could inherit from this therefore providing user details to my service layer.
public abstract class Request
{
public Request(string username)
{
this.Username = username;
}
public string Username { get; private set; }
}
public class GetCataloguesRequest : Request
{
public GetCataloguesRequest(string username) : base(username)
{
}
}
2) To define an interface, for example ISecurity, which is then injected into my service layer but this would require the layers above my service layer to implement the interface.
I read here - Placing authorization into the service layer rather than Web API layer
- to create an authorization layer but I am not sure of the technical implementation of this.
Any ideas?
What you are looking for is fine-grained, externalized authorization:
fine-grained: you want to create authorization policies that take into account multiple parameters or attributes and possibly relationships between the client (the requestor) and the targeted entity e.g. a listing in your case.
externalized: you want to decouple the business logic from the authorization logic. In your question you complain about how complex the code and the SQL statements are becoming. This is a direct consequence of not clearly separating business logic from authorization logic.
There is a model called attribute-based access control (ABAC) that defines an approach to fine-grained externalized authorization. NIST, the National Institute of Standards and Technology, has produced a report on ABAC which you can read online.
OASIS, the organization for the advancement of structured information standards, has defined a standard called XACML (eXtensible Access Control Markup Language) to implement ABAC.
XACML brings you:
an architecture as illustrated below
The policy enforcement point (PEP) intercepts your API calls. It protects your API, inspects the messages and sends an authorization request to the policy decision point (PDP).
The policy decision point (PDP) evaluates incoming authorization requests from the PEP against a set of authorization policies written in XACML. The PDP eventually reaches a Permit or Deny decision. To reach decisions it may need to look up additional attribute values from databases, web services, LDAP, or files. These are called policy information points in the architecture.
a policy language: the XACML policy language is attribute-based which means it uses attributes to define what can be allowed and what is not. For instance, you could define rules such as:
a real estate agent can see all the listings if and only if the listing location == the agent location
a real estate agent can edit a listing if and only if he/she owns the listing
a real estate agent can close a listing if and only if the listing's item is sold and if and only if the agent is the person that sold the item.
a request/response scheme: XACML also defines a way to query the PDP and to get responses back. A PDP can be queried either via single questions or via multiple questions in a single request e.g.:
Can Alice view listing 123? Yes, permit.
Can Alice view, edit, or delete listing 123? Permit; Deny; Deny.
With a XACML-based approach, you get to maintain your business logic and your API separate from the authorization logic. This has several benefits:
you can always reimplement the API and keep the same authorization model
you can easily expand your API without having to rewrite the authorization
you can change your authorization logic independently of your code
you can audit your authorization logic more easily
your authorization logic is technology-neutral. It works for REST APIs, web services, databases, and more
I recommend you check out the following resources:
the OASIS XACML website
the ALFA plugin for Eclipse - a free tool to write XACML policies.
The XACML developer community
There are both vendor and open-source implementations of XACML:
Axiomatics is a vendor solution that provides both .NET and Java XACML implementations
SunXACML is a long-standing open source Java XACML implementation
HTH,
David.

ServiceStack ungraceful client disconnect

In a ServiceStack app is there any way to determine that the client has ungracefully disconnected? I would like to get a list of users that are online, but
var sessionPattern = IdUtils.CreateUrn<IAuthSession>("");
var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList();
var activeSessions = Cache.GetAll<IAuthSession>(sessionKeys).Values;
will only get valid sessions, that are valid until they expire or client logouts (which doesn't reflect whether he is onlline or not).
If you're referring to Server Events subscriptions, their lifetimes are completely unrelated to User Sessions. A Server Event subscription just represents a long-lived HTTP connection to the Server Events /event-stream which may or may not be from an Authenticated User.
The way to find out active connected users is to call /event-subscribers.
Inside ServiceStack, all information available on Server Event subscriptions is accessible through the IServerEvents dependency, e.g. To find out all active subscriptions for a user you can call GetSubscriptionInfosByUserId()

Understanding srp principle in solid with nlayers

I have a web application with the following layers:
View
Business
Entities
Repository
I want to send an email to a User when he or she is registered.
I have the class User, in the Entities layer, and the classes UserBussines and MailBusiness in the Business layer.
The problem is that I don't know where is correct to send the email to the user.
I see some options
1) In the controller:
UserBusiness.AddUser();
MailBusiness.SendEmail();
2) In the business
UserBusiness.AddUserAndSendEmail()
{
AddUser();
MailBusiness.SendEmail();
}
In the two options I think that I'm not fulfilling the SRP in the SOLID principle, because I'm giving two responsibilities in one method.
I'm not understanding the principle? Or am I doing something wrong?
You have user registration scenario:
Given not registered user
When user registers
Then user becomes registered
And greeting mail is sent
This scenario should exist in your business logic layer, because:
It is scenario of your business domain
It should exist whether you use web application, desktop application, or mobile application.
So, you should have some application service (e.g. UserService) which will act as coordinator for user repository and email service:
public void RegisterUser(User user)
{
// possibly you should also check that user is not registered yet
_userRepository.Add(user);
_emailService.SendGreeting(user);
}

SignalR: How to stop creating new connection on page reload

Hi i am developing a chat application along with some other pages in my application. once i login i am maintaining the session of the user. My main intention is that user should get notification whenever another user connects to server.
The problem that i am facing is whenever i navigate to some other page in my application the connection is lost. How to stop this behaviour and continue the connection until user logs out.
I am using SignalR 2.0 in ASP.NET MVC4 project, any help??
Each connection only has a lifecycle for the duration of the time the user spends on a given page. When they navigate to another page, a new connection is established. Also, if a user has more than one tab or browser window open, they will have multiple connection Ids. I don't think you want to try to persist the connection Id beyond it's intended lifecycle.
In a similar scenario that I work on, we store the connectionIds OnConnect and delete them OnDisconnect. When a message needs to be sent to a given user, we send it to all of their connectionIds. This ensures that the message will be delivered to all tabs/windows.
EDIT 1 the following is in response to #Saurabh's comments:
Consider what the scope of the Hub is, and that of your other classes and the client. The Hub is there to facilitate communications between the browser and the server. While it's possible to do a lot of work within the hub, I think it's best to move most of the scope outside of communictions to other places.
The client knows that it just reloaded a page, so it's a good candidate for making the decision that this is a reconnect event.
_chatHub.server.reJoinRooms();
Then the Hub can query the user's rooms, by UserId, rather than ConnectionId.
public Task ReJoinRooms()
{
// get the user's rooms from your repository
// optionally get the user's connectionIds from your repository
// Clients.Caller.onJoinRooms(rooms);
// or Clients.Clients(_connectionIds).onJoinRooms(rooms);
}
Then the client can decide whether or not to take action:
$chatModule.client.onJoinRooms = function (rooms) {
for (var i in rooms) {
var _room = rooms[i];
// if I'm not already in this room, add it to my rooms
console.log('joining room', _room)
}
}
You could skin this many different ways. The client could own the scope of remembering rooms, instead of a server-side repository, too.
EDIT 2
If the number of groups/rooms that a user belongs to is ever-increasing, the above example may not scale up very well.
In that case, each user could join personal feed(s) instead (i.e. join a feed named for the user's GUID). We would keep track of each user that is affiliated with a group. When a message is sent to that group, we would iterate over those user's and publish a message to each feed.

Categories