Let's say we got a class like this one:
public class Person
{
[JsonConstructor]
public Person(string name, DayOfWeek bornOnDay) => (Name, BornOnDay) = (name, bornOnDay);
public string Name { get; protected set; }
public DayOfWeek BornOnDay { get; protected set; }
}
And an endpoint like this one:
[HttpPost]
[Route("api/people")]
public IHttpActionResult PostPerson([FromBody]List<Person> people)
{
// whatever
}
I've noticed that if I make a typo in enum type when making a request - no error occurs, only the object that has the erroneous enum won't be deserialized.
For instance, the request body may look like this:
[{"name":"John", "bornOnDay":"Moonday",},
{"name":"Mark", "bornOnDay":"Friday",},]
Endpoint will receive the list containing one Person, Mark, born on Friday.
I would like to make the post operation either happen completely, or fail, not with only with the objects without enum typos.. Is there a way to do it, without receiving a string instead of DayOfWeek, and then using Enum.TryParse(...) to determine that the input was erroneous?
Edit:
I actually want the error to occur, and be detectable, so I can return 400 code to the client.
you can do like this , you can create enum value from string you have inputted
public class Person
{
private string day;
[JsonConstructor]
public Person(string name, string bornOnDay){
this.Name = name;
this.day = bornOnDay;
}
public string Name { get; protected set; }
public DayOfWeek BornOnDay {
get {
DayOfWeek weekday;
if(Enum.TryParse(day, true, out weekday))
return weekday;
else
return DayOfWeek.None;//add none if no able to parse
}
}
Note : None is added according to Null Object Pattern to avoid issues related to null value in system.
What about this:
public class Person
{
[JsonProperty]
public string Name { get; protected set; }
[JsonProperty]
private string _BornOnDay { set {
//try parse the string, if not successful, throw a nicely
//formatted error with the original string and what you expect,
//if parse is successful, set the value to BornOnDay;
}}
[JsonIgnore]
public DayOfWeek BornOnDay { get; protected set; }
}
Not sure about the JsonConstructor attribute, never needed to use it. If you do need it and if I understand it correctly you can have something similar with it. Deserializer should give a string into constructor, and then inside of it, you do parsing logic for the enum yourself.
I'm going by this tutorial and trying to figure out how to have a DataMember without an auto property. Basically I have a field is a date time in epoch format and I want the property to be a DateTime so I'm trying to do the conversion in the property's get. I'm not sure how to format this exactly.
Since Code was requested please look at the following. :
// The date looks like this in the JSON
"someEpochDateTime": 1428785212000,
// I thought I could work around it using the following code, however
// I get a warning saying someEpochDateTime is never set.
[DataMember(Name = "someEpochDateTime")]
private long someEpochDateTime;
public DateTime test
{
get { return DateTimeConverter.FromUnixTime(someEpochDateTime); }
}
Using FromUnixTime
like this you can create datereturn property this will return date
[DataContract]
public class Mycontractclass
{
// Apply the DataMemberAttribute to the property.
[DataMember]
public DateTime datereturn
{
get
{
return this.dateCreated.HasValue
? this.dateCreated.Value
: DateTime.Now;
}
set { this.dateCreated = value; }
}
private DateTime? dateCreated = null;
}
Apparently my last edit actually works as a solution, I just get a compiler warning for some reason.
[DataMember(Name = "someEpochDateTime")]
private long someEpochDateTime;
public DateTime test
{
get { return DateTimeConverter.FromUnixTime(someEpochDateTime); }
}
I try save complex class inside another class. TypeMask contained inside Entity. TypeMask overloads ToString method, and when time to save Entity comes, a want automaticaly save Mask prop in string form, and when I need load Entity class back automaticaly convert this string to TypeMask(constructor of TypeMask can build TypeMask using string). So what have I overload or from what have I inherit to make it real?
public class Entity
{
[Key]
public int Id { get; set; }
public TypeMask Mask { get; private set; }
}
Here's a way to do this:
public class Entity
{
private TypeMask _typeMask;
[Key]
public int Id { get; set; }
public string TypeMaskString { get; set; }
[NotMapped]
public TypeMask Mask
{
get
{
if (this._typeMask == null && !string.IsNullOrEmpty(TypeMaskString))
{
this._typeMaks = new TypeMask(this.TypeMaskString);
// Or some other way to create a TypeMask from string.
}
return this._typeMask;
}
set
{
this._typeMask = value;
this.TypeMaskString = value.ToString();
}
}
}
There are some things to keep in mind here. When your code makes modifications to a TypeMask object you have to set the object again to update TypeMaskString. Of course, this is error-prone and elaborate, so you want to make sure that TypeMask can be modified through only one method (maybe a method in Entity).
The alternative is to have a property like this (skipping null checks for brevity)
public string TypeMaskString
{
get
{
return this.TypeMask.ToString();
}
set
{
this.TypeMask = new TypeMask(this.TypeMaskString);
}
}
Now the TypeMask object can be modified and TypeMaskString will always return an up-to-date value. But this may hit performance because it potentially converts TypeMask to and from string many times. More often than you may suspect, because EF's change tracker will always read TypeMaskString when it executes DetectChanges, which is a process that runs repeatedly.
I'm currently finishing work on object change log functionality and would like to polish few things. Since we have a lot of web forms/reports where historical data should appear, I'm wondering if there is a way to implement that without changing controls/reports.
Currently, I have this situation:
public class Foo {
public string Property1 { get; set; }
public DateTime CreatedDate { get; set;}
public string GetHistoricalValue(string propertyName)
{
HistoryHelper historyHelper = CreateHistoryHelper(this);
return historyHelper.GetHistoricalValue(propertyName, CreatedDate);
}
...
public class HistoryHelper {
public string GetHistoricalValue(string propertyName, DateTime date) {
...
So, when someone wants to fetch historical data for Property1:
string historicalValue = fooInstance.GetHistoricalValue("Property1");
It's obvious that this approach requires a lot of changes in current application.
Is there a way to make Foo class returns historical value when I access Property1 in regular way:
string historicalValue = fooInstance.Property1;
Something like dynamically generating subclass with overriden properties or some other solution?
Is this possible?
INITIAL ANSWER
Something like this:
public class Foo {
public bool HistoricalMode { get; set; }
private string _property1;
public string Property1 {
get {
if (HistoricalMode) {
return GetHistoricalValue("Property1");
} else {
return _property1;
}
set {
if (HistoricalMode){
throw new NotSupportedException("Updates not possible in historical mode.");
} else {
_property1 = value;
}
}
}
public DateTime CreatedDate {
get {
// Similar pattern as above
}
set {
// Similar pattern as above
}
}
public string GetHistoricalValue(string propertyName) {
HistoryHelper historyHelper = CreateHistoryHelper(this);
return historyHelper.GetHistoricalValue(propertyName, CreatedDate);
}
}
Basically the idea is to keep a boolean in your objects which indicates in the object is in 'history mode'. If so, use your helper method. If not, normal properties getters/setters apply.
UPDATE
The solution to this question I think would require a change in your framework (if you have a single framework for all your applications). I would seek the solution in the way you are loading your objects. Hopefully you can detect when an object is required in 'historical mode' and when in 'normale mode'. Where you now 'just read' the object (record) from the database, in historical mode you need to compose the original object (from when the change happened) from your change log functionality. That way, all your current application can (hopefully) stay the way they are. The 'only' change you need to do is at the repository class.
This is all just speculation btw.
Can you easily affect how Foo instances are created? If so, you can for example create derived class HistoricalFoo : Foo, make Property1 virtual and use its getter to change its behaviour. Then use HistoricalFoo whenever you need historical data. It is not a very clean object model, but can get the job done.
public class Foo
{
protected string _property1;
public virtual string Property1
{
get { return _property1; }
set { _property1 = value; }
}
public DateTime CreatedDate { get; set;}
/* ... */
}
public class HistoricalFoo : Foo
{
public override string Property1
{
get
{
return GetHistoricalValue("Property1");
}
}
}
If this is not applicable, it's possible to embed some decision logic into the Property1 getter. In this scenario, you would have to change the internal state of the Foo instance - for example by setting a boolean flag IsInHistoryMode. Changing object states can be very tricky though, expecially in multithreaded environment.
public class Foo
{
public bool IsInHistoryMode { get; set; }
protected string _property1;
public virtual string Property1
{
get
{
if(IsInHistoryMode)
{
return GetHistoricalValue("Property1");
}
return _property1;
}
set
{
_property1 = value;
}
}
public DateTime CreatedDate { get; set;}
/* ... */
}
Does any one know how I can specify the Default value for a DateTime property using the System.ComponentModel DefaultValue Attribute?
for example I try this:
[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated { get; set; }
And it expects the value to be a constant expression.
This is in the context of using with ASP.NET Dynamic Data. I do not want to scaffold the DateCreated column but simply supply the DateTime.Now if it is not present. I am using the Entity Framework as my Data Layer
Cheers.
You cannot do this with an attribute because they are just meta information generated at compile time. Just add code to the constructor to initialize the date if required, create a trigger and handle missing values in the database, or implement the getter in a way that it returns DateTime.Now if the backing field is not initialized.
public DateTime DateCreated
{
get
{
return this.dateCreated.HasValue
? this.dateCreated.Value
: DateTime.Now;
}
set { this.dateCreated = value; }
}
private DateTime? dateCreated = null;
Add below to the DateTime property
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
I have tested this on EF core 2.1
Here you cannot use either Conventions or Data Annotations. You must use the Fluent API.
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
}
}
Official doc
There's no reason I can come up with that it shouldn't be possible to do through an attribute. It might be in Microsoft's backlog. Who knows.
The best solution I have found is to use the defaultValueSql parameter in the code first migration.
CreateTable(
"dbo.SomeTable",
c => new
{
TheDateField = c.DateTime(defaultValueSql: "GETDATE()")
});
I don't like the often reference solution of setting it in the entity class constructor because if anything other than Entity Framework sticks a record in that table, the date field won't get a default value. And the idea of using a trigger to handle that case just seems wrong to me.
It is possible and quite simple:
for DateTime.MinValue
[System.ComponentModel.DefaultValue(typeof(DateTime), "")]
for any other value as last argument of DefaultValueAttribute specify string that represent desired DateTime value.
This value must be constant expression and is required to create object (DateTime) using TypeConverter.
Just found this looking for something different, but in the new C# version, you can use an even shorter version for that:
public DateTime DateCreated { get; set; } = DateTime.Now;
A simple solution if you are using the Entity Framework is the add a partical class and define a constructor for the entity as the framework does not define one. For example if you have an entity named Example you would put the following code in a seperate file.
namespace EntityExample
{
public partial class Example : EntityObject
{
public Example()
{
// Initialize certain default values here.
this._DateCreated = DateTime.Now;
}
}
}
I think the easiest solution is to set
Created DATETIME2 NOT NULL DEFAULT GETDATE()
in column declaration and in VS2010 EntityModel designer set corresponding column property StoreGeneratedPattern = Computed.
Creating a new attribute class is a good suggestion. In my case, I wanted to specify 'default(DateTime)' or 'DateTime.MinValue' so that the Newtonsoft.Json serializer would ignore DateTime members without real values.
[JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore )]
[DefaultDateTime]
public DateTime EndTime;
public class DefaultDateTimeAttribute : DefaultValueAttribute
{
public DefaultDateTimeAttribute()
: base( default( DateTime ) ) { }
public DefaultDateTimeAttribute( string dateTime )
: base( DateTime.Parse( dateTime ) ) { }
}
Without the DefaultValue attribute, the JSON serializer would output "1/1/0001 12:00:00 AM" even though the DefaultValueHandling.Ignore option was set.
Simply consider setting its value in the constructor of your entity class
public class Foo
{
public DateTime DateCreated { get; set; }
public Foo()
{
DateCreated = DateTime.Now;
}
}
using System.ComponentModel.DataAnnotations.Schema;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn { get; private set; }
I needed a UTC Timestamp as a default value and so modified Daniel's solution like this:
[Column(TypeName = "datetime2")]
[XmlAttribute]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
[Display(Name = "Date Modified")]
[DateRange(Min = "1900-01-01", Max = "2999-12-31")]
public DateTime DateModified {
get { return dateModified; }
set { dateModified = value; }
}
private DateTime dateModified = DateTime.Now.ToUniversalTime();
For DateRangeAttribute tutorial, see this awesome blog post
There is a way. Add these classes:
DefaultDateTimeValueAttribute.cs
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Custom.Extensions;
namespace Custom.DefaultValueAttributes
{
/// <summary>
/// This class's DefaultValue attribute allows the programmer to use DateTime.Now as a default value for a property.
/// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class DefaultDateTimeValueAttribute : DefaultValueAttribute
{
public string DefaultValue { get; set; }
private object _value;
public override object Value
{
get
{
if (_value == null)
return _value = GetDefaultValue();
return _value;
}
}
/// <summary>
/// Initialized a new instance of this class using the desired DateTime value. A string is expected, because the value must be generated at runtime.
/// Example of value to pass: Now. This will return the current date and time as a default value.
/// Programmer tip: Even if the parameter is passed to the base class, it is not used at all. The property Value is overridden.
/// </summary>
/// <param name="defaultValue">Default value to render from an instance of <see cref="DateTime"/></param>
public DefaultDateTimeValueAttribute(string defaultValue) : base(defaultValue)
{
DefaultValue = defaultValue;
}
public static DateTime GetDefaultValue(Type objectType, string propertyName)
{
var property = objectType.GetProperty(propertyName);
var attribute = property.GetCustomAttributes(typeof(DefaultDateTimeValueAttribute), false)
?.Cast<DefaultDateTimeValueAttribute>()
?.FirstOrDefault();
return attribute.GetDefaultValue();
}
private DateTime GetDefaultValue()
{
// Resolve a named property of DateTime, like "Now"
if (this.IsProperty)
{
return GetPropertyValue();
}
// Resolve a named extension method of DateTime, like "LastOfMonth"
if (this.IsExtensionMethod)
{
return GetExtensionMethodValue();
}
// Parse a relative date
if (this.IsRelativeValue)
{
return GetRelativeValue();
}
// Parse an absolute date
return GetAbsoluteValue();
}
private bool IsProperty
=> typeof(DateTime).GetProperties()
.Select(p => p.Name).Contains(this.DefaultValue);
private bool IsExtensionMethod
=> typeof(DefaultDateTimeValueAttribute).Assembly
.GetType(typeof(DefaultDateTimeExtensions).FullName)
.GetMethods()
.Where(m => m.IsDefined(typeof(ExtensionAttribute), false))
.Select(p => p.Name).Contains(this.DefaultValue);
private bool IsRelativeValue
=> this.DefaultValue.Contains(":");
private DateTime GetPropertyValue()
{
var instance = Activator.CreateInstance<DateTime>();
var value = (DateTime)instance.GetType()
.GetProperty(this.DefaultValue)
.GetValue(instance);
return value;
}
private DateTime GetExtensionMethodValue()
{
var instance = Activator.CreateInstance<DateTime>();
var value = (DateTime)typeof(DefaultDateTimeValueAttribute).Assembly
.GetType(typeof(DefaultDateTimeExtensions).FullName)
.GetMethod(this.DefaultValue)
.Invoke(instance, new object[] { DateTime.Now });
return value;
}
private DateTime GetRelativeValue()
{
TimeSpan timeSpan;
if (!TimeSpan.TryParse(this.DefaultValue, out timeSpan))
{
return default(DateTime);
}
return DateTime.Now.Add(timeSpan);
}
private DateTime GetAbsoluteValue()
{
DateTime value;
if (!DateTime.TryParse(this.DefaultValue, out value))
{
return default(DateTime);
}
return value;
}
}
}
DefaultDateTimeExtensions.cs
using System;
namespace Custom.Extensions
{
/// <summary>
/// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. See usage for more information.
/// </summary>
public static class DefaultDateTimeExtensions
{
public static DateTime FirstOfYear(this DateTime dateTime)
=> new DateTime(dateTime.Year, 1, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
public static DateTime LastOfYear(this DateTime dateTime)
=> new DateTime(dateTime.Year, 12, 31, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
public static DateTime FirstOfMonth(this DateTime dateTime)
=> new DateTime(dateTime.Year, dateTime.Month, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
public static DateTime LastOfMonth(this DateTime dateTime)
=> new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month), dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
}
}
And use DefaultDateTimeValue as an attribute to your properties. Value to input to your validation attribute are things like "Now", which will be rendered at run time from a DateTime instance created with an Activator. The source code is inspired from this thread: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. I changed it to make my class inherit with DefaultValueAttribute instead of a ValidationAttribute.
I faced the same issue, but the one which works for me best is below:
public DateTime CreatedOn { get; set; } = DateTime.Now;
In C# Version 6 it's possible to provide a default value
public DateTime fieldname { get; set; } = DateTime.Now;
Using EntityTypeConfiguration, I get it like this:
public class UserMap : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
//throw new NotImplementedException();
builder.Property(u => u.Id).ValueGeneratedOnAdd();
builder.Property(u => u.Name).IsRequired().HasMaxLength(100);
builder.HasIndex(u => u.Email).IsUnique();
builder.Property(u => u.Status).IsRequired();
builder.Property(u => u.Password).IsRequired();
builder.Property(u => u.Registration).HasDefaultValueSql("getdate()");
builder.HasMany(u => u.DrawUser).WithOne(u => u.User);
builder.ToTable("User");
}
}
Using the Fluent API, in OnModelCreating function in your Context class add following.
builder.Property(u => u.CreatedAt).ValueGeneratedOnAdd();
builder.Property(u => u.UpdatedAt).ValueGeneratedOnAddOrUpdate();
Note I'm using a separate type configuration class. If you did right in the function would be like:
builder.Enitity<User>().Property(u => u.CreatedAt).ValueGeneratedOnAdd();
public DateTime DateCreated
{
get
{
return (this.dateCreated == default(DateTime))
? this.dateCreated = DateTime.Now
: this.dateCreated;
}
set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);
How you deal with this at the moment depends on what model you are using Linq to SQL or EntityFramework?
In L2S you can add
public partial class NWDataContext
{
partial void InsertCategory(Category instance)
{
if(Instance.Date == null)
Instance.Data = DateTime.Now;
ExecuteDynamicInsert(instance);
}
}
EF is a little more complicated see http://msdn.microsoft.com/en-us/library/cc716714.aspx for more info on EF buisiness logic.
I know this post is a little old, but a have a suggestion that may help some.
I used an Enum to determine what to set in the attribute constructor.
Property declaration :
[DbProperty(initialValue: EInitialValue.DateTime_Now)]
public DateTime CreationDate { get; set; }
Property constructor :
Public Class DbProperty Inherits System.Attribute
Public Property InitialValue As Object
Public Sub New(ByVal initialValue As EInitialValue)
Select Case initialValue
Case EInitialValue.DateTime_Now
Me.InitialValue = System.DateTime.Now
Case EInitialValue.DateTime_Min
Me.InitialValue = System.DateTime.MinValue
Case EInitialValue.DateTime_Max
Me.InitialValue = System.DateTime.MaxValue
End Select
End Sub
End Class
Enum :
Public Enum EInitialValue
DateTime_Now
DateTime_Min
DateTime_Max
End Enum
I think you can do this using StoreGeneratedPattern = Identity (set in the model designer properties window).
I wouldn't have guessed that would be how to do it, but while trying to figure it out I noticed that some of my date columns were already defaulting to CURRENT_TIMESTAMP() and some weren't. Checking the model, I see that the only difference between the two columns besides the name is that the one getting the default value has StoreGeneratedPattern set to Identity.
I wouldn't have expected that to be the way, but reading the description, it sort of makes sense:
Determines if the corresponding column in the database will be auto-generated during insert and update operations.
Also, while this does make the database column have a default value of "now", I guess it does not actually set the property to be DateTime.Now in the POCO. This hasn't been an issue for me as I have a customized .tt file that already sets all of my date columns to DateTime.Now automatically (it's actually not hard to modify the .tt file yourself, especially if you have ReSharper and get a syntax highlighting plugin. (Newer versions of VS may already syntax highlight .tt files, not sure.))
The issue for me was: how do I get the database column to have a default so that existing queries that omit that column will still work? And the above setting worked for that.
I haven't tested it yet but it's also possible that setting this will interfere with setting your own explicit value. (I only stumbled upon this in the first place because EF6 Database First wrote the model for me this way.)
below works in .NET 5.0
private DateTime _DateCreated= DateTime.Now;
public DateTime DateCreated
{
get
{
return this._DateCreated;
}
set { this._DateCreated = value; }
}
You can also consider using the DatabaseGenerated attribute, example
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime DateCreated { get; set; }
https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations
I also wanted this and came up with this solution (I'm only using the date part - a default time makes no sense as a PropertyGrid default):
public class DefaultDateAttribute : DefaultValueAttribute {
public DefaultDateAttribute(short yearoffset)
: base(DateTime.Now.AddYears(yearoffset).Date) {
}
}
This just creates a new attribute that you can add to your DateTime property.
E.g. if it defaults to DateTime.Now.Date:
[DefaultDate(0)]