Passing javascript Date object to C# WebBrowser control using window.external - c#

I am able to call C# methods of WebBrowser.ObjectForScripting with javascript window.external from WebBrowser WinForms control and pass string, int, bool etc. However I don't know how to pass javascript Date object and somehow convert/marshal it to .NET DateTime class.
Obviously, I could pass a string and parse it, but this is really not the point. I'm just curious how could I do it with javascript Date and .NET DateTime?

You can take advantage of the fact that dates in Javascript are expressed as the number of milliseconds elapsed since the UNIX epoch (1970-01-01 00:00:00 UTC). Use the valueOf() method to obtain that value from a Date object :
var millisecondsSinceEpoch = yourDate.valueOf();
If you can marshal that value to C# as a double, you can create the appropriate DateTime object using its constructor and the AddMilliseconds() method:
DateTime yourDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
.AddMilliseconds(millisecondsSinceEpoch);

I finally got it working. I don't know why, but I am unable to use it with dynamic. Here is the solution:
[ComVisible(true)]
public class Foo
{
public void Bar(object o)
{
var dateTime = (DateTime)o.GetType().InvokeMember("getVarDate", BindingFlags.InvokeMethod, null, o, null);
Console.WriteLine(dateTime);
}
}

I found better solution for my project.
in javascript:
var date = new Date();
myComObject.DoSomething(date.getVarDate());
in C#
[ComVisible(true)]
public class Foo
{
public void Bar(DateTime dateTime)
{
Console.WriteLine(dateTime);
}
}

Related

DateTime.Now in class constructor

