I have a class that keeps track of Property Changes
public class Property
{
object _OriginalValue;
object _ProposedValue;
DateTime _ProposedDateTime;
List<Property> _History = new List<Property>();
public object OriginalValue
{
get
{
return _OriginalValue;
}
set
{
_OriginalValue = value;
}
}
public object ProposedValue
{
get
{
return _ProposedValue;
}
set
{
_ProposedDateTime = DateTime.Now;
_ProposedValue = value;
}
}
public bool IsDirty
{
get
{
if (OriginalValue != ProposedValue)
{
return true;
}
else
{
return false;
}
}
}
}
This property can be used by classes like
public class Customer
{
protected Property _FirstName = new Property();
public string FirstName
{
get
{
return (string)_FirstName.ProposedValue;
}
set
{
_FirstName.ProposedValue = value;
}
}
public object GetOriginalValue(Property Property)
{
return Property.OriginalValue;
}
}
The question is, is there a way to secure the original value when passing this to a client in an N-Tier architecture?
When a client passes a Customer back into the Service Boundary - by default you can't trust the client. You need to either reload the original values from the database or validate that the original values are untampered. Of course I'm assuming we're going to use business logic based on the current values in the customer to reject or allow an update operation.
Example:
User inserts record with Name Bob.
User fetches record with Name Bob and changes name to Ted. Original Value is Bob, proposed Value is Ted.
User sends Customer to Service to Update Customer.
Everything is good.
*A business rule is now coded into the service that says if the customer's name is Ted - allow the update else throw "unable to update" exception. *
User fetches record with name Ted.
User changes name to Darren.
User changes name back to Ted - system throws exception.
User fetches Ted. User cheats and uses a tool to change the OriginalPropertyValue on the client.
The server doesn't refetch the OriginalValue from the database and simply reads the OriginalValue coming from the client.
User bypasses business rule.
Actually there're more issues with your approach than just checking if original value hasn't been tampered. For example, I suspect that's a multi-user environment where more than an user would be able to edit the same object. That is, the original value mightn't be tampered, but changed before other has already saved a new original value in the database.
I guess you're already applying some kind of optimistic or pessimistic locking on your data...
About your actual concern, probably you need to sign your original value, and whenever you're going to store those objects back in the database, your application layer should check that original value hasn't been tampered (from Wikipedia):
Digital signatures are a standard element of most cryptographic
protocol suites, and are commonly used for software distribution,
financial transactions, contract management software, and in other
cases where it is important to detect forgery or tampering.
Related
For study purposes I have designed a product-service which allows to perform CRUD operations against a product entity made up by the following properties:
string ID
string Name
decimal ListPrice
decimal FinalPrice
the ID, the Name and the ListPrice are stored in the product-service's database, while the FinalPrice is retrieved by an external service, the price-card-service, which exposes the following endpoint: GET /price-card-by-id/{product-id} which returns an object containing the product's final price.
The Create and Update operations of the product-service don't allow to do anything with the product's FinalPrice, but when retrieving a Product it will have its FinalPrice if returned by the price-card-service
By now the logic of retrieving and setting the FinalPrice is handled withing the GetProductByIdRequestHandler:
public class GetProductByIdRequestHandler : IAppRequestHandler<GetProductByIdRequest, GetProductByIdResponse>
{
private readonly IProductRepository _productRepository;
private readonly PriceCardServiceClient _priceCardServiceClient;
public GetProductByIdRequestHandler(IProductRepository productRepository, PriceCardServiceClient priceCardServiceClient)
{
_productRepository = productRepository;
_priceCardServiceClient = priceCardServiceClient;
}
public async Task<OneOf<GetProductByIdResponse, IError>> Handle(GetProductByIdRequest request, CancellationToken cancellationToken)
{
var product = await _productRepository.GetById(request.ProductId);
if (product == null)
{
return new NotFoundError
{
Message = $"Could not find product {request.ProductId}"
};
}
var priceCardList = await _priceCardServiceClient.ActiveAsync(product.Id, cancellationToken);
if (!priceCardList.Items.Any())
{
product.FinalPrice = product.Price;
return new GetProductByIdResponse(product);
}
var priceCard = priceCardList.Items.First();
if (priceCard.NewPrice < 0)
{
return new PriceCardNewPriceLessThanZeroError
{
Message = $"Price {priceCard.NewPrice} for PriceCard {priceCard.Id} for Product {product.Id} must be greater or equal to 0"
};
}
product.FinalPrice = ProductPrice.From(System.Convert.ToDecimal(priceCard.NewPrice));
return new GetProductByIdResponse(product);
}
}
I'm wondering if DDD promotes a different way for handling this kind of operations, perhaps by injecting the PriceCardServiceClient into the Product entity and creating a readonly FinalPrice property which handles the logic.
What are the possible approches?
It depends from your domain, mainly.
Is the Product, as a domain object, requiring this information? Then you could:
store it directly, requiring it before via the service,
obtain it every time you need the entity.
The first solution requires a 'update' process, that at least for each valid Product, aligns the stored value with the current valid one. The second one gives you the current value every time, but it also makes that part of the domain dependent from another service. In other words, you could not get the Product if the service PriceCardServiceClient is not responding. Or, you should manage this special case, once again with extra code.
If, instead, your domain entity doesn't require it, if you load/show/manage it is just related to the UI. Hence, using the DDD will not cause any change in the way you get this information.
I'm using Windows Auth in an Intranet setting to Cache information pulled from Active Directory. The purpose of the Cache is to speed up the page, as reading from AD is not particularly fast, and doesn't need to be done every single time. (The data doesn't change all that often)
To do this, i'm setting a custom key in HttpContext.Application.
This is the code located in Global.asax to handle VaryByCustom:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
System.Diagnostics.Debug.Print("GetVaryByCustomString : " + context.Application["BrowsingSession_Key"].ToString());
if (arg == "BrowsingSession_Key")
{
object o = context.Application["BrowsingSession_Key"];
if (o == null)
{
o = Guid.NewGuid();
context.Application["BrowsingSession_Key"] = o;
}
return o.ToString();
}
return base.GetVaryByCustomString(context, arg);
}
In my BaseController (Inherited by all my controllers):
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
//Custom Cache Initiation Variable
if (HttpContext.Application["BrowsingSession_Key"] == null)
{
HttpContext.Application["BrowsingSession_Key"] = Guid.NewGuid();
System.Diagnostics.Debug.Print("BaseController.Initialize : " + HttpContext.Application["BrowsingSession_Key"].ToString());
}
}
And finally, in my method inside a controller:
[OutputCache(Duration = 300, VaryByCustom = "BrowsingSession_Key", Location = OutputCacheLocation.Server)]
public ActionResult Index(HomeViewModel model)
//...
return View("index", model);
}
The issue is simple - the first person to view the page has their info cached, and the Guid for BrowsingSession_Key is set.
However, the next user visits the page within the 5 minute window, and reaches the last users cached content.
As you can see - i'm attempting to give each user a unique BrowsingSession_Key, so that they get their own cached content.
I'm using VaryByCustom so that i can quickly invalidate the cache by assigning a new BrowsingSession_Key (Guid) to that user - and pull a non-cached copy of a page for them.
Can you see what's going wrong here?
From my testing - it seems Initialize is often called, as is GetVaryByCustomString, in the places you'd expect them to be called. However, i can't run debug as multiple users, so i can't see why they're getting the same Guid and the same outputcache.
As it turns out, Application-level variables are not a good place to be storing per-user information, even temporarily.
In the end, i swapped over to using a cookie with a stored GUID, and invalidate the cookie (reset the GUID, or delete & Re-create). This meant multiple users were then able to use the site, with GetVaryByCustomString instead handling information stored in the Cookie.
This works for me - but i need to take into account the possibility of users swapping cookies, so will look further into encryption options.
For now - the answer is - Don't use Application-level variables this way, they're not suited to such tasks.
I have an application that is going to be used to change the status code of production units to track them throughout the process. My current issue is displaying the status code description depending on the status code of the currently selected record. I have a method that I think will do the job, but I do not know where to put it to perform the desired actions. I have a 2NF Microsoft Access (.mdb) database on the backend that has all of the desired information and is built properly, but I am having trouble working with it through C#.
public void DescLabel()
{
if (statusCodeLabel.Text == "-5")
{
statusCodeDescLabel.Text = "Problem with Unit.";
}
if (statusCodeLabel.Text == "10")
{
statusCodeDescLabel.Text = "Manufacturing Order Created.";
}
if (statusCodeLabel.Text == "15")
{
statusCodeDescLabel.Text = "Stock Room in Process.";
}
if (statusCodeLabel.Text == "20")
{
statusCodeDescLabel.Text = "Picked by Stock Room.";
}
}
You could simply add a property to your Production Unit model class, called StatusDescription and have it return the strings above based on its internal status code. Then, just call that property from your UI to get the text you desire.
public StatusDescription {
get {
if (statusCode == 15) {
return "Stock Room in Process.";
}
// etc, etc.
return string.Empty;
}
}
Then just...
statusCodeLabel.Text = productionUnit.StatusDescription;
And update your UI when it is required to be updated. Either on a change of state. Or on a timer, whatever your application requires.
That said, it's something that sounds like it should be in the database already and mapped to your model class via the status code in question.
In the old API (1.X) you could tell whether the server was connected or not by using the State property on the MongoServer instance returned from MongoClient.GetServer:
public bool IsConnceted
{
get
{
return _client.GetServer().State == MongoServerState.Connected;
}
}
However GetServer is not a part of the new API (2.0). How can that be achieved?
The more appropriate way to do that is not by checking the server but rather the cluster (which may contain multiple servers) and you can access it directly from the MongoClient instance:
public bool IsClusterConnceted
{
get
{
return _client.Cluster.Description.State == ClusterState.Connected;
}
}
If you would like to check a specific server that's also possible:
public bool IsServerConnceted
{
get
{
return _client.Cluster.Description.Servers.Single().State == ServerState.Connected;
}
}
Keep in mind that the value is updated by the last operation so it may not be current. The only way to actually make sure there's a valid connection is to execute some kind of operation.
As noted by i3arnon, one has to perform some sort of operation on the database before the state is updated properly.
The act of enumerating the databases is sufficient to update the state.
This worked for me:
var databases = _client.ListDatabasesAsync().Result;
databases.MoveNextAsync(); // Force MongoDB to connect to the database.
if (_client.Cluster.Description.State == ClusterState.Connected)
{
// Database is connected.
}
I'm a IT student, second year. We just learned to program with 3 layers, one for getting data with a class, one for manipulating stuff with requests (all of the methods go in here) and one for the working of the program itself. Seeing as the first two go into classes instead of a form I dont know how to show errors.
Example:
We need to make a login system with a webbrowser and some other stuff behind it. So I make the login in a class, but how to check back for errors? I don't think it's normal or even possible to do MessageBox.Show(error); from a class, I can only return stuff, but I want the username/id to be returned if possible.
So in short, what is the best/most accepted way to report errors that are caused by data, so from a class?
Your framework level API's (eg. your layers) should use Exceptions for real errors, and return values to report non-critical errors.
public class Login
{
public bool AccountExists(string name) {
bool exists;
// do checking
return exists;
}
public LoginResult Login(string name, string password) {
// Try login
// If successful
return LoginResult.Success;
// What if the user does not exist?
return LoginResult.AccountNotFound;
// What about an error?
return LoginResult.Error;
}
}
public enum LoginResult
{
None,
AccountNotFound,
Error,
Success
}
In the example above, you can report the status of operations through return values. For LoginResult this could even be a value type (struct) that contains more information about the result (eg. a string message or something). Because these types of operations on non-critical, there is no necessity for exceptions here. Exceptions are costly and not always necessary to report errors.
Now let's talk about a different type of error. Logical developer errors. These should be handled by throwing exceptions. Take this example (assume we have some type Account that has a Role property).
public class Foo
{
public bool IsAdmin(Account account) {
if (account == null) {
throw new System.ArgumentNullException("You cannot pass a null account!");
}
return account.Role == "Admin";
}
}
We know as a developer that the account should not be null, so we should check for it and throw an exception if it is. If this exception is ever thrown, its a bug in the calling code and should be fixed not to pass in a null value.
Now that I've given two rough scenarios, how does this apply to your question? These are API's. Whatever your UI layer is, whether it be a WinForm, WPF Window, WebForm, or some other UI, the UI only has to use the API. The API is responsible for reporting information that can be usable by the UI, and the UI is responsible for displaying info in whatever way is best suited for that UI.
The framework API layers should never be responsible for reporting an error to the user with a UI. They should only be responsible for reporting errors to the developer who can take the result, and wire it up to the UI layer in some fashion. You would never display a message box or write to a console from a framework API for example. You would return some result that the UI can use to display its own message.
I highly recommend that you read Framework Design Guidelines. It covers a lot of this material and is an extremely great read.
You should have a class which validates the data object and returns error information. Then your front-end code can ask this class to validate the data and show any error messages that get returned.
var username = GetUserName();
var password = GetPassword();
var validationResult = new Validator().ValidateLogin(username, password);
if(validationResult.ErrorMessage != null) {
MessageBox.Show(validationResult.ErrorMessage);
} else {
// Do what you would have done.
}
If any errors occur that are outside of the expected logic flow, they should throw an exception.
Well you can use Exceptions. You Just throw the exception, it is up to the caller on what to do with the exception.
class Login
{
public Login()
{
}
public bool CheckLogin(string userName, string password)
{
// Do your validation here.
If every thing goes fine
return True.
else
throw Exception("custom message.");
}
}
class Input //class which takes input.
{
Login login = new Login();
public void TakeInput(string username, string password)
{
try
{
login.CheckLogin(username, password);
}
catch(Exception ex)
{
MessageBox.show(ex.message);
}
}
}