I want to execute a msbuild script using a specific culture (en-US) as one of the tasks is trying to call a web service using aDateTime.ToShortDateString() as a parameter, and my current culture is uncompatible with the server's (english) format.
How to do it without altering my regional settings ?
I ended up by creating a specific task for changing the current culture like this:
public class ChangeCulture : Task
{
[Required]
public string Culture { get; set; }
public override bool Execute()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(Culture);
return true;
}
}
If you want to change the culture of your entire application then you can set the culture when the application starts like this:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);
You can read about setting it on MSDN.
Given your example though, that may be overkill. If you are trying to change just the ToShortDateString() to en-US there may be a more simple way. You can use the ToString() method instead and pass in a specific format, for example you can do:
aDateTime.ToString("MM/dd/yyyy");
More specifically you can use the pre-defined culture info with System.Globalization like this:
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-US");
string datePattern = culture.DateTimeFormat.ShortDatePattern;
string shortDate = aDateTime.ToString(datePattern);
Related
I am implementing a custom IBsonSerializer with the official MongoDB driver (C#). I am in the situation where I must serialize and deserialize a Guid.
If I implement the Serialize method as follow, it works:
public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
BsonBinaryData data = new BsonBinaryData(value, GuidRepresentation.CSharpLegacy);
bsonWriter.WriteBinaryData(data);
}
However I don't want the Guid representation to be CSharpLegacy, I want to use the standard representation. But if I change the Guid representation in that code, I get the following error:
MongoDB.Bson.BsonSerializationException: The GuidRepresentation for the writer is CSharpLegacy, which requires the subType argument to be UuidLegacy, not UuidStandard.
How do I serialize a Guid value using the standard representation?
Old question but in case someone finds it on google like I did...
Do this once:
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
For example, in a Web Application/Web API, your Global.asax.cs file is best place to add it once
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
//Other code...below
}
}
If you don't want to modify the global setting BsonDefaults.GuidRepresentation (and you shouldn't, because modifying globals is a bad pattern), you can specify the setting when you create your collection:
IMongoDatabase db = ???;
string collectionName = ???;
var collectionSettings = new MongoCollectionSettings {
GuidRepresentation = GuidRepresentation.Standard
};
var collection = db.GetCollection<BsonDocument>(collectionName, collectionSettings);
Then any GUIDs written to the collection will be in the standard format.
Note that when you read records from the database, you will get a System.FormatException if the GUID format in the database is different from the format in your collection settings.
It looks like what's happening is when you are not explicitly passing the GuidRepresentation to BsonBinaryData constructor, it defaults to passing GuidRepresentation.Unspecified and that ultimately maps to GuidRepresentation.Legacy (see this line in the source)
So you need to explicitly pass the guidRepresentation as a third argument to BsonBinaryData set to GuidRepresentation.Standard.
edit: As was later pointed out, you can set BsonDefaults.GuidRepresentation = GuidRepresentation.Standard if that's what you always want to use.
What's the best way to set default properties for new entities in DDD? Also, what's the best way to set default states for complex properties (eg. collections)?
My feeling is that default values should be in the models themselves as they are a form of business rule ("by default, we want X's to be Y & Z"), and the domain represents the business. With this approach, maybe a static "GetNew()" method on the model itself would work:
public class Person {
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public bool IsAlive { get; set; }
public List Limbs { get; set; }
public static Person GetNew() {
return new Person() {
IsAlive = true,
Limbs = new List() { RightArm, LeftArm, RightLeg, LeftLeg }
}
}
}
Unfortunately in our case, we need the collection property to be set to all members of another list, and as this model is decoupled from its Repository/DbContext it doesn't have any way of loading them all.
Crappy solution would be to pass as parameter :
public static Person GetNew(List<Limb> allLimbs) {
return new Person() {
IsAlive = true,
Limbs = allLimbs
}
}
Alternatively is there some better way of setting default values for simple & complex model properties?
This is an instance of the factory pattern in DDD. It can either be a dedicated class, such as PersonFactory, or a static method, as in your example. I prefer the static method because I see no need to create a whole new class.
As far as initializing the collection, the GetNew method with the collection as a parameter is something I would go with. It states an important constraint - to create a new person entity you need that collection. The collection instance would be provided by an application service hosting the specific use case where it is needed. More generally, default values could be stored in the database, in which case the application service would call out to a repository to obtain the required values.
Take a look at the Static Builder in Joshua Bloch's Effective Java (Second Edition). In there, you have a static builder class and you chain calls to set properties before construction so it solves the problem of either having a constructor that takes a ton of arguments or having to put setters on every property (in which case, you effectively have a Struct).
I'm using Nlog to write some logging to a textfile. Partial nlog.config:
<target name="file" xsi:type="File" fileName="${basedir}/MBWRunner_log.txt"
layout="${date} (${level}): ${message}
Exception: ${exception:format=Method, ToString}"/>
Lines in the logfile look like this:
0001-01-01 00:00:00 (Trace): MBWRunner started
As you can see the date and time are all 0. I have tested {longdate} and {date:format=yyyyMMddHHmmss} with the same result.
The application is a console app, run from an elevated commandline.
Any clues?
[EDIT] I have tested this on 2 machine's within the organisation with the same result. Please help!
Code used:
static Logger _logger = LogManager.GetCurrentClassLogger();
public static void Log(string message, LogLevel priority)
{
LogEventInfo eventinfo = new LogEventInfo(); ;
eventinfo.Message = message;
eventinfo.Level = priority;
Log(eventinfo);
}
static void Log(LogEventInfo logentry)
{
_logger.Log(logentry);
}
UPDATE:
#edosoft I think the problem is your use of the default constructor for LogEventInfo. If you look at the source for LogEventInfo here
https://github.com/NLog/NLog/blob/master/src/NLog/LogEventInfo.cs
You will see that using the default constructor does not populate the .TimeStamp field, so the field will probably just default to the default value for DateTime, which I assume is DateTime.MinValue. You should use one of the other constructors or one of the Create methods. Since you are setting only the Message and Level fields, I would suggest either:
var logEvent = new LogEventInfo(priority, "", message); //Second param is logger name.
Or
var logEvent = LogEventInfo.Create(priority, "", message);
From the NLog source for DateLayoutRenderer (from here) we can see that the date value that gets written as part of the logging stream is calculated like this:
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var ts = logEvent.TimeStamp;
if (this.UniversalTime)
{
ts = ts.ToUniversalTime();
}
builder.Append(ts.ToString(this.Format, this.Culture));
}
What is happening here is that the DateLayoutRenderer is getting the TimeStamp value from the LogEventInfo object (NLog creates one of these each time you use the Logger.Trace, Logger.Debug, Logger.Info, etc methods. You can also create LogEventInfo objects yourself and log them with the Logger.Log method).
By default, when a LogEventInfo object is created, its TimeStamp field is set like this (from the source for LogEventInfo here) (note the use of CurrentTimeGetter.Now):
public LogEventInfo(LogLevel level, string loggerName, IFormatProvider formatProvider, [Localizable(false)] string message, object[] parameters, Exception exception)
{
this.TimeStamp = CurrentTimeGetter.Now;
this.Level = level;
this.LoggerName = loggerName;
this.Message = message;
this.Parameters = parameters;
this.FormatProvider = formatProvider;
this.Exception = exception;
this.SequenceID = Interlocked.Increment(ref globalSequenceId);
if (NeedToPreformatMessage(parameters))
{
this.CalcFormattedMessage();
}
}
The TimeStamp field is set in the LogEventInfo constructor using the TimeSource.Current.Now property, whose implementation can be seen here.
(UPDATE - At some point NLog changed from using CurrentTimeGetter to a more generic approach of having a TimeSource object that has several flavors (one of which, CachedTimeSource, is essentially the same as CurrentTimeGetter)).
To save the trouble of navigating the link, here is the source for CachedTimeSource:
public abstract class CachedTimeSource : TimeSource
{
private int lastTicks = -1;
private DateTime lastTime = DateTime.MinValue;
/// <summary>
/// Gets raw uncached time from derived time source.
/// </summary>
protected abstract DateTime FreshTime { get; }
/// <summary>
/// Gets current time cached for one system tick (15.6 milliseconds).
/// </summary>
public override DateTime Time
{
get
{
int tickCount = Environment.TickCount;
if (tickCount == lastTicks)
return lastTime;
else
{
DateTime time = FreshTime;
lastTicks = tickCount;
lastTime = time;
return time;
}
}
}
}
The purpose of this class is to use a relatively cheap operation (Environment.Ticks) to limit access to a relatively expensive operation (DateTime.Now). If the value of Ticks does not change from call to call (from one logged message to the next), then the value of DateTime.Now retrieved the this time will be the same as the value of DateTime.Now retrieved this time, so just use the last retrieved value.
With all of this code in play (and with Date/Time logging apparently working for most other people), one possible explanation of your problem is that you are using the Logger.Log method to log your messages and you are building the LogEventInfo objects yourself. By default, if you just new a LogEventInfo object, the automatic setting of the TimeStamp property should work fine. It is only dependent on Environment.Ticks, DateTime.Now, and the logic that reuses the last DateTime.Now value, if appropriate.
Is it possible that you are creating a LogEventInfo object and then setting its TimeStamp property to DateTime.MinValue? I ask because the date that is being logged is DateTime.MinValue.
The only other explanation that I can think of would be if Environment.Ticks returns -1 for some reason. If it did, then CurrentTimeGetter would always return the initial value of the lastDateTime private member variable. I can't imagine a scenario where Environment.Ticks would return -1.
what happens if you implement an automatic property
public string Foobar { get; set; }
and then code the corresponding variable
private string foobar = string.Empty;
Will the automatic property use this variable or does the compiler generate
an additional variable?
No, the automatic property will not use your variable. It would be just like any other field called foobar.
The name smilarity does not influence the compiler in any way.
The compiler will generate a field behind the scenes but you do not have access to the backing field of the automatic property in any way.
This post shows how things work at the IL (Intermediate Langauge, Assembly of C#) level.
The compiler won't use that variable, no. To use your variable you will have to write
private string foobar = string.Empty;
public string Foobar
{
get { return foobar; }
set { foobar = value; }
}
If you have Resharper, you can set up templates to do this. Resharper will also generate a getter from an unused private variable for you.
Why would it? Backing field doesn't have to be (and often isn't) named this way.
I have following property in my Model Metadata class:
[Required(ErrorMessage = "Spent On is required")]
[RegularExpression(#"[0-1][0-9]/[0-3][0-9]/20[12][0-9]",
ErrorMessage = "Please enter date in mm/dd/yyyy format")]
[DataType(DataType.Date)]
[DisplayName("Spent On")]
public DateTime SpentOn { get; set; }
But whenever I call ModelState.IsValid it always returns false because regex is not validating. I have matched the entered date (08/29/2010) against new regex using same pattern and it matches perfectly.
What am I doing wrong?
Actualy there is another workaround for this. You can simply subclass the RegularExpressionAttribute
public class DateFormatValidatorAttribute : RegularExpressionAttribute {
public DateFormatValidatorAttribute()
: base(#"[0-1][0-9]/[0-3][0-9]/20[12][0-9]")
{
ErrorMessage = "Please enter date in mm/dd/yyyy format";
}
public override bool IsValid(object value) {
return true;
}
}
in your Global.asax.cs on application start register the RegularExpression addapter for client side validation like so:
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(DateFormatValidatorAttribute),
typeof(RegularExpressionAttributeAdapter));
Now you get to have the build-in MVC regular exression validator client side and keep the DateTime as your property type
That's because regex applies to strings and not DateTime properties. If the user enters an invalid string which cannot be parsed to a DateTime instance from the model binder it will add a generic error message before your regex pattern executes.
You have a couple of possibilities:
Customize the error message in a resource file
Write a custom model binder
Use a string property (I feel guilty for proposing this :-))