Good day all.
I am working on something that handles tasks.
Each task consists of 3 strings and a DateTime Object
Below is the constructor I built.
public Task(string von, string was, string an, DateTime zeit = DateTime.Now)
When compiling I get compiler error
Default parameter value for 'zeit' must be a compile-time constant (CS1736)
I assume the problem is, that -obvioulsy- the value for DateTime.Now depends on the time the constructor is called, which is the whole point that I want to have here.
I already looked at [this] thread, but it does not really apply to me, because the memory demand for a DateTime Object is always the same and that thread says the problem is the unknown heap-demand of that call.1
I already have an idea for a work-around (see below), but as we all know work-arounds are not best practice
public Task(string von, string was, string an, DateTime zeit){
if(zeit == null)
dateOfCreation = DateTime.Now; //dateOfCreation being the name of Task's internal DateTime field.
else
dateOfCretion = zeit;
So if I want to use the current DateTime I pass null. However: If I take the time and effort to always specifically pass null, I might as well each time pass DateTime.Now.
Question:
Is there a way to get parameter DateTime zeit = DateTime.Now accepted or substituted with identical outcome?
Use Constructor overloading instead:
public Task(string von, string was, string an, DateTime zeit)
{
...
}
public Task(string von, string was, string an) : this(von, was, an, DateTime.Now)
{
...
}

Overriding DateTime.MinValue causing issue

We are trying to override the DateTime.MinValue in our application, but by doing it we noticed that our Web services are timing-out, following is a sample code. Not sure what is wrong/what we are missing.
public MainWindow()
{
//Introducing this.. Causes timeout of the webservice call...
typeof(DateTime).GetField("MinValue").SetValue(typeof(DateTime),new DateTime(1900, 1, 1));
var yesitworks= DateTime.MinValue;
InitializeComponent();
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
//Below call will timeout...
var value =client.GetData(10);
}
PS: This might not be the best solution for what we are trying resolve but now its more of curiosity as to why it is not working? how is it related.
DateTime.MinValue is a static readonly field. That means that library authors will not expect it to change, and may write code that depends on it having the expected value.
Hence, you should not change the value of DateTime.MinValue.
For example, a library may use it as the default value for a variable:
private mostRecentDate= DateTime.MinValue;
foreach (var date in myDates)
{
if (date > mostRecentDate)
{
mostRecentDate= date;
}
}
// Do something with the most recent date in myDates...
In this example, if myDates only contained dates earlier than your new value for DateTime.MinValue, then this code would set mostRecentDate to DateTime.MinValue rather than the latest date in myDates.
While this rather contrived example may not be good programming practise (for example, you could use Nullable instead), it is valid code, whose behaviour would be changed if you changed the value of DateTime.MinValue.
The point is that libraries you are using could also be dependant on the value on DateTime.MinValue, so changing it could break them. You are llucky in so far as you found out that this introduced a bug early. If you are unlucky, you would not see a problem until your software had gone live and some corner case was hit.
I had a similar problem recently.
You didn't tell why you wanted to override DateTime.MinValue, but I guess the reason is similar to mine:
I have a server written in .NET, which has .NET clients and (via COM-Interop) MS Access clients.
The clients pass DateTime values, and the server needs to check whether they passed a "real" value or DateTime.MinValue.
My problem was:
.NET's DateTime.MinValue is January 1st of the year 1
The smallest possible value for VBA's Date type is January 1st of the year 100
⇒ Checking for DateTime.MinValue didn't work when the data was coming from MS Access, because Date variables in Access can't hold a date as small as .NET's DateTime.MinValue.
At that point I tried to override DateTime.MinValue too, and found out it doesn't work.
My solution was to write an extension method for DateTime:
public static class DateTimeExtensions
{
public static bool MinValue(this DateTime input)
{
// check the min values of .NET *and* VBA
if (input == DateTime.MinValue || input == new DateTime(100, 1, 1))
{
return true;
}
return false;
}
}
For the code in your question, it would need to look like this:
public static class DateTimeExtensions
{
public static bool MinValue(this DateTime input)
{
if (input == new DateTime(1900, 1, 1))
{
return true;
}
return false;
}
}
Usage:
DateTime theDate = DateTime.Now;
// vanilla .NET
bool isMin1 = (theDate == DateTime.MinValue);
// with the extension method
bool isMin2 = theDate.MinValue();
I don't think you will be able to change the DateTime MinValue as it is read only, But if you can DON'T
DateTime:
public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>
{
public static readonly DateTime MaxValue
public static readonly DateTime MinValue
....

Resharper suggests but does not perform any refactoring to this code block

In the following method, parameters fromDate and toDate's value are never used because they are overwritten in the body before being read.
static void GetDatesFromMonth(string month, ref DateTime fromDate, ref DateTime toDate)
{
DateTime userDateTime = TimeHelper.getUserGMTNow();
DateTime calculatedDate = Convert.ToDateTime(month + " 01," + userDateTime.Year);
toDate = calculatedDate.AddMonths(1).AddSeconds(-1);
fromDate = toDate.AddMonths(-12).AddSeconds(1);
}
I am using this code at many places in my class file.
When I run Resharper on my code it shows this message and unlike all its other suggessions it is not able to correct this code block
can anybody help me to rewrite this method with good coding practice.
Change the two date parameters to out
static void GetDatesFromMonth(string month, out DateTime fromDate, out DateTime toDate)
See here for a clarification on out vs ref
Simply, you use out when your method need to return two or more values, the out means 'I will set this values before exiting'. On the contrary ref is more complicated. It means 'I need this values/objects inside this method and I will change them before exit'
Alternatively since out parameters are generally a code smell you may want to rewrite your method as something like:
static Tuple<DateTime, DateTime> GetDatesFromMonth(string month)
{
...
}
or
static ToFromDates GetDatesFromMonth(string month)
{
...
}
with
class ToFromDates
{
public DateTime To{get;set;}
public DateTime From{get;set;}
}
You could also create an extension method
static class DateExtensions
{
public static Tuple<DateTime, DateTime> GetDatesFromMonth(this string month)
{
...
}
}
and use this in your code like this
var dates = "January".GetDatesFromMonth();
Simply use out in place of ref. It will show your intentions (that parameters will be out parameters) and it will also indicate that initial values of those parameters are irrelevant. That should also fix R# warning. If you use ref, R# expects you to use the parameter values before any overwrite.

What should be the default value in a DateTime optional parameter?

Normally, if I have a nullable type for an optional parameter, I would put null as the default value. This way I know that if the value is null, the caller doesn't want to specify any value for that one.
public void Foo(string text, string text2= null);
If the parameter is normally a positive integer, I can use a negative number
public void Foo(string text, int index=-1);
How about DateTime? It is not nullable, and (as far as I know) it doesn't have a meaningless number that cannot be a true input either (like -1 for positive integer). Or is there? What would you use in this situation?
I also know that I can use the nullable DateTime type, but this means that the method caller will have to use Nullable as well as opposed to just conveniently pass a DateTime.
You can make value types nullable using the ? operator in C#:
DateTime? myDate = null;
From this, you can make the parameter optional:
void Foo(DateTime? myDate = null)
{
}
Further reading on Nullable Types.
This is not the only way to skin the cat however, you can use default(DateTime), however you cannot use DateTime.MinValue, MaxValue, or Now in optional parameters because they are not compile time constants.
Of course, you don't need to use optional parameters, you can use overloaded methods if you wish to make use of Min, Max, or Now.
void Foo()
{
Foo(DateTime.MinValue);
}
void Foo(DateTime d)
{
}
If you want to go overkill (well, maybe not overkill, plenty of valid reasons to do this), then you could define a new date type that understands when it has a value:
class SmarterDateTime
{
public bool IsSet { get; set; }
// Wrapper around DateTime etc excluded.
}
As for what should be the default, you can choose to make any date represent a default if you wish, but for things like optional parameters you'll have limitations.
Personally, I tend to use DateTime.MinValue.
default (DateTime) - operator default is intended for It
At the question "what can be a default value for a DateTime" the response must be: you can only use default(DateTime). This because the default value must be const and both DateTime.MinValue and DateTime.MaxValue are only static readonly, but note that
default(DateTime) == DateTime.MinValue
down to the Kind.
If you want you can implement an overload with one less parameter (the DateTime) and from that overload call the "main" method passing the value you prefer.
But as written by others, the problem is that you wrote wrong premises.
No, DateTime (as nearly all the ValueTypes. Nearly all because Nullable<Nullable<int>> is illegal, even while Nullable<T> is a ValueType) is nullable. Nullable<DateTime> or DateTime? (same thing)
Even int are nullable, you know? int? :-)
DateTime.MinValue will be the default value.
check the dateTime default parameter , its value would be 1/1/0001 12:00:00 AM,
private void M(Int32 x = 9, String s = “A”, DateTimedt = default(DateTime), Guidguid = new Guid()) {
Console.WriteLine(“x={0}, s={1}, dt={2}, guid={3}”, x, s, dt, guid);
}
If you use the Nullable the callers of your function can just pass a regular DateTime to it, so they won't notice a thing :) There are implicit operators that will do this for you
If you want to set a default in your function you can do:
public void Foo(DateTime? value = null)
{
if ( value == null )
{
value = ... // default
}
}
Code Snippet
public DateTime method1()
{
if (condition)
return new DateTime(2007, 5, 30, 11, 32, 00);
else
return default(DateTime);
}
The default statement will initialise a value type to it's default value. In the case of a datetime this value is also exposed as a static property called DateTime.MinValue. If using C# 1.0 the statement "default(DateTime)" would be equivalent to "DateTime.MinValue". You could use this special value as a kind of "marker" value, meaning if it is returned it indicates an invalid datetime.
If using C# 2.0 again, it is also possible to use what is called a nullable type, and actually return NULL, as shown in the following example
Code Snippet
public DateTime? method2()
{
if (condition)
return new DateTime(2007, 5, 30, 11, 32, 00);
else
return null;
}
// This is the best way to null out the DateTime.
//
DateTime dateTime2 = DateTime.MinValue;
You might consider using the value DateTime.MinValue and use overloading.
Depends on your use-case.
Any that won't match real data will work, but that depends on your use of it (so in a way does -1 for integers, since it's a perfectly good integer only for your use of it being one were only positive integers make sense).
If you are sending a minimum date (interested in all foo that are later) then any date prior to the earliest sensible date will do, and code like .Where(f -> f.When > myDate) will work without even having to look for that special case.
Likewise with maximum dates in reverse (any date that would be after the latest sensible date).
Otherwise, just avoid the use of defaults entirely, and overload instead.

