The problem:
When programming with play framework I feel that I'm stumbling with same problem than in many times at the past which is creating several models of the same type just because I want to add, update or use different data about certain model in different use cases.
Let me explain, lets consider of a example where I have 2 different views: register and login
I would have following User model:
/**
* Example User class (simple annotations for demo purposes).
*
*/
#Entity
public class User {
#Id
public Long id;
#Required
public String email;
#Required
public String password;
#Required
public String firstName;
#Required
public String lastName;
}
In case of registering: I would have all corresponding fields in register.scala.html : email, password, firstName, lastName - because I will need them all when I register, right?
But also I would want to use repeatPassword field to confirm that user has typed password correctly, so I would add this into User model:
#Required
#Transient
public String repeatPassword;
Ok, then I would extend this model to have repeat password confirmation check in order to correct my "automatic" validations when form is submitted, like this:
public String validate() {
if(!password.equals(repeatPassword)) {
return "Passwords doesn't match.";
}
return null;
}
}
So even now I would have one extra attribute repeatPassword which is not persisted to database but used within registration.
Problem #1: Our model starts to go confusing piece by piece.
In case of login: I would want to use same model because its a User which is trying to sign in, right? But instead of all the fields I would only need email, password.
Problem #2: My User model cant be used in login because its already customized to be used within registration - I would need to move repeatPassword and validate() method to separate UserRegistation model, plus duplicate firstName lastName etc. fields or mix using both User and UserRegistration model within registration and to render two different forms to same registration view = confusing.
Problem #3: My login page cant use User model because it has annotations in place, if I dont add all the necessary fields like firstName, lastName etc. I will get errors. Again, I would need to create separate UserLogin model just because I want to login to work.? Example below:
public class UserLogin {
#Required
public String email;
#Required
public String password;
public String validate() {
if(User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
So very fast, I would have 3 different models just to represent User, one of them is persisted to database and two others is used to validate errors when we are completing login and registration functionality at template side.
So my question is: How on earth I should begin to solve this mess? code complexity is rising very fast :) Should I create separate models.template and models.database packages where template models are only ones within annotations and in case of no errors I start to fill real model before saving or updating its info to database? I need desperately answers from you guys/girls, Can we make one model approach? thnx in advance.
I'll start from the end: you don't need to use whole model for changing password or loggin-in (also you don't need to create separate, 'non-persisted' sub-models), although Form<YourModel> is useful while filling large objects, you can just avoid them and rely on common DynamicForm.
In such case of course it won't use constraints added with annotations to the model's fields but you can validate them manually.
For an example: in registration form you can check if #Required fields like email, firstName, lastName exists (tip: also add MinLength and MaxLength constraints), but you should remove #Required annotation from password field.
Next after checking if the form hasn't any errors you can check if password and repeatedPassword are the same and it they are identical you can also add some individual (advised) strength check - most probably it wouldn't be possible with the annotations in the model.
In case of logging form the thing is ever easier: using DynamicForm data just try to find existing User with given password if result is null that means, the user doesn't exists or password is invalid.
Finally, tip: There is ready-to-use, full-stack authentication and authorisation module available for Play 2.0 by Joscha Feth (and I'm huge advocate of this solution.)
Related
Say I have a simple form with the following field the user has to fill in:
name
surname
birth date
address
The data needs to be saved in a database table with the same fields/columns. All the columns are not nullable.
The form offers two buttons: "Save" and "Save as draft" to let the user finish compiling the form later.
The first will check if all the fields are correctly filled whereas the second doesnt make any check other than "cannot insert number in name field".
I tend to use Hibernate Validation annotations on my DTO, but in this case will break the function "Save as draft".
How would you handle this scenario?
Technologies I'm using: Spring Boot/MVC to expose the REST service consumed by frontend, hibernate/Spring DATA to save data to database.
You can use a validation function instead of annotations directly on the attributes. That way your validation can have some logic in it.
#Value
class MyDto{
String name;
String surname;
DateTime birthdate;
Address asdress;
boolean draft;
#AssertTrue
private boolean validateInstance(){
if(!isDraft()){
// do validation
}
return true;
}
}
Create an interface for your entry and create two implementations of that interface.
One being the actualEntry with the annotations.
The other being the draft without those annotations.
I originally asked this question when Identity was in beta. The classes and interfaces have changed considerably since then and it appears the RTW version has some modifications again over the RC version. In principle I need to achieve the following.
authenticate the local login against my usertable tblMembers which contains the userid field and password which are the two items I need to authenticate.
have access to my tblMember record/class via the Controller.User property (Prior to MVC5 identity I had achieved this using the membership provider methods.) regardless of if the user logged in via the localuser method or via one of the other OAuth providers (Twitter, Google etc).
Ability to display my own custom username despite the login method. Local users login with a userid 1234567 and a password, ideally I would like to display "John Smith (1234567)" regardless of the authentication method (local/Twitter etc)
Initially I'm unsure as to what my memberclass should be inheriting from It appears from the
aspIdentitySample project that I should be using IdentityUser?
public partial class tblMember
{
public int id { get; set; }
public string membership_id { get; set; }
public string password { get; set; }
....other fields
}
Are there any new or updated examples of integrating your existing database/user tables with the ASP.NET Identity system?
I am also adding the identity tables to my database. If you create a new web project in visual studio 2013 you will see that now in RTM everything works better than RC plus you will see the
following table
public class ApplicationUser : IdentityUser
{
}
So Instead of ApplicationUser you can call your table tblMembers
public class tblMembers : IdentityUser
{
}
your table tblMembers will inherit Id Username Password security stamp and a discriminator column saying this is a tblMemeber
without making custom classes for authentication the easiest thing to do would be just to make the username the combination of your old usernames and userids. Then store the users real name or old username without the user id in a separate column.
have the users register with the built in user login and they can go to manage account and click use another service to log in. This will link the Google account to their regular account, so no matter which one they use it will log them in to the same account. If you have users with connected table information, I suggest you seed your table with all the users with something similar to the register method found in the template.Then just match the new combined username and Id to the old ones and populate data where needed in sql management studio.
Again a lot of issues in RC with extending IdentityUsers have been fixed. Microsoft is already adding more features to the identity user store and this tutorial http://www.windowsazure.com/en-us/develop/net/tutorials/web-site-with-sql-database/ is supposed to be updated soon. I plan on making my own walk through when i'm done changing my database but for now I hope my suggestions even though they are a simpler solution than you might want to implement.
You can do this easily by modifying the IdentityModel.cs as per the below:
Override OnModelCreating in your DbContext then add the following, this will change AspNetUser table to "Users" you can also change the field names the default Id column will become User_Id.
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
or simply the below if you want to keep all the standard column names:
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo")
Full example below (this should be in your IdentityModel.cs file) i changed my ApplicationUser class to be called User.
public class User : IdentityUser
{
public string PasswordOld { get; set; }
public DateTime DateCreated { get; set; }
public bool Activated { get; set; }
public bool UserRole { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
modelBuilder.Entity<User>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
}
}
Please note i have not managed to get this working if the current table exists.
Also note whatever columns you do not map the default ones will be created.
Hope that helps.
I'm starting to think (partially due to the lack of information in this area), that it may be easier to user the default identity classes, but to provide referential integrity to my own user table from the AspNetUsers table.
If i add a custom linking field into the AspNetUsers table is it possible to access my tables from the Controllers.User property? i.e. Controller.User.tblMember.Orders?
Say you have a repository method to update a Document:
public Document UpdateDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}
In this case, the entity has two properties. When updating a Document, both of these properties are required in the JSON request, so a request to PUT /api/folder with a body of
{
"documentId" = "1",
"title" = "Updated Title"
}
would return an error because "content" was not provided. The reason I'm doing this is because, even for nullable properties and properties that the user doesn't update, it seems safer to force the client to specify these fields in the request to avoid overwriting unspecified fields with nulls serverside.
This has led me to the practice of always requiring every updatable property in PUT and POST requests, even if it means specifying null for those properties.
Is this cool, or is there a pattern/practice that I haven't learned about yet that might facilitate partial updates by sending only what is needed over the wire?
The best practice in API design is to use HTTP PATCH for partial updates.
In fact, use cases like yours are the very reason why IETF introduced it in the first place.
RFC 5789 defines it very precisely:
PATCH is used to apply partial modifications to a resource.
A new method is necessary to improve interoperability and prevent
errors. The PUT method is already defined to overwrite a resource
with a complete new body, and cannot be reused to do partial changes.
Otherwise, proxies and caches, and even clients and servers, may get
confused as to the result of the operation. POST is already used but
without broad interoperability (for one, there is no standard way to
discover patch format support).
Mark Nottingham has written a great article about the use of PATCH in API design - http://www.mnot.net/blog/2012/09/05/patch
In your case, that would be:
[AcceptVerbs("PATCH")]
public Document PatchDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}
Is this cool, or is there a pattern/practice that I haven't learned
about yet that might facilitate partial updates by sending only what
is needed over the wire?
A good practice of doing a POST or PUT is to only include values that you need for that specific request. In doing the UpdateDocument you should ask yourself what "really should be done here"? If you have a hundred fields on that object do you need to update all of them or only part of them. What "action" are you really trying to do?
Let's have an illustration for those questions, say we have a User object that has the following fields:
public class User {
public int Id {get;set;}
public string Username {get;set;}
public string RealName {get;set;}
public string Password {get;set;}
public string Bio {get;set;}
}
You then have two use cases:
Update the profile of a User
Update the password of a User
When you do each of those you will not, or it's a good idea to, have one update method that will do both. Instead of having a generic UpdateUser method you should have the following methods:
UpdateProfile
UpdatePassword
Methods that accepts fields that they just need, nothing more, nothing less.
public User UpdateProfile(int id, string username, string realname, string bio) {
}
public User UpdatePassword(int id, string password) {
}
Now comes the question:
I have a use case that a "user action" allows for an update on
multiple fields where some of the fields can have "no input" from the
user but I don't want to update that field in my model.
Suppose a user updates his/her profile and provided values for Username, RealName but not for Bio. But you do not want to set Bio as null or empty if it has a value already. Then that becomes a part of your application's business logic and that should be handled explicitly.
public User UpdateProfile(int id, string username, string realname, string bio) {
var user = db.Users.Find(id);
// perhaps a validation here (e.g. if user is not null)
user.Username = username;
user.RealName = realname;
if (!string.IsNullOrEmptyWHiteSpace(bio)) {
user.Bio = bio;
}
}
I am having trouble figuring out how to get server-side DbContext validation errors back to the client. I understand that Breeze has default validators that react to a few of the attributes such as Required, but what about all the other attributes? I could write a custom JavaScript validator for Breeze that will check on the client side, but I also need to check to make sure the entity is valid on the server-side.
For example, the application requires a Person to to have a valid email address. A malicious user comes along and gets an email address past the client and posts to the server with a data that would not pass the EmailAddress validator. Thus far my experience with Breeze is that the email address will save and not bubble up any DbContext Entity Framework errors.
Assuming the model below, what would be the best way to get any entity validation errors?
public class PeopleContext : DbContext
{
public PeopleContext()
: base("name=ConnectionString"){ }
public DbSet<Person> People { get; set; }
}
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
}
UPDATE 1:
Here are some instructions to re-create the issue that I am experiencing.
Follow the instructions to create the "Todo" sample (http://www.breezejs.com/documentation/start-nuget)
Add a new custom validator to the BreezeSampleTodoItem.cs file:
[AttributeUsage(AttributeTargets.Property)]
public class CustomValidator : ValidationAttribute
{
public override Boolean IsValid(Object value)
{
string val = (string)value;
if (!string.IsNullOrEmpty(val) && val == "Error")
{
ErrorMessage = "{0} equal the word 'Error'";
return false;
}
return true;
}
}
Decorate the Description field with the new custom validator:
[CustomValidator]
public string Description { get; set; }
Add the proper usings of course (System and System.ComponentModel.DataAnnotations).
Run the project.
In one of the description fields type "Error" and save.
This is where I would expect to see an error come up through Breeze, or even an DbEntityValidationException be thrown from Entity Framework. I have tried on 2 separate computers with the same result. The entity saves to the database as if there were no error. In fact, if you put a breakpoint anywhere inside IsValid method of the custom validator you will see that its not even being called.
As of Breeze v 0.78.1 all registered DbContext server side validations will now execute during an EntityManager SaveChanges call. Any exceptions encountered will cause the save to rollback, and any validation errors to be serialized back to the Breeze client.
Note that this functionality is not yet supported for older ObjectContext ( as opposed to DbContext) based EF models.
And ... thanks to adamlj for discovering this issue and suggesting the solution.
I'm not sure what you mean by
get server-side DbContext validation errors back to the client
You could mean that you want the validation error messages to be sent to the client. But the rest of your question suggests that you want to know (a) how to run a custom validation on the server and (b) how to acquire and run a corresponding JavaScript version of that validation on the client. I will address this interpretation of your question.
Server
The Entity Framework (which you're using in your example) automatically runs Data Annotation validation rules for you ... unless you've disabled that feature manually. If you create custom validation rules in the proper way, EF will run these as well. This post by Daniel Wertheim describes how to write such rules. I can't vouch for that post in every detail but it seems correct to me. It even defines a custom Email-validationattribute!
If authoring a custom Data Annotation validation rule seems too Baroque to you (as it often does to me), you can write and call your own validation logic in one of the BeforeSave... methods discussed in "Server-side Interception".
I think these are your best server options. On to the client ...
Client
Breeze registers client-side JavaScript validations to match certain of the server-side Data Annotations (e.g., Required and MaxLength) that come across the wire in the metadata. As I write, custom Data Annotations are not recognized nor included in the metadata and they have no out-of-the-box analogs on the client. If you want the client to prescreen your entities using these rules, you'll have to write your own corresponding JavaScript validators and register them for the pertinent entity types as discussed in the Validation documentation page.
If you have suggestions or better alternatives, we'd love to hear them.
What I'm trying to accomplish is:
Have a bean backed form being validated, for example using the following class
public class PersonForm {
#NotNull
String name;
List<Long> interests;
// This attribute is not filled out in the form
List<Interest> realInterests;
}
So, "name" and "interests" come from the web form. "name" has some constrains (NotNull) and using #Valid does what it is supposed to do.
"interests" is a list of Interest ids.
After doing the initial validation of the "name" I fill out the List collection.
#CustomValidInterest
public class Interest {
Long id;
String name;
boolean available;
}
I want to validate this structure afterwards. "#CustomValidInterest" is a custom validation annotation.
I can do a 2-stage validation using do this with Validation Groups.
The problem is, if some "Interest" object is not valid I want to associate the error message with the "interests" field (List< Long > type), so when I retrieve the form errors the error is associated with the right field.
Maybe I'm trying to use validation the wrong way. I was trying to avoid having a bunch of programmatic comparisons which filled errors manually.
Answering my own question, this is achievable using PropertyEditors. The form might return a List< Long > but the form object can have only a List < Interest > which is built using said Property mapper. After that a #Valid on that list should validate any constraints that "Interest" enforces.