Suppose I have an entity Person(id, dept, EmailAddress,DOB, ...), when model created with EF, then create a metadata class for this class to put validation rule on server side like:
[CustomValidation(typeof(MyValidator), "DOBValidator")]
public Nullable<DateTime> DOB { get; set; }
[RegularExpression("^([\\w-\\.]+)#((\\[[0–9]{1,3}\\.[0–9]{1,3}\\.[0–9]{1,3}\\.)|(([\\w-]+\\.)+))([a-zA-Z]{2,4" + "}|[0–9]{1,3})(\\]?)$", ErrorMessage = "Invalid email address")]
[StringLength(128)]
public string EmailAddress { get; set; }
when the validation rule is in place, for any data sent from client side will go through the validation with no exception when submit any data for saving.
but now I want exception for the rule: from UI, when get data from UI by binding for entity Person, based on the data, I want to ignore validation. for example, when Dept=A, do not check EmailAddress validation, for dept=B, do not check DOB validation.
How to resolve this issue?
I believe you need Class-level validation. Have a look at this question
Of course, your code need to be compiled client-side. (If using WCF ria services there are a couple of ways to reach this)
HTH
Related
I'm hoping this is a simple question. I've created an Azure Mobile Apps project based upon the sample ToDo project, adding my own tables/data objects. The problem I'm having is adding/POSTing records to a table that has a foreign key relationship to another. The following is my Employee table data object:
public class Employee : EntityData
{
public string Name { get; set; }
public string EmailAddress { get; set; }
public bool IsActive { get; set; }
public string EmployeeTypeId { get; set; }
public virtual EmployeeType EmployeeType { get; set; }
}
...and this is my EmployeeType data object:
public class EmployeeType : EntityData
{
public string EmpType { get; set; }
public bool IsActive { get; set; }
}
The virtual EmployeeType property in the Employee class was necessary, I believe, to create the relationship with the EmployeeType table when using EF Code First to create the tables in the database. (At least, that's what I understand, and it worked) I am able to insert records from my Xamarin client app into the EmployeeType table using the InsertAsync method, but I receive a "Bad Request" 400 error when trying to insert into the Employee table.
I've looked around quite a bit for solutions, but everything refers to Azure Mobile Services and not Apps. If need be, I can update this question with my client side model classes (I'm on my PC now and don't have access to the Xamarin Studio project on my Mac). For reference, these classes are pretty much the same as the data objects - just each property is decorated with the JsonProperty attribute, except the virtual property outlined in the service. And for completeness, I did try adding that property to the client object and it still threw the "Bad Request" 400 error.
Thanks for any direction you can offer me.
Most likely, the problem is happening when trying to map the foreign key. Are you specifying all of the fields for employee type? I recommend that you do the following:
Use Fiddler or attach a delegating handler to your client to see what the outgoing request looks like. Update your comment with the JSON body. See https://github.com/Azure/azure-mobile-apps/wiki/Help,-my-app-isn't-working!#log-outgoing-requests-in-managed-client-xamarin-windows.
Attach a debugger to your server project. You can do this while running locally or after your solution is deployed to Azure, but you'll have better performance if you run locally. See https://github.com/Azure/azure-mobile-apps/wiki/Help,-my-app-isn't-working!#remote-debugging-net-server-sdk.
I suspect that the problem is that EmployeeType ends up being null in your deserialized object, and then Entity Framework rejects the DB insert.
Could you get more information from the bad request? Try adding this to the table controller
protected override void Initialize(HttpControllerContext controllerContext)
{
controllerContext.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
I'm currently developing a side-project, which will consist of a Database, Web API, and then different Apps on top which consume the restful API.
I've started thinking about User accounts and how to make these secure. Currently, as a standard, I have the following model in the Data Layer:
public int Id { get; set; }
public string Username { get; set; }
public string Full_Name { get; set; }
public string Password { get; internal set; }
public string Salt { get; internal set; }
Now, obviously, when someone makes a request for /Users/{id}, the User associated with that Id is returned. However, I don't want to return the Password or Salt, so really don't want those to be part of the User model.
I have toyed with the idea of creating a different, internal-only model for UserDetails, and shipping the Password/Salt, etc off into that. However, I hit the snag of, when signing up to the service, how do I get a desired password from the user to the API?
There's probably a really simple implementation of what I want to do, but I can't think of one right now. Any help would be greatly appreciated!
You should use a special view model without the password property for this purpose. Then inside your API you will map between your data model and the view model and return the view model out from your Web API method. Same stands true for the Salt property as well.
Say you have the following Contact DTO. Address/PhoneNumber/EmailAddress/WebSiteAddress classes are simple DTOs as well (just data no behavior)
public class Contact
{
public Address[] Addresses { get; set; }
public PhoneNumber[] PhoneNumbers { get; set; }
public EmailAddress[] EmailAddresses { get; set; }
public WebSiteAddress[] WebSiteAddresses { get; set; }
}
How should I model DTOs to allow implementing the following behavior?
The client can submit a request that will
add a phone number, update two phone numbers and delete two add two
add two email addresses, update one email address and delete three
add three website addresses, update two website addresses and delete
two. You get the idea.
One option is to add an Action attribute to each Address / PhoneNumber / EmailAddress / WebSiteAddress.
Then the code the update addresses look like this:
var addressesToUpdate = serviceContact.Addresses.Where(x => x.AddressAction.ToUpper() == "UPDATE");
var addressesToAdd = serviceContact.Addresses.Where(x => x.AddressAction.ToUpper() == "ADD");
var addressesToDelete = serviceContact.Addresses.Where(x => x.AddressAction.ToUpper() == "DELETE").Select(x => x.AddressId);
Repeating this for all other lists will probably create duplication.
My question is:
How should I model service DTOs with updatable lists while avoiding duplication?
Generally I'll try to keep my writes idempotent which means it should have the same side-effect (i.e. end result) of calling it when you have no records or all records (i.e. Store or Update).
Basically this means that the client sends the complete state: i.e.
What entries don't exist => gets created,
The entities that already exist => get updated,
Whilst the entities that aren't in the request DTO => get deleted.
OrmLite's db.Save() command has nice support for this where it detects if a record(s) already exist and will issue an UPDATE otherwise will INSERT.
You can use ETags with conditional requests instead of providing the complete state. Use the ETag as a version of the list and change it each time the list changes. On the client side, use the ETag to request an update using the If-None-Match http header and be prepared to receive a 402 Precondition Failed status if the list changed while the request was sent.
I have been reading some artices about using the RelationshipManager to gain access to the entries that have related data. It is still unclear to me what the best way to audit when an entity whose related data is added or updated.
Sample Classes:
public class Rfi
{
public Guid Id {get;set;}
public string Number {get;set;}
public virtual ICollection<Attachment> Attachments {get;set;}
}
public Class Attachment
{
public Guid Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public string FileName {get;set;}
public string Path {get;set;}
}
Sample Mappings:
public class RfiMapping: EntityTypeConfiguration<Rfi>
{
public Rfimapping()
{
HasMany(r => r.Attachments).WithMany().Map(m =>
{
m.MapLeftKey("RfiId");
m.MapRightKey("AttachmentId");
m.ToTable("Rfi_Attachments");
});
}
}
I am using the Repository and Unit Of Work patterns. My UoW inherits from DbContext. A repository call may look like this:
public void AddAttachmentToRfi(Attachment attachment, Guid rfiId)
{
var rfi = _rfiRepository.FindById(rfiId);
rfi.Attachments.Add(attachment);
_rfiRepository.UnitOfWork.Commit();
}
Is it possible , in an overridden SaveChanges method, to figure out that an Attachment entity was added to an Rfi entity? When I traverse the, say ChangeTracker.Entries, I am not seeing its state being set to modified. Which makes sense, because I am only adding to the relationships and not the entity directly.
I know to cast my DbContext to an IObjectContextAdapter, but I am not sure what I need to do with the RelationshipManager to get the changes made to any of the relationships. I am also curious to know if I were to update an Attachment's Description property later on, if I can still see what changes were made to any related data.
My goal with this is, the user interface for the Rfi allows users to attach files (Rfi is obviously not the only entity that can have attachments). I need to show a history of everything that happens to an Rfi. This means if an attachment is added I need to audit it. If the attachment's data is updated, I need to audit those changes and show that they were updated via the Rfi interface. This may get complicated if that attachment is shared with another entity, but I will cross that road later.
As you say you are not changing any of the entities only the relationship between them.
EF will then convert this to an insert into or delete from the Rfi_Attachments table.
One way to audit this is to add a database trigger that writes an entry to a log table, each time an entry is added or deleted.
Consider the following property UserName of a Model Class. You can see that the validation criteria are added over it manually.
[Required]
[StringLength(100, MinimumLength = 6)]
public string UserName { get; set; }
Now again consider the following code:
public string UserName { get; set; }
The same property without the validators. Now when I am generating the model class using Entity Framework Database first approach I am getting the later result (means a property without having validators). But in the database there are constraints added over each attribute.
So is there any tool/way that I can use those constraints and generate the model class having properties like shown in code 1 (that is property with validators).
No there is no ready to use tool which would add these attributes for you. You can modify T4 template to create these attributes for you but for that you need to understand how EF metadata are stored. You can add attributes yourselves manually in buddy classes.