Is it possible to create a C# 'pointer' to a DateTime object?

Is it possible to create a C# pointer to a DateTime object? I'm trying to do this:
DateTime Event1 = DateTime.Now;
DateTime Event2 = DateTime.Now.AddYears(10);
DateTime EventPointer; // A Pointer?
if (something)
{
EventPointer = Event1;
}
else
{
EventPointer = Event2;
}
EventPointer.DoSomething? // Something that would change the value of Event1/2 variable.
Not directly, but you can wrap it around a class:
Wrapper w1 = new Wrapper { TheDate = DateTime.Now };
Wrapper w2 = new Wrapper { TheDate = DateTime.Now.AddYears(10) };
Wrapper w;
if (something)
{
w = w1;
}
else
{
w = w2;
}
w.DoSomething();
class Wrapper
{
public DateTime TheDate { get; set; }
public void DoSomething()
{
}
}
DateTimes are value types which unlike reference types everytime you assign its value to another variable their value is copied.
A DateTime is a value type, when you assign it the value is copied. However, methods can take a reference to a value type using the ref keyword. Your EventPointer.DoSomething would take a DateTime as reference. Here's a simple example of how you might be able to apply it.
var date = DateTime.Today;
MakeMinValue(ref date);
Console.Out.WriteLine("date = {0}", date);
public void MakeMinValue(ref DateTime dateTime)
{
dateTime = DateTime.MinValue;
}
This will only work with a method parameter.
You can't use pointers in managed code unless you use unsafe. I'd advise against it.
DateTimes are immutable. The only thing you can do to modify a variable of type DateTime is to reassign to it.
You can do something close to what you want, but in general it's not a good idea to do this:
DateTime event1 = new DateTime(2011, 10, 11);
DateTime event2 = new DateTime(2021, 10, 11);
Action<DateTime> eventPointer; // A Pointer?
if (true)
{
eventPointer = x => { event1 = x; };
}
else
{
eventPointer = x => { event2 = x; };
}
eventPointer(new DateTime(2016, 10, 11));
Console.WriteLine(event1.ToString(CultureInfo.InvariantCulture));
Console.WriteLine(event2.ToString(CultureInfo.InvariantCulture));
Result:
10/11/2016 00:00:00
10/11/2021 00:00:00
I think it is a better idea is to find another way to solve your problem.
Pointers, as you are thinking of them, don't exist in managed C# code. You might want to look into out and ref parameters if you need to pass a DateTime and have the original value change. Since DateTimes are structs (value type) they are always copied instead of passed by reference, unless you specifically use an out or ref parameter.
You can replace type of EventPointer, Event1 and Event2 types from DateTime type to DateTime?. It makes EventPointer's type nullable reference type.
DateTime? Event1 = DateTime.Now;
DateTime? Event2 = DateTime.Now.AddYears(10);
DateTime? EventPointer;
if (condition)
{
EventPointer = Event1;
}
else
{
EventPointer = Event2;
}
EventPointer.Value //.DoSomething

Categories

Resources