Saving business rules per user - c#

public interface IRule
{
bool Check(string input);
}
I have an interface that defines a rule. A rule is just a generic business rule or constraint that a user can create. So I have two sample rules:
public class ContainsRule : IRule
{
public string MustContain { get; set; }
public bool Check(string input)
{
return input.Contains(this.MustContain);
}
}
public class LengthRule : IRule
{
public int MaxLength { get; set; }
public bool Check(string input)
{
return input.Length <= this.MaxLength;
}
}
Rules may have more than one property that can be set, but in this example, each of these rules only have one property.
A user can create their own set of rules that should be saved. For example, a user have these three rules:
IRule[] rules = new IRule[]
{
new ContainsRule { MustContain = "foo" },
new ContainsRule { MustContain = "bar" },
new LengthRule { MaxLength = 5}
};
I need to persist this information to a database or some data store for each user. Since each user can have their own set of rules, I'm not sure what the database tables should look like.
User | ClassName | Parameters
-----------------------------------------------
1 | Namespace.ContainsRule | MustContain:foo
1 | Namespace.ContainsRule | MustContain:bar
1 | Namespace.LengthRule | MaxLength:5
My initial guess would be to create a table that looks something like the above, where parameters should a string. This means I would need to parse out the information and use reflection or something to set the properties. I would need to use the activator to create the class using the ClassName column. Another suggestion was instead of creating a delimited string for all the properties, there would be another table. Each of the properties would be its own row that has a foreign key relationship back to a row in the table above.
However, both examples don't seem to be the best way of saving these rules. Is there a better way to do this?

Why not use XML serialisation. The database table would contain the User # and the XML serialisation of the indvidual rule.

I believe that you are retrieving from database.
If so, try my suggestion.
Store the retrieved data into datatable, or convert them to datatable before applying the rule.
So the rule can be put as normal sql in datatable's filter property.
Instead of rule name and parameters, you can change it to a column containing
column like '%foo%'
Then apply this on the datatable's filter.
PS: I have converted List to Datatable and used such filter before

It seems to me, simply put, you need to map your objects to SQL tables (if only there was a technology that could to do this automatically... :)
Based on what you have posted, I envisage at least six SQL tables, more if there are further subclasses of rule e.g.
Rules
MustContainTextRules (subclass of Rules, 1:0..m)
MaxLengthRules (subclass of Rules, 1:0..1)
[Possibily further subclasses of Rules e.g. MinLengthRules?]
Rulesets ("a set of Rules")
Users
RulesetOwnership (relationship table between Users and Rulesets)
Whether they are distinct tables may be influenced by whether the rules are interrelated e.g. if the MinLengthRule value for a Ruleset cannot exceed its MaxLengthRule value then you may find it difficult to write a SQL constraint to validate this when they are in different tables.

Related

Dynamically assign values in C#

I am looking for an easiest way to assign values to the properties of a class dynamically.
In my WPF App, I have a list header values as shown below :
Name Mark Class --> header values (Name, Mark, Class these are the 3 headers)
---- --- -----
Nick 10 5
Tom 12 7
John 09 4
Sometimes, the header values changes:
Name Mark Percent Phone --> 4 header values
---- ----- ------- -----
So we cannot predict the number of headers. Sometimes it will be 5, sometimes it will be 2,
sometimes the number of headers will be 6, etc
So I created a class Named StudentMark with following properties.
public class StudentMark
{
[Order]
public double? Col1 {get;set;}
[Order]
public double? Col2 {get;set;}
[Order]
public double? Col3 {get;set;}
- - - - -
[Order]
public double? Col10 {get;set;}
}
When I get the list from server, I assign the values to the properties of the student mark class are shown as below code. This is doing for plotting a graph. We don't know the column header values in advance, we do like these.
StudentMark sm = new StudentMark();
var properties = from property in typeof(StudentMark).GetProperties()
where Attribute.IsDefined(property, typeof(OrderAttribute))
orderby ((OrderAttribute)property.GetCustomAttributes(typeof(OrderAttribute), false).Single()).Order
select property;
//PropertyInfo[] properties = typeof(StudentMark).GetProperties();
foreach (string str in HeaderColumns)
{
var d1 = csv.GetField<string>(str); // taking cell value
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(Double?))
{
if (property.GetValue(sm) == null)
{
property.SetValue(sm, d1);
break;
}
}
}
}
this is working but very very very slow. Is there anyway to do it without using reflection ??
Try to keep typed data separate from arbitrary untyped data. So if you want to represent a table of arbitrary user defined data you would do it something like:
public class MyTable{
public List<string> Headers {get;}
public List<List<string>> Rows {get;}
}
If the only thing you will be doing is presenting it to the user, and reading writing csv-files, such an representation is perfectly appropriate.
It is only when you need to use the data for something you need to use actual types to represent the data. But this can be quite complicated and would involve a lot of data validation to ensure the data is on the correct format.
You could for example have logic to check if each header has some specific value, and then parse the values for each row to a set of predefined types. If either the headers have incorrect values, or the parsing of some value fails, you would give an error and let the user deal with the problem.
If you want minimize the risk of mistakes, you should make them impossible in the first place, or detect them as early as possible, i.e. enforce the correct header names, parse values as soon as they are entered etc.
If you need to combine typed data with untyped data you could for example use a dictionary:
public class MyDataRow{
public string name {get;}
public int Mark {get;}
public Dictionary<string, string> UserDefinedData {get;}
The user defined data would just be treated as an opaque data blob, tracked thru the system, but not used for any computation, or if it is, with a great deal of error checking.

Show Hide divs in views based on boolean value

I'm currently working on an app using Asp.Net MVC and C#. One of the requirement is to check what process the item is and then to only show the appropriate div. So I've decided to create a Table in the Db which consist of:
Id ProcessDescription DivOneVisible DivTwoVisible
1 Approved True False
2 Analysis True True
...
NOTE - The Id's and ProcessDescription will never change
Currently the table only holds 10 rows of data but the idea is, in future more rows/columns can be added.
I then go ahead and create the appropriate methods, one for each Div as follows
public bool ShowDivOne(int id)
{
var data = uow.GetRepository<ItemProcess>().GetById(id);
bool showDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
if (showDivOne)
return true;
else
return false;
}
I use the same code as above for ShowdivTwo() method, but match the different column. Then in the view I do
#if(ShowDivOne){//div one code here}
#if(ShowDivTwo){//div two code here}
This works but I was wondering if there is a more generic way where I can write one method which will cover each scenarios even if new columns or rows are added.
The main thing you still need to have a mapping between Database and ViewModel somewhere. At the moment it is hard coded in your methods.
You can make it absolutely generic if you start use reflection and have a mapping array with properties name. But I would nt recommend doing it as it over complication and hard to maintain and change.
(If you want I can go into details of implementation).
For you example I would suggest to have a viewmodel per item, that contains properties of divs to display.
public class ProcessViewModel
{
public int Id {get;set;}
public bool ShowDivOne {get;set;}
public bool ShowDivTwo {get;set;}
ProcessViewModel(){}
ProcessViewModel(ItemProcess data){
Id = data.Id;
ShowDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
ShowDivTwo = data.DivTwoVisible.HasValue ? data.DivTwoVisible.Value : false;
}
}
You still query for each item individually or query them altogether and pass data to viewmodel to construct it.
And a simple foreach on a view to traverse through the list of viewmodels.
Extending it to contain more properties would be very easy and strait forward, with minimum code to maintain.

Azure Table Storage Doesn't Save Everything in Entity definition

This is the same of the entity that I am planning to save in the Azure Table Storage (ATS):
public class CarEntity : TableEntity
{
public CarEntity(string objPartitionKey, string objRowKey)
{
this.PartitionKey = objPartitionKey;
this.RowKey = objRowKey;
}
public string TableName
{
get { return "EntityTableName"; }
}
public string Property1 { get; set; }
// and this goes on
public string Property60 { get; set; }
}
Not all properties are required. Population of records depend on the selections that the user would be saving (e.g this is a CarEntity - if the user ordered wheels, properties WheelSize and WheelQuantity would be populated, if the user asks for repainting, RepaintingColor would be populated and so, on).
Assuming that there are 60 properties in this entity, not all properties gets saved in ATS. Despite a property being defined and no error being returned, that data doesn't get saved in the table. I know that there's a limit of 1MB per entity but considering the computations that we have done, it is kinda far from the 1MB limit.
Any help why columns don't appear even if the properties are saved accordingly? My save function is defined as follows:
public static CarEntity CarInsertOrReplace(CarEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
var table = SetupTable(entity.TableName);
table.CreateIfNotExists();
TableOperation insertOrMergeOperation = TableOperation.InsertOrReplace(entity);
TableResult result = table.Execute(insertOrMergeOperation);
CarEntity objEntity = result.Result as CarEntity;
return objEntity;
}
Sounds like the properties for your Entity vary based on the usage. What's probably happening is that Azure Table Storage is only creating columns for properties that are not null (have a value set). So you are will only see columns created for properties that have been set.
It sounds as if Table Storage is performing as you require but not necessarily as you expect. As answered by #Paul Fryer ATS will not store null values and as you do not (going by your quoted code) initialise the CarEntity properties they will be null by default. Therefore only properties set by the user will be saved to the table.
https://msdn.microsoft.com/en-us/library/azure/hh452242.aspx #Remarks:
If the Insert Or Replace Entity operation is used to replace an
entity, any properties from the previous entity will be removed if the
new entity does not define them. Properties with a null value will
also be removed.
Also, from your code
TableResult result = table.Execute(insertOrMergeOperation);
CarEntity objEntity = result.Result as CarEntity;
result will contain the TableOperation not a copy of the full entity in case that was what you were expecting.
This scenario might be the difference between using, for example, a SQL table where fields that are not given a value have a database default or default to null, against the Azure table model where fields not given a value do not exist. You just need to be aware of that difference when reading/writing to the storage chosen.
If you require all fields to be persisted to the table then provide a default value for each property, e.g. string.Empty
If strings are null or empty then it doesn't save the property at all. You're not doing anything wrong, you just have to consider this in your design when you're working with them.
If you're using TableEntity then it does the null/empty check for you. If you're using DynamicTableEntity then you have to do the check yourself.

Temp Table like thing in c#

I have a scenario where I need to use tabular data which is unlikely to change but which helps implement business logic:
Table
Parent Child Relationship Allowed
A B C True
B A C False
Each row represent a business rule. Based on this table I need to populate a dropdown control with the contents of the "Relationship" column. Can I have some sort of data structure within C# to store this tabular data, or do I need to use a a database table?
Unless you need to persist this data across sessions, you don't need to store it in a database table. From the perspective of Object Oriented design, why not make an object, and therefore class, that represents the structure you need. Something like this:
public class Relationship
{
public string Name { get; set; }
public string Parent { get; set; }
public string Child { get; set; }
public bool Allowed { get; set; }
}
Note of course that I'm using strings where you might want to use further objects of their own 'type'. Additionally, keep in mind access, and what should and shouldn't be allowed to access these properties... This is example is intentionally simple at this point!
I would agree that a full blown database may be overkill if this is all the data you need to store, so you could theoretically hardcode the data and structure in C# if you really wanted to, but not a good idea in almost all cases - even if it is unlikely to change.
At a minimum store the data in a little XML / config file so that IF it does change, you do not need to recompile the application.
Use DataTable: http://msdn.microsoft.com/en-us/library/System.Data.DataTable.aspx
You can create your Table and fill it like this:
// Definition
DataTable table = new DataTable();
DataColumn column = new DataColumn("Parent", typeof(string));
table.Columns.Add(column);
// Data
DataRow row = table.NewRow();
row["Parent"] = "A";
table.Rows.Add(row);

Best way to store look up values

I have had this question for quiet long and thought of seeking wisdom of the crowd here.
In my application there are 10 user roles allowed. Its an ASP.NET MVC2 application. Each controller method can be accessed by a specific user role only.
For implementing this I created a UserRoleType Enum.
public enum UserRoleType
{
SystemAdministrator = 1,
SeniorLevelExecutive = 2,
SeniorManager = 3,
JuniorManager = 4,
SeniorAdmin = 5,
JuniorAdmin1 = 6,
JuniorAdmin2 = 7,
SeniorAppraiser = 8,
JuniorAppraiser = 9,
SeniorResearch = 10
}
These values match with whats in database (UserRole table with 10 rows).
Also the UserRoleId of a user is stored in [User] table. As soon as a user logs in we get the roleId of the user from the database and match this to the above enum. For instance if the roleId of the user was 4, it means he/she is a Junior Manager.
This application is not in production now. The only drawback I see is when we go live if for some reason the value in User Role Type table did not match the Enum we will be in big trouble. What are the alternatives? Or should I just concentrate on making sure that we have the matching values in database. Any help will be highly appreciated.
Thanks a lot!
My opinion is, that if you can't trust your own configuration in the DB and Config files, you're up the creek anyways. Just make sure your DB records have that value as a specific column value, not the auto generated row ID.
Don't log the user in if the value for RoleID is not in the range of the Enum.
I would send an email to the admin to fix the issue.
A simple method would be to add a Name field to the UserRole table, and at your application startup, iterate over your enumeration, look up that UserRole by ID, and make sure the name matches UserRoleType.ToString(). You should be able to implement this without any major code changes.
private void VerifyUserRoles()
{
foreach (UserRoleType role in Enum.GetValues(typeof(UserRoleType)))
{
string dbName = /* SELECT Name FROM UserRole WHERE UserRoleId = (int)role */;
if(role.ToString() != dbName) throw new Exception();
}
}
A more complex method would be to not have an enum at all. If you want to have the list of roles be completely database driven, then make UserRoleType a class with a private constructor, and have it do a database read to create the list of objects. (I imagine there's a name for this pattern, not sure what it is, though.) Obviously, this would be a more significant change to your existing code.
public class UserRole
{
static List<UserRole> roles = new List<UserRole>();
static UserRole()
{
foreach (/* SELECT * FROM UserRole */)
{
roles.Add(new UserRole(...));
}
}
private UserRole(...){...}
// Permissions that the role consists of.
private bool CanEditEverything { get; private set; }
// Use this whenever you need to display a list of UserRoles.
public static ReadOnlyCollection<UserRole> AllUserRoles { get { return roles.AsReadOnly(); } }
// If you still need to explicitly refer to a role by name, rather than
// its properties, do these and set them in the static constructor.
public static UserRole SystemAdministrator { get; private set; }
}
I do this but add the appropriate constraints to the DB, with the constraint description directing the reader to the enum.
I am not sure you should be using a static data structure like an enum to model the elements from a dynamic one like a table. Would it not be better to have a UserRole entity class and a UserRoleCollection collection class? That way the set of user roles can be a bit more dynamic. Of course, anytime your code uses these data structures you would have to make sure you build in a failsafe mechanism that causes access to a particular resource to always be denied if an unknown user role is encountered. Naturally the code would generate a descriptive message if an unknown role somehow got entered into the database.

Categories

Resources