Validation and synchronous commands in CQRS - c#

I like the idea of trying CQRS without event sourcing.
But I'm not sure how to tackle the fact that I need to give user an instant feedback.
This is how my current signup (simplified to understand)
I use Dapper for reads and nHibernate for writes.
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// use service layer to validate against database and create user
var registermodel = _userService.create_user_account(model.username, model.email, model.password);
// service returns and object with several states
if (registermodel.Status == UserRegistrationStatus.Ok)
{
// user registered ok, display thank you or whatever
}
if (registermodel.Status == UserRegistrationStatus.DuplicatedUsername)
{
// duplicated username found, back to form and show errors
}
if (registermodel.Status == UserRegistrationStatus.DuplicatedEmail)
{
// duplicated email found, back to form and show errors
}
// get back to form and show errors
}
Which of the appraoches would be the most CQRS friendly?
Method 1
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// validate duplicated email
bool is_email_duplicated = _read.user_email_exists(model.email);
// duplicated email found, back to form and show errors
// validate duplicated username
bool is_username_duplicated = _read.user_username_exists(model.username);
// duplicated username found, back to form and show errors
// assume all is perfect and dispatch
_commandDispatcher.Dispatch(new CreateUserCommand(model.username, model.email, model.password));
}
What if I need to do the same validation somewhere else in the system (I would have duplicated code)?
I thought about creating ValidationService.
What if command "explodes" for some reason and user will get false feedback?
Method 2
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// dispatch and validate inside the handler, abort execution if validation failed
var command = new CreateUserCommand(model.username, model.email, model.password)
// attached common feedback object to the command and deal with errors
if(command.status == UserRegistrationStatus.DuplicatedUsername)
{
// get back to form and show errors
}
}
Basically inside the handler I cheat and validate (adding extra methods to nHibernate repo).
Method 3
Similar to the first approach, but encapsulating validation and dispatch within UserService
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
var feedback = _userService.create_user(model.username, model.email, model.password);
// check for status and return feedback to the user
}
userservice.cs
public Feedback create_user(string username, string email, string password)
{
// validate duplicated email
bool is_email_duplicated = _read.user_email_exists(email);
// duplicated email found, back to form and show errors
// validate duplicated username
bool is_username_duplicated = _read.user_username_exists(username);
// duplicated username found, back to form and show errors
// dispatch command
_commandDispatcher.Dispatch(new CreateUserCommand(username, email, password));
}
I like this approach but I feel it will become a Baklava code.

Generally when using CQRS, you want to use an optimistic approach.
The idea is to validate your input (may it be simple validation against a string format or the uniqueness of an email) before to issue the command.
Obviously, you will double check your data when actually building your Command to make sure your Command is in a valid and safe state (the same applies to every other objects).
Based on this, you can assume your Command is going to dispatch properly and use an optimistic approach to give a positive feedback to your user.
If your CommandHandler fails to handle your Command it is likely to throw an Exception you can catch and notify your user accordingly.
Take the Messenger / Facebook example, when you type and send, the UI let you think everything is going well and your message has been sent, though, if something happens, your UI will be rolled-back.

Like you have seen, there are multiple possible approaches to dealing with the dispatch of a command. Sometimes you will see people use a strict adherence to returning a void from the command handler, but there is also the approach of an ACK/NACK (Acknowledged / Not Acknowledged) response.
The way that I have done this, is that the Dispatch() method of my command handler implementations will always return one of two possible statuses, being either an ACK or a NACK. This tells me whether or not the command that I attempted to dispatch was deemed to be in a state that it could be applied to the system. However, as opposed to a simple enumeration for ACK/NACK, every command is capable of returning an Acknowledgement class. That class contains a state (the ACK/NACK), along with one or more Command Failures. This way, if I have an ACK, I know that the command was received, and I can assume that it will be processed. On the other hand, if I get back a NACK, I have a failure that I can then format and present to the user. At no time, though, am I returning any information related to the post-dispatch state. The failures that I report (and there can be multiple failures for the same command) are entirely based on the data in the command and not related to it being applied to the system.
This all most closely relates to your third example. Where the above approach varies would mainly be that encapsulating the failures and status will allow you to present/track all issues with a command, as opposed to the first failure.
Here are the simple classes/enumeration that I use to accomplish this.
Acknowledgement
namespace Commands
{
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Provides an ACK/NACK for an issued <see cref="Command" />. Can represent one of two states,
/// being either Acknowledged or Not Acknowledged, along with the ability to track unhandled faults.
/// </summary>
/// <remarks>
/// ACK/NACK implies a synchronous command execution. Asynchronous commands, while more rarely used,
/// should represent the concept of command acknowledgement through events.
/// </remarks>
public sealed class Acknowledgement
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <remarks>
/// This is representative of an <see cref="AcknowledgementState.Acknowledged" /> state, with
/// no command failures nor faults.
/// </remarks>
public Acknowledgement()
{
this.State = AcknowledgementState.Acknowledged;
this.CommandFailures = new List<CommandValidationFailure>();
}
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <param name="failures">The command validation failures that led to NACK.</param>
/// <remarks>
/// This is representative of a <see cref="AcknowledgementState.NotAcknowledged" /> state, with
/// at least one command validation failure and no fault.
/// </remarks>
public Acknowledgement(IEnumerable<CommandValidationFailure> failures)
{
this.State = AcknowledgementState.NotAcknowledged;
this.CommandFailures = failures;
}
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <param name="fault">The fault that led to the NACK.</param>
/// <remarks>
/// This is representative of a <see cref="AcknowledgementState.NotAcknowledged" /> state, with
/// a fault and no command validation failures.
/// </remarks>
public Acknowledgement(Exception fault)
{
this.State = AcknowledgementState.NotAcknowledged;
this.Fault = fault;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the command failures that led to a NACK, if any.
/// </summary>
/// <value>
/// The command failures, if present.
/// </value>
public IEnumerable<CommandValidationFailure> CommandFailures { get; }
/// <summary>
/// Gets the fault that led to a NACK, if present.
/// </summary>
/// <value>
/// The fault.
/// </value>
public Exception Fault { get; }
/// <summary>
/// Gets a value indicating whether this <see cref="Acknowledgement" /> is backed by a fault.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reflective of a fault; otherwise, <c>false</c>.
/// </value>
public bool IsFaulted => this.Fault != null;
/// <summary>
/// Gets a value indicating whether this <see cref="Acknowledgement" /> is backed by command validation failures.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reflective of command failures; otherwise, <c>false</c>.
/// </value>
public bool IsInvalid => this.CommandFailures != null && this.CommandFailures.Any();
/// <summary>
/// Gets the state of this instance, in terms of an ACK or NACK.
/// </summary>
/// <value>
/// The state representation.
/// </value>
public AcknowledgementState State { get; }
#endregion
}
}
AcknowledgementState
namespace Commands
{
/// <summary>
/// Provides a simple expression of acknowledgement state (ACK/NACK).
/// </summary>
public enum AcknowledgementState
{
/// <summary>
/// Indicates an ACK that contains no command failures nor a fault.
/// </summary>
Acknowledged,
/// <summary>
/// Indicates a NACK that contains either command failures or a fault.
/// </summary>
NotAcknowledged
}
}
CommandValidationFailure
namespace Commands
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
/// <summary>
/// Thrown when on or more violations are found during the attempted execution of a command.
/// </summary>
/// <remarks>
/// In general, this exception is thrown as a guard against non-validation of a command ahead
/// of application. The most feasible scenario is a command handler which attempts to skip
/// validation, prior to execution.
/// </remarks>
[Serializable]
public class CommandValidationException : Exception
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
public CommandValidationException(List<DomainValidationFailure> violations)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
/// <param name="message">The message to associate with the exception.</param>
public CommandValidationException(List<DomainValidationFailure> violations, string message) : base(message)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
/// <param name="message">The message to associate with the exception.</param>
/// <param name="innerException">The inner exception to associate with this exception.</param>
public CommandValidationException(List<DomainValidationFailure> violations, string message, Exception innerException) : base(message, innerException)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
public CommandValidationException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the violations associated to this exception.
/// </summary>
/// <value>
/// The violations associated with this exception.
/// </value>
public List<DomainValidationFailure> Violations { get; }
#endregion
}
}

Related

How to display parameter in Web API help page for request and response body

I want to show request and response body as parameter not as raw data .
For that I have followed Generate Description Fields for Body Parameters answer but not get success , still showing
/// <summary>
/// Gets some very important data from the server.
/// </summary>
/// <param name="reqData">A Test Model</param>
[HttpPost]
public AccountService.GetAccountList_ResponseData GetAccountList([FromBody] AccountService.GetAccountList_ReqestData reqData)
{
}
//--my modal
public class GetAccountList_ReqestData
{
/// <summary>
/// StartDate
/// </summary>
/// <param name="StartDate">Describe parameter.</param>
public string StartDate { get; set; }
}
//---Also enabled
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/WebApi.xml")));
You have to add XmlDocs to your class GetAccountList_RequestData
/// <summary>
/// My requestData model
/// </summary>
/// <param name="reqData">The description you want </param>
public class GetAccountList_ReqestData
{
/// <summary>
/// StartDate
/// </summary>
/// <param name="StartDate">Describe parameter.</param>
public string StartDate { get; set; }
}
You followed the steps correctly, however the person asking in the other thread was displaying a property. You on the other hand are asking for an object, which is your class. Therefor the xmldocs of the class will be used to generate the descriptions.

Swagger italicizing quotes

Following remarks in the XML comments section in my code show up in Swagger -
/// <remarks>
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
///</remarks>
I am noticing that the last value (in this case Test) always has italicized quotations (Red arrow). Does anyone know how to change it to be regular quotes? For example, like they are for 1a (Blue arrow).
Add a remarks element to the Create action method documentation. It supplements information specified in the summary element and provides a more robust Swagger UI. The remarks element content can consist of text, JSON, or XML.
So, in order to fix the remarks and generate the Swagger documentation in a proper way, you must add a text after open the remarks tag, add a break line, and then add an example of request.
Another important detail is the indentation, you must apply a proper code indentation.
Please, find below your current scenario, a fix for your problem, and 2 examples.
Before - Wrong (your scenario)
/// <remarks>
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
After - Correct
/// <remarks>
/// [Description]:
///
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
///</remarks>
Example 01:
/// <summary>
/// Creates a Item From Query (Default)
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /api/Items/CreateViaQuery
/// {
/// "code": "0001",
/// "description": "Item1"
/// }
///
/// </remarks>
/// <param cref="CreateItemViewModel" name="createItemViewModel">Create Item View Model</param>
/// <returns>A newly created Item</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost("CreateViaQuery")]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public ActionResult<CreateItemViewModel> CreateViaQuery(CreateItemViewModel createItemViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Created("", createItemViewModel);
}
Example 02:
/// <summary>
/// Creates a Item From Body
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /api/Items/CreateViaBody
/// {
/// "code": "0001",
/// "description": "Item1"
/// }
///
/// </remarks>
/// <param cref="CreateItemViewModel" name="createItemViewModel">Create Item View Model</param>
/// <returns>A newly created Item</returns>
/// <response code="201" cref="CreateItemViewModel">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost("CreateViaBody")]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public ActionResult<CreateItemViewModel> CreateViaBody([FromBody]CreateItemViewModel createItemViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Created("", createItemViewModel);
}
For more info, please take a look the following article:
Get started with Swashbuckle and ASP.NET Core
I hope this can help you.

Parameter dont have value in webapi

I am trying to call a service through swagger, by passing a parameter in XML format.
Method is hitting, but the passed parameter is blank
Means "xlff" is blank. Do you have clue what wrong i am doing
/// <summary>
/// Get or insert blog comments which is approved based on blogs
/// </summary>
/// <remarks> Get or insert blog comments which is approved based on blogs</remarks>
/// <param name="xlf">The comment.</param>
/// <response code="200">Get approved blog comments</response>
/// <response code="404">Not found</response>
/// <returns>IHttpActionResult</returns>
[Route("api/smartling/ProcessSmartlingTranslation")]
[VersionedRoute("", 1)]
[ResponseType(typeof(HttpResponseMessage))]
[HttpPost]
public IHttpActionResult ProcessSmartlingTranslation([FromBody]xliff xlff)
{
return Content(HttpStatusCode.BadRequest, "Any object");
}
/// <summary>
/// XliffModel created
/// </summary>
public class xliff
{
/// <summary>
/// file getter setter method
/// </summary>
public string file { get; set; }
/// <summary>
/// body getter setter method
/// </summary>
public string body { get; set; }
}
Your parameter content type is application/json, but you're sending xml. You should change the content type to application/xml.

NullReference exception when using List.Add<t>, would like to understand it [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I have a settings class that looks like the following:
/// <summary>
/// Class for pipeline settings
/// </summary>
public class PipelineSettings
{
/// <summary>
/// List of jobs to process
/// </summary>
[JsonProperty("jobs")]
public List<PipelineJob> Jobs;
// todo: make private and create FetchCredentials(id)
/// <summary>
/// List of credentials information cataloged by id
/// </summary>
[JsonProperty("credentials")]
public List<PipelineCredentials> Credentials;
}
And a credentials class that looks like the following:
/// <summary>
/// Class to hold credentials for pipeline jobs
/// </summary>
public class PipelineCredentials
{
/// <summary>
/// The id for the current credential to be used when referring to it within
/// other areas of json settings files
/// </summary>
[JsonProperty("id")]
public int Id;
/// <summary>
/// Username or login string for the current system
/// </summary>
[JsonProperty("username")]
public string Username;
// refine: AES auto encrypt?
/// <summary>
/// The password for the active authentication. If not encrypted then it
/// will be automatically converted into an AES encrypted string
/// </summary>
[JsonProperty("password")]
public string Password;
[JsonProperty("path")]
public string UNCPath;
}
I've built the following to try to add a new credential to my list:
var settings = new PipelineSettings();
// Build credentials for storage
var credentials = new PipelineCredentials();
credentials.Id = 1;
credentials.Username = "testUsername";
credentials.Password = "test_password";
credentials.UNCPath = null;
// Add credentials to the current settings class
settings.Credentials.Add(credentials);
var json = new JsonSerializeHelper();
Console.Write(json.Serialize(settings));
Console.ReadKey();
And when I do, I'm receiving a null reference exception on the following line:
settings.Credentials.Add(credentials);
I don't know what I don't know - how should I be adding new items into a list if they're prebuilt?
It looks like you need to instantiate the Credentials list.
settings.Credentials = new List<PipelineCredentials>
somewhere in the code. Or, to keep things tidy, you could do this in the constructor:
/// <summary>
/// Class for pipeline settings
/// </summary>
public class PipelineSettings
{
public PipelineSettings()
{
this.Credentials = new List<PipelineCredentials>();
}
/// <summary>
/// List of jobs to process
/// </summary>
[JsonProperty("jobs")]
public List<PipelineJob> Jobs;
// todo: make private and create FetchCredentials(id)
/// <summary>
/// List of credentials information cataloged by id
/// </summary>
[JsonProperty("credentials")]
public List<PipelineCredentials> Credentials;
}
That way, whenever a new PipelineSettings class is instantiated, it will automatically create a PipelineCredentials list.
Your Credentials list is not initialized, you could do that in the constructor:
public class PipelineSettings
{
/// <summary>
/// List of jobs to process
/// </summary>
[JsonProperty("jobs")]
public List<PipelineJob> Jobs;
// todo: make private and create FetchCredentials(id)
/// <summary>
/// List of credentials information cataloged by id
/// </summary>
[JsonProperty("credentials")]
public List<PipelineCredentials> Credentials;
public PipelineSettings()
{
Credentials = new List<PipelineCredentials>();
}
}

Loading large amount of data in session after logging in

I have some data I need to store somewhere after a user logs in, what I need are:
1. A list of customers
2. US States list
for now that's all. Now Customer's list can continue to grow constantly and even after it has been loaded, obviously US States don't.
Currently what I do in my login.aspx page after the user logs in and everything is validated then I go to my SQL database and load all customers and US states into a Session variable. Right now this works although it does take a little bit of time but since there's only about 3 users at any time testing the site it doesn't affect. But as I understand this could be a problem when the company of about 50+ users start using it or even customers aswell.. So what would be the best way to work this and why? Thanks in advance.
ps. if this is not a valid question, please let me know and I'll take it down, I just didn't know where to ask this and get some useful feedback.
Andres,
Is it possible to (instead of using session) to cache the data. This can be done in multiple ways through various caching techniques (IE System.Web.Caching, MemoryCahce).
As your users grow \ shrink you can modify the DB and the cached instance at the same time. When the user requests the list of users (states) the cached list is evaluated. If the cached list isnt set then you re-build the cache list.
You could do something like. (Basic example)
public class UserCache : IEnumerable<User>
{
/// <summary>
/// const cache string
/// </summary>
const string userCacheString = "_userCacheList";
/// <summary>
/// current list of users
/// </summary>
public static UserCache Current
{
get
{
if (HttpContext.Current == null)
throw new Exception("NO CONTEXT");
var userList = HttpContext.Current.Cache[userCacheString] as UserCache;
if (userList == null)
{
userList = new UserCache();
HttpContext.Current.Cache[userCacheString] = new UserCache();
}
return userList;
}
}
/// <summary>
/// default constructor
/// </summary>
public UserCache()
{
}
/// <summary>
/// the list of users
/// </summary>
List<User> users;
/// <summary>
/// adds a user
/// </summary>
/// <param name="user"></param>
public void Add(User user)
{
if (this.Contains(user))
return;
this.users.Add(user);
}
/// <summary>
/// removes a user
/// </summary>
/// <param name="user"></param>
public void Remove(User user)
{
if (this.Contains(user))
return;
this.users.Remove(user);
}
/// <summary>
/// clears a user
/// </summary>
public void Clear()
{
this.users = null;
}
/// <summary>
/// fills the users from the database
/// </summary>
void fillUsers()
{
this.users = new List<User>();
//TODO: Get from DB
}
/// <summary>
/// gets the enumerator
/// </summary>
/// <returns></returns>
public IEnumerator<User> GetEnumerator()
{
if (this.users == null)
fillUsers();
foreach (var user in users)
yield return user;
}
/// <summary>
/// gets the enumerator
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class User
{
public string UserName { get; set; }
public Guid UserID { get; set; }
public string Email { get; set; }
}
From here you user management (where you add \ remove users) can call the UserCache to modify its collection accordinly. Such as (psudo code)
public class UserManager
{
public void Register(string userName, string email)
{
//TODO: Register in DB.
UserCache.Current.Add(new User
{
UserID = Guid.NewGuid(),
Email = email,
UserName = userName
});
}
}
From here you can always call UserCache.Current to get the current user list.
Just a thought.
EDIT: Response to Simon Halsey comment.
In the example I did inherit from the IEnumerable<> interface and not the List<> interface. This was a personal preference and to support "how" the class was defined. Now before I explain, this is not the only way but just a conceptual way of achieving the result.
In the example the method Clear() clears the inner list by setting the inner list user to null. In the IEnumerable<> implentation GetEnumerator() method the first check is if the inner list is null. If the inner list is null then the fillUsers() method is called to retrieve all users from the database.
If this example inherited from List<> then the Clear() method of List<> would be called and clears the list (removing all items) however the list is not null. Therefore enumerating the list after the Clear() method has been called will result in no users. Now this could be re-written using a List<> implentation as follows. Where the only thing you will have to do is override the Clear() method and the constructor to load the users. Such as.
public class UserListCache : List<User>
{
/// <summary>
/// const cache string
/// </summary>
const string userCacheString = "_userCacheList";
/// <summary>
/// current list of users
/// </summary>
public static UserListCache Current
{
get
{
if (HttpContext.Current == null)
throw new Exception("NO CONTEXT");
var userList = HttpContext.Current.Cache[userCacheString] as UserListCache;
if (userList == null)
{
userList = new UserListCache();
HttpContext.Current.Cache[userCacheString] = new UserListCache();
}
return userList;
}
}
/// <summary>
/// default constructor
/// </summary>
public UserListCache()
{
this.fillUsers();
}
/// <summary>
/// clear the list
/// </summary>
public new void Clear()
{
base.Clear();
this.fillUsers();
}
/// <summary>
/// fills the users from the database
/// </summary>
void fillUsers()
{
//TODO: Get from DB
}
}
Now neither method is better than the other (and the solution may not be adequate).

Categories