I have the following property:
public virtual String Firstname { get; set; }
and i only want to be able to write to the field IF it is currently null (not set), it this possible to achieve through DataAnnotations?
Data annotations are metadata used for example for validation so you can create custom data annotation to validate property value but the validation cannot ensure that your property will not be set if it already has value. That is code which should be part of property's setter itself like:
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set
{
if (_firstName != null) throw ...
_firstName = value;
}
}
If by data annotations you simply mean attributes then the answer is: It can be achieved with attributes BUT you need something which will implement some logic related to the attribute. This is usually done through Aspect oriented programming (AOP) where you will create marker attribute which will be used by some complex API. The API will based on that attribute wrap your class with custom code adding the if statement either at compile time (for example PostSharp) or at runtime (for example Unity, Spring.NET).
Another way to achive this, by me more elegant, do not implement set for the property, but only get
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
}
and have a function:
public void SetFirstName(string FirstName)
{
_firstName = FirstName;
}
So no exception, no return value handling. You have one property the only retrieve value, and one function, or constructor (why not, depends on your architecture, it's hard to deduct from post) that initialized it only once.
By me the API of your object will be more clear and straightforward in this way.
Regards.
There is also a specific DataAnnotation syntax to achieve this:
[DisplayFormat(NullDisplayText = "some string")]
public virtual String Firstname { get; set; }
Related
I am wondering what is a "good practice" for setting properties that are not mapped in the database. I am working with EF Core, but this is really more of a question of design. Imagine I have a following class:
class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public string Name { get; set; }
...
}
Where Name would be computed after fetching the the FirstName and LastName from the database. I am trying to prevent calling the getter for Name without setting the property first.
I know I could do something like
class User
{
...
private string _name = null;
[NotMapped]
public string Name {
get
{
if (_name == null)
_name = $"{FirstName} {LastName}";
return _name;
}
}
...
}
But this gets really messy when multiple properties need to be set this way and when they are obtained in a more complicated way than this one-liner.
For now I wrote a function SetAllProperties() which sets all NotMapped properties, however I don't consider it a good solution since there is a risk of forgetting
To update it when new NotMapped properties are added
To actually call it before accessing the properties
Is an interface a way to go? How should it look like? Or is there some "standard" way of dealing with this? I wasn't able to find anything useful on this topic.
i have 50 properties in model name 'student' and im trying to set all properties NULL values to "" to prevent error messages in case of NULL.is there c# method that can do that?
thank you for your help.
You could initialize each property in your model (pretty simple with search/replace):
public string PropertyName { get; set; } = "";
However, I would question whether it is better to handle your NULL scenarios. It is pretty simple (model.PropertyName?.Method()).
Use a backing field for each.
In the get for each property, coalesce via return this.field ?? string.Empty;
Change the model to have fail safe check, as below.Will below work for you?
public class Student
{
private string _Name;
public string Name
{
get => string.IsNullOrWhiteSpace(_Name) ? string.Empty : _Name;
set => _Name = value;
}
//todo: rest of properties
}
I have a typical web API with a couple of PUT/UPDATE endpoints. These endpoints simply call the underlying service, and do the update.
The service layer, has the typical signature such as Object Update(Object object). What I then do is I basically run the following pseudo code:
var dbobject = _db.Object.Find(object.Id);
dbobject.Field1 = object.Field1;
dbobject.Field2 = object.Field2;
// continue for all fields
_db.SaveChanges();
return GetObjectById(object.Id);
However, this provides a challenge for me.
Lets say we have a consumer of our API. This consumer calls my PUT endpoint (/api/Object/{id}), and the payload is the updated Object.
However, lets say that the object we put don't know about example Field4, then this value would be NULL after the update has been run.
My question is:
What do you do about all those fields the payload does NOT contain?
How do you handle not setting values to NULL you don't expect to be
NULL afterwards?
As one of the possible ways, here can be used mix of NotifyPropertyChanged with automapper
The Idea is to store in DTO object which fields exactly was set, and which stays filled with default value. And use collected data in mapping.
For example DTO object will be
public class Dto
{
private List<string> Changed = new List<string>();
public bool IsChanged(string field) => Changed.Contains(field);
private int _age;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
// IMPORTANT: field name should fit main object field name
Changed.Add("Name");
}
}
public int Age
{
get { return _age; }
set
{
_age = value;
Changed.Add("Age");
}
}
}
I used Next class for test
public class Human
{
public string Name { get; set; } = "DEFAULT";
public int Age { get; set; } = -1;
}
and automapper configuration will looks like
cfg.CreateMap<Dto, Human>()
.ForAllMembers(s=> s.Condition(d=>d.IsChanged(s.DestinationMember.Name)));
This is a simple example. But it still doesn't prevent to use function IsChanged for some complex/specific logic, use not just a strings but Expressions / MethodInfo, or add custom attributes and use them in automapper configuration (DestinationMember is MethodInfo)
Append
Instead of complex DTO object the information about passed field you can get from Request.Properties in your controller (key ms_querynamevaluepairs value of type Dictionary<string, string>).
I have a serialization mechanism in place that works on the private fields to determine what should be serialized and what not. The main idea behind the approach is to only serialize the "essence" of the data.
Example:
public class Person {
private readonly string _firstName;
private readonly string _lastName;
public C1(string firstName, string lastName) {
_firstName = firstName;
_lastName = lastName;
}
public string FirstName { get { return _firstName; } }
public string LastName { get { return _lastName; } }
public string FullName { get { return _firstName + " " + _lastName; } }
}
A serialized example object would then look like this (JSON):
{ "firstName": "John", "lastName": "Doe" }
As you can see, serializing based on fields ensures that FullName is not serialized.
This mechanism was in place for a while now and worked flawlessly. However, with the new read-only auto properties in C# 6.0, the fields have an awkward name like e.g. <FirstName>k__BackingField.
Of course, I can update my serialization code to extract the actual property name from the backing field and use that name during serialization. What I want to know: Is this a robust solution? Or is the naming of the generated backing fields subject to change?
Note: The reason for this approach is that model classes can remain serialization-agnostic like that. I know that I could also use the [JsonIgnore] attributes to achieve the same, but I don't want to add such attributes to my model classes.
It sounds like you are basing your correlation of backing field to property by a naming convention. Menaing if you have a private field _name and a property Name then the field must be the backing field for that property.
Is this a robust solution?
No - a robust solution would be to implement serialization for each type since only it knows for certain which fields tie to which property.
Or is the naming of the generated backing fields subject to change?
This is an implementation detail - MS could decide to change the naming convention however they see fit.
Another approach, rather than struggling with the inanities associated wit reflecting over the auto properties, might be to use the ContractResolver.
I'm going to omit any examples since the link I provided has 3 practical examples that walk you through the necessaries.
I have an Address object defined simply as follows:
public class Address
{
public string StreetNumber { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
Fairly simple. On the advice an answer to another question I asked, I am referring to this blog post when databinding my UI to an object of type Person (which contains an Address MailingAddress field).
The problem is that the IDataError interface method isn't validating any of the properties of the Address type.
public string this[string columnName]
{
get
{
string result = null;
// the following works fine
if(columnName == "FirstName")
{
if (string.IsNullOrEmpty(this.FirstName))
result = "First name cannot be blank.";
}
// the following does not run
// mostly because I don't know what the columnName should be
else if (columnName == "NotSureWhatToPutHere")
{
if (!Util.IsValidPostalCode(this.MailingAddress.PostalCode))
result = "Postal code is not in a know format.";
}
return result;
}
}
So, obviously I don't know what the columnName will be... I've stepped through it and it has never been anything other than any of the public properties (of intrinsic types). I've even tried running and breaking on a statement like:
if (columnName.Contains("Mailing") || columnName.Contains("Postal"))
System.Windows.Forms.MessageBox.Show(columnName);
All to no avail.
Is there something I'm missing?
You need to define IErrorInfo on all the classes that you want to supply error messages for.
Take a look at my answer here.
This explains how to use a modelbinder to add 'class-level' checking of your model without having to use IDataError - which as you have seen here can be quite clumsy. It still lets you use [Required] attributes or any other custom validation attributes you have, but lets you add or remove individual model errors. For more on how to use data annotations I highly recommend this post from Scott Gu.