Validation with State Pattern for Multi-Page Forms in ASP.NET - asp.net

I'm trying to implement the state pattern for a multi-page registration form. The data on each page will be accumulated and stored in a session object.
Should validation (including service layer calls to the DB) occur on the page level or inside each state class? In other words, should the concrete implementation of IState be concerned with the validation or should it be given a fully populated and valid object? See "EmptyFormState" class below:
namespace Example
{
public class Registrar
{
private readonly IState formEmptyState;
private readonly IState baseInformationComplete;
public RegistrarSessionData RegistrarSessionData { get; set;}
public Registrar()
{
RegistrarSessionData = new RegistrarSessionData();
formEmptyState = new EmptyFormState(this);
baseInformationComplete = new BasicInfoCompleteState(this);
State = formEmptyState;
}
public IState State { get; set; }
public void SubmitData(RegistrarSessionData data)
{
State.SubmitData(data);
}
public void ProceedToNextStep()
{
State.ProceedToNextStep();
}
}
//actual data stored in the session
//to be populated by page
public class RegistrarSessionData
{
public string FirstName { get; set; }
public string LastName { get; set; }
//will include values of all 4 forms
}
//State Interface
public interface IState
{
void SubmitData(RegistrarSessionData data);
void ProceedToNextStep();
}
//Concrete implementation of IState
//Beginning state - no data
public class EmptyFormState : IState
{
private readonly Registrar registrar;
public EmptyFormState(Registrar registrar)
{
this.registrar = registrar;
}
public void SubmitData(RegistrarSessionData data)
{
//Should Validation occur here?
//Should each state object contain a validation class? (IValidator ?)
//Should this throw an exception?
}
public void ProceedToNextStep()
{
registrar.State = new BasicInfoCompleteState(registrar);
}
}
//Next step, will have 4 in total
public class BasicInfoCompleteState : IState
{
private readonly Registrar registrar;
public BasicInfoCompleteState(Registrar registrar)
{
this.registrar = registrar;
}
public void SubmitData(RegistrarSessionData data)
{
//etc
}
public void ProceedToNextStep()
{
//etc
}
}
}

I prefer to validate at both the state (collection) level AND the final commit. In general, I prefer to validate as soon as possible as part of a good user experience. From a data validation/protection level I prefer to validate at the final save/commit level as well just in case something snuck through, protection against generall trickery, or (more likely) a different route to the save/commit point in the future.

Related

Castle Dynamic Proxy MixinInstance behaviour

I was struggling with non virtual members in my POCO classes using Castle's DynamicProxy generator and hit upon a way to make this happen using the ProxyGenerationOptions.AddMixinInstance() using the below code.
The question I have is why, if the mixin can send non-virtual members to the interceptor, can't the standard proxy when based on my actual type???
Below is the code.
void Main()
{
var generator = new ProxyGenerator();
Console.WriteLine(Environment.NewLine + "============ Proxy - With Target ===============");
var person = new Person { Name = "Freddy FudPucker", Age = 62 };
var personProxy = CreateProxyWithTarget(generator, person);
Console.WriteLine(((IPerson)personProxy).Name);
Console.WriteLine(((IPerson)personProxy).Age);
((IPerson)personProxy).Name = "Speedy";
((IPerson)personProxy).Age = 64;
Console.WriteLine(((IPerson)personProxy).Name);
Console.WriteLine(((IPerson)personProxy).Age);
Console.WriteLine(((ITracking)personProxy).State);
((ITracking)personProxy).State = 1;
Console.WriteLine(((ITracking)personProxy).State);
}
public object CreateProxyWithTarget(ProxyGenerator generator, Person person)
{
var options = new ProxyGenerationOptions();
options.AddMixinInstance(person);
options.AddMixinInstance(new Tracking());
return generator.CreateClassProxyWithTarget(typeof(ProxyBase), new[] { typeof(ITracking) }, new ProxyBase(), options, new PersonInterceptor());
}
Which gives the following output
Person System.String get_Name()
Freddy FudPucker
62
Person Void set_Name(System.String)
Person Void set_Age(Int32)
Person System.String get_Name()
Speedy
Person Int32 get_Age()
64
Person Int32 get_State()
0
Person Void set_State(Int32)
Person Int32 get_State()
1
Below are the supporting classes and interfaces
public class ProxyBase
{
public ProxyBase()
{
}
}
public interface ITracking
{
int State { get; set; }
}
public class Tracking : ITracking
{
public int State { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
public int Age { get; set; }
}
public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
}
public interface IPersonAge
{
int Age { get; set; }
}
class PersonInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Person {invocation.Method}");
invocation.Proceed();
}
}
Your class proxy with target inherits from your ProxyBase class so requires virtual members, while DynamicProxy mixins implement members of the mixin class's interfaces on that proxy class so are implicitly virtual. Effectively mixins work like interface proxies with targets.
// You can do this (from your example):
Console.WriteLine(((IPerson)personProxy).Name);
// ... but not this (because the proxy isn't a Person but is an IPerson):
Console.WriteLine(((Person)personProxy).Name);
The XML documentation for AddMixinInstance has some more detail: https://github.com/castleproject/Core/blob/e2dfb57020d9dbb4b31f3ce548b34cb35ffa3307/src/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs#L208-L225

Asp Mvc 6 Model Validation with a service in custom ValidationAttribute

TLDR: In Asp Mvc 6 how do I perform model validation with a service using data annotations? What are the alternatives?
I have a very simple model
public class MyModel
{
[Required]
public string Name { get; set; }
}
I also have a service that exposes some simple validation methods
public interface IMyService
{
string[] ReservedWords { get; }
bool IsValidName(string name);
// Internally calls IsValidName and throws an Exception if the name is invalid
void Save(MyModel myModel);
// ... snip
}
And I have wired up my controller like so
public class MyController : Controller
{
private readonly IMyService _service;
public MyController(IMyService service)
{
_service = service;
}
// ... snip
public IActionResult Post(MyModel myModel)
{
if (!_service.IsValidName(input?.Name))
{
ModelState.AddModelError(nameof(MyModel.Name), "Invalid Name");
}
if (!ModelState.IsValid)
{
return View(myModel);
}
_service.Save(myModel);
return RedirectToAction(nameof(Index));
}
}
It feels a bit clucky to have 2 stages of validation - automatic model validation then manually performing service validation. I was hoping that something simialr to this would work
public class MyModel
{
[ServiceValidation(nameof(IMyService), nameof(IMyService.IsValidName)]
[Required]
public string Name { get; set; }
}
public ServiceValidationAttribute : ValidationAttribute
{
private readonly Type _interfaceOrClass;
private readonly string _methodOrProperty;
public ServiceValidationAttribute(Type interfaceOrClass, string methodOrProperty)
{
_interfaceOrClass = interfaceOrClass;
_methodOrProperty = methodOrProperty;
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = validationContext.GetService(_interfaceOrClass);
// Extension method in shared library to assist with reflection
bool isValid = _interfaceOrClass.ValueForMethodOrPropertyNamed<bool>(service, _methodOrProperty, value);
return isValid
? ValidationResult.Success
: new ValidationResult(ErrorMessage);
}
}
However var serivce is always null, is there any way around this? I have wired up the IMyService to an implementation in the Startup.cs as it is available in the Controller.
Alternatively is there a better way of adding to the ModelState with a service?

ASP.NET MVC - Abstraction between Data and Object Layers

I am using ASP.NET EntityFramework MVC (All Latest) with Visual Studio 2013.
I am attempting to come up with a unifying means of standardizing the abstraction between my object and data layer.
I know that many people like to use the IRepository pattern with MVC. My biggest issue with this is that it forces you to create and maintain a second object type (The Repository) for each of the objects that you want to maintain. My solution has been to combing the IRepository method with a Static Factory pattern to make a Static Repository, for instance:
public class SiteDatabase : DbContext
{
// Singleton
private static SiteDatabase _Instance;
public static SiteDatabase Instance
{
get
{
if (_Instance == null)
{
_Instance = new SiteDatabase();
}
return _Instance;
}
}
public DbSet<User> Users { get; set; }
}
public class User : IUser
{
public static User Create(string UserName)
{
User item = new User();
item.UserName = UserName;
SiteDatabase.Instance.Users.Add(item);
return item;
}
public static User Find(string UserName)
{
return SiteDatabase.Instance.Users.SingleOrDefault(x => x.UserName == UserName);
}
public static User[] All()
{
return SiteDatabase.Instance.Users.ToArray();
}
public string Id { get; set; }
public string UserName { get; set; }
protected User()
{
Id = Guid.NewGuid().ToString();
}
public void Delete()
{
SiteDatabase.Instance.Users.Remove(this);
}
}
public class Page
{
public static Page Create(string PageName)
{
...
}
public static Page Find(string PageName)
{
...
}
public static Page[] All()
{
...
}
...
public void Delete()
{
...
}
}
My question is: will this pattern cause me to miss out on any built-in functionality that the normal repository pattern would allow me to capture?
The non-static methods could be handled with an interface, but what about the static methods? Is there any way to have a base class that ensures that static methods will exist in derived classes?

Create a log everytime When methods in an interface class are called

I want to update a log file(txt) everytime when methods in a an interface class are called?
Is there any way to do this other than writing code in every method to create log?
Here's my 30 mins. you'll have to implement the logging code somewhere so you have to create another abstraction for your code. thus an abstract class is needed. i think. this is very quick and dirty.
public interface IService<T>
{
List<T> GetAll();
bool Add(T obj);
}
then you'll need the abstract class where you'll need to implement your logging routine
public abstract class Service<T> : IService<T>
{
private void log()
{
/// TODO : do log routine here
}
public bool Add(T obj)
{
try
{
log();
return AddWithLogging(obj);
}
finally
{
log();
}
}
public List<T> GetAll()
{
try
{
log();
return GetAllWithLog();
}
finally
{
log();
}
}
protected abstract List<T> GetAllWithLog();
protected abstract bool AddWithLogging(T obj);
}
as for your concrete classes
public class EmployeeService : Service<Employee>
{
protected override List<Employee> GetAllWithLog()
{
return new List<Employee>() { new Employee() { Id = 0, Name = "test" } };
}
protected override bool AddWithLogging(Employee obj)
{
/// TODO : do add logic here
return true;
}
}
public class CompanyService : Service<Company>
{
protected override List<Company> GetAllWithLog()
{
return new List<Company>() { new Company() { Id = 0, Name = "test" } };
}
protected override bool AddWithLogging(Company obj)
{
/// TODO : do add logic here
return true;
}
}
public class Employee
{
public int Id {get;set;}
public string Name { get; set;}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
then on your implementation you can just..
static void Main(string[] args)
{
IService<Employee> employee = new EmployeeService();
List<Employee> employees = employee.GetAll();
foreach (var item in employees)
{
Console.WriteLine(item.Name);
}
IService<Company> company = new CompanyService();
List<Company> companies = company.GetAll();
foreach (var item in companies)
{
Console.WriteLine(item.Name);
}
Console.ReadLine();
}
hope this helps!
I think you would have to use Aspect Oriented Programming to achieve that. Read http://www.sharpcrafters.com/aop.net
I think you meant class (instead of interface)
Two options I can think of:
Implementing INotifyPropertyChanged which is in lines of writing code in every method
or
to adopt on of the AOP frameworks in the article http://www.codeproject.com/KB/cs/AOP_Frameworks_Rating.aspx if that is not a major leap

asp.net WebForms emulation of the state in the stateless env

I'm looking for an elegant way to have AppContext configured right and here is it:
public class AppContext : IAppContext
{
public AppContext()
{
Application = new AppStorage(); // app scoped hashtable
Local = new LocalStorage(); // current thread scoped hashtable
Session = new SessionStorage(); // session for some reasons hashtable
}
public CultureInfo Culture { get; set; } // session scoped
public UserProfile AuthProfile { get; set; } // session scoped
public IStorage Application { get; private set; } // application
public IStorage Session { get; private set; } // session
public IStorage Local { get; private set; } // current thread
public IStorage WcfSession { get; private set; } // wcf session
private ISecurityWriter SecurityWriter; // session scoped
private ISecurityContext SecurityContext; // session scoped
/// 1. START WEB CONTEXT
/// 2. START WCF CONTEXT
}
currently I am balancing between
a)
public class Global : HttpApplication
{
public static AppContext Context;
protected void Application_Start(object sender, EventArgs e)
{
Context = new AppContext();
}
}
but I don't like the ideea to have
Global.Context.Sesstion.Set<Order>(theOrderInstance);
b) and the addition to AppContext following lines
public class AppContext{
private static AppContext instance;
public AppContext Instance
{
get{
if(instance == null)
instance = new AppContext();
return instance;
}
}
this also is not nice looking
AppContext.Instance.Session.Set<Order>(theOrderInstance);
QUESTION: I like the idea of having
AppContext.Session.Set<Order>(theOrderInstance);
any toughs how to achieve this ?
something OSS and relevant for this topic would be greatly appreciated
have fun :)
How about this way?
protected AppContext Instance
{
get{
if(instance == null)
instance = new AppContext();
return instance;
}
}
public IStorage Session
{
get{
return Instance.Session;
}
}
look here:
public static class AppContextExtensions
{
public static AppContext Context(this Page page)
{
return AppContext.Instance;
}
}
usage
this.Context().Session.Set<Order>(theOrderInstance)
and i'm happy with it :)

Resources