I'm trying to build an entity manager in Dart which uses reflection. The idea is that the method getById(String id, String returnClass) calls a method _get[returnClass]ById(String id).
To accomplish this I'm using dart:mirrors and try to determine if my entity manager object has such a method and call it then. Unfortunately the LibraryMirror doesn't contain any functions.
class EntityMgr {
Object getById(String id, String returnClass) {
InstanceMirror result = null;
String methodName = '_get'+returnClass+'ById';
// Check if a method '_get[returnClass]Byid exists and call it with given ID
if(_existsFunction(methodName)) {
Symbol symbol = new Symbol(methodName);
List methodParameters = new List();
methodParameters.add(id);
result = currentMirrorSystem().isolate.rootLibrary.invoke(symbol, methodParameters);
}
return result;
}
Product _getProductById(String id) {
return new Product();
}
bool _existsFunction(String functionName) {
return currentMirrorSystem().isolate.rootLibrary.functions.containsKey(functionName);
}
}
The mirrors library has changed significantly since this response and no longer reflects the api mentioned in this answer
Isolate's are for concurrent programming and you probably don't have any isolates running. Where you want to look is currentMirrorSystem().libraries, or you can use currentMirrorSystem().findLibrary(new Symbol('library_name')).
You need to know the library because a function or class with the same Symbol could me in different libraries but have completely different signatures.
how to invoke class form dart library string or file shows how to get the class mirror from the library and class name.
The ClassMirror contains the methods, the getters and the setters. The methods mirror does not contain the getters or setters.
final Map<Symbol, MethodMirror> methods
final Map<Symbol, MethodMirror> getters
final Map<Symbol, MethodMirror> setters
That being said, you might want to check out the dart serialization at http://api.dartlang.org/docs/bleeding_edge/serialization.html since it might already do exactly what you're trying to do.
How to pass UTC dates to Web API?
Passing 2010-01-01 works fine, but when I pass a UTC date such as 2014-12-31T22:00:00.000Z (with a time component), I get a HTTP 404 response. So
http://domain/api/controller/action/2012-12-31T22:00:00.000Z
yields a 404 error response, while
http://domain/api/controller/action/2012-12-31
works fine.
How to pass UTC dates to Web API then - or at least specify date and time?
The problem is twofold:
1. The . in the route
By default, IIS treats all URI's with a dot in them as static resource, tries to return it and skip further processing (by Web API) altogether. This is configured in your Web.config in the section system.webServer.handlers: the default handler handles path="*.". You won't find much documentation regarding the strange syntax in this path attribute (regex would have made more sense), but what this apparently means is "anything that doesn't contain a dot" (and any character from point 2 below). Hence the 'Extensionless' in the name ExtensionlessUrlHandler-Integrated-4.0.
Multiple solutions are possible, in my opinion in the order of 'correctness':
Add a new handler specifically for the routes that must allow a dot. Be sure to add it before the default. To do this, make sure you remove the default handler first, and add it back after yours.
Change the path="*." attribute to path="*". It will then catch everything. Note that from then on, your web api will no longer interpret incoming calls with dots as static resources! If you are hosting static resources on your web api, this is therefor not advised!
Add the following to your Web.config to unconditionally handle all requests: under <system.webserver>: <modules runAllManagedModulesForAllRequests="true">
2. The : in the route
After you've changed the above, by default, you'd get the following error:
A potentially dangerous Request.Path value was detected from the client (:).
You can change the predefined disallowed/invalid characters in your Web.config. Under <system.web>, add the following: <httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?" />. I've removed the : from the standard list of invalid characters.
Easier/safer solutions
Although not an answer to your question, a safer and easier solution would be to change the request so that all this is not required. This can be done in two ways:
Pass the date as a query string parameter, like ?date=2012-12-31T22:00:00.000Z.
Strip the .000 from every request, and encode the url, so replace all :'s with %3A, e.g. by using HttpUtility.UrlEncode().
in your Product Web API controller:
[RoutePrefix("api/product")]
public class ProductController : ApiController
{
private readonly IProductRepository _repository;
public ProductController(IProductRepository repository)
{
this._repository = repository;
}
[HttpGet, Route("orders")]
public async Task<IHttpActionResult> GetProductPeriodOrders(string productCode, DateTime dateStart, DateTime dateEnd)
{
try
{
IList<Order> orders = await _repository.GetPeriodOrdersAsync(productCode, dateStart.ToUniversalTime(), dateEnd.ToUniversalTime());
return Ok(orders);
}
catch(Exception ex)
{
return NotFound();
}
}
}
test GetProductPeriodOrders method in Fiddler - Composer:
http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59
DateTime format:
yyyy-MM-ddTHH:mm:ss
javascript pass parameter use moment.js
const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss');
const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');
I feel your pain ... yet another date time format... just what you needed!
Using Web Api 2 you can use route attributes to specify parameters.
so with attributes on your class and your method you can code up a REST URL using this utc format you are having trouble with (apparently its ISO8601, presumably arrived at using startDate.toISOString())
[Route(#"daterange/{startDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}/{endDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}")]
[HttpGet]
public IEnumerable<MyRecordType> GetByDateRange(DateTime startDate, DateTime endDate)
.... BUT, although this works with one date (startDate), for some reason it doesnt work when the endDate is in this format ... debugged for hours, only clue is exception says it doesnt like colon ":" (even though web.config is set with :
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" />
</system.web>
So, lets make another date format (taken from the polyfill for the ISO date format) and add it to the Javascript date (for brevity, only convert up to minutes):
if (!Date.prototype.toUTCDateTimeDigits) {
(function () {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
Date.prototype.toUTCDateTimeDigits = function () {
return this.getUTCFullYear() +
pad(this.getUTCMonth() + 1) +
pad(this.getUTCDate()) +
'T' +
pad(this.getUTCHours()) +
pad(this.getUTCMinutes()) +
'Z';
};
}());
}
Then when you send the dates to the Web API 2 method, you can convert them from string to date:
[RoutePrefix("api/myrecordtype")]
public class MyRecordTypeController : ApiController
{
[Route(#"daterange/{startDateString}/{endDateString}")]
[HttpGet]
public IEnumerable<MyRecordType> GetByDateRange([FromUri]string startDateString, [FromUri]string endDateString)
{
var startDate = BuildDateTimeFromYAFormat(startDateString);
var endDate = BuildDateTimeFromYAFormat(endDateString);
...
}
/// <summary>
/// Convert a UTC Date String of format yyyyMMddThhmmZ into a Local Date
/// </summary>
/// <param name="dateString"></param>
/// <returns></returns>
private DateTime BuildDateTimeFromYAFormat(string dateString)
{
Regex r = new Regex(#"^\d{4}\d{2}\d{2}T\d{2}\d{2}Z$");
if (!r.IsMatch(dateString))
{
throw new FormatException(
string.Format("{0} is not the correct format. Should be yyyyMMddThhmmZ", dateString));
}
DateTime dt = DateTime.ParseExact(dateString, "yyyyMMddThhmmZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
return dt;
}
so the url would be
http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z
Hanselman gives some related info here:
http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
As a similar alternative to s k's answer, I am able to pass a date formatted by Date.prototype.toISOString() in the query string. This is the standard ISO 8601 format, and it is accepted by .Net Web API controllers without any additional configuration of the route or action.
e.g.
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"
This is a solution and a model for possible solutions. Use Moment.js in your client to format dates, convert to unix time.
$scope.startDate.unix()
Setup your route parameters to be long.
[Route("{startDate:long?}")]
public async Task<object[]> Get(long? startDate)
{
DateTime? sDate = new DateTime();
if (startDate != null)
{
sDate = new DateTime().FromUnixTime(startDate.Value);
}
else
{
sDate = null;
}
... your code here!
}
Create an extension method for Unix time. Unix DateTime Method
It used to be a painful task, but now we can use toUTCString():
Example:
[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)
Put the below into Ajax post request
data: {
Start: new Date().toUTCString(),
End: new Date().toUTCString()
},
As a matter of fact, specifying parameters explicitly as ?date='fulldatetime' worked like a charm. So this will be a solution for now: don't use commas, but use old GET approach.
One possible solution is to use Ticks:
public long Ticks { get; }
Then in the controller's method:
public DateTime(long ticks);
Since I have encoding ISO-8859-1 operating system the date format "dd.MM.yyyy HH:mm:sss" was not recognised what did work was to use InvariantCulture string.
string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)
By looking at your code, I assume you do not have a concern about the 'Time' of the DateTime object. If so, you can pass the date, month and the year as integer parameters. Please see the following code. This is a working example from my current project.
The advantage is; this method helps me to avoid DateTime format issues and culture incompatibilities.
/// <summary>
/// Get Arrivals Report Seven Day Forecast
/// </summary>
/// <param name="day"></param>
/// <param name="month"></param>
/// <param name="year"></param>
/// <returns></returns>
[HttpGet("arrivalreportsevendayforecast/{day:int}/{month:int}/{year:int}")]
public async Task<ActionResult<List<ArrivalsReportSevenDayForecastModel>>> GetArrivalsReportSevenDayForecast(int day, int month, int year)
{
DateTime selectedDate = new DateTime(year, month, day);
IList<ArrivalsReportSevenDayForecastModel> arrivingStudents = await _applicationService.Value.GetArrivalsReportSevenDayForecast(selectedDate);
return Ok(arrivingStudents);
}
If you are keen to see the front-end as well, feel free to read the code below. Unfortunately, that is written in Angular. This is how I normally pass a DateTime as a query parameter in Angular GET requests.
public getArrivalsReportSevenDayForecast(selectedDate1 : Date): Observable<ArrivalsReportSevenDayForecastModel[]> {
const params = new HttpParams();
const day = selectedDate1.getDate();
const month = selectedDate1.getMonth() + 1
const year = selectedDate1.getFullYear();
const data = this.svcHttp.get<ArrivalsReportSevenDayForecastModel[]>(this.routePrefix +
`/arrivalreportsevendayforecast/${day}/${month}/${year}`, { params: params }).pipe(
map<ArrivalsReportSevenDayForecastModel[], ArrivalsReportSevenDayForecastModel[]>(arrivingList => {
// do mapping here if needed
return arrivingList;
}),
catchError((err) => this.svcError.handleError(err)));
return data;
}
Passing the date as a string and then parsing it worked for me. Probably want to add try catch on the parse, but this is the basic code.
[HttpGet("name={name}/date={date}", Name = "GetByNameAndDate")]
public IActionResult GetByNameAndDate(string name, string date) {
DateTimeOffset dto = DateTimeOffset.Parse(date);
}
Then the request can look like this
https://localhost/api/Contoller/name=test/date=2022-02-18T13:45:37.000Z
For external APIs (where you do not know what type of client will call your service), Unix Time should be used both on the input parameters and outputted date fields.
https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset.tounixtimeseconds?view=net-6.0
.Net provides ToUnixtimeSeconds and FromUnixtimeSeconds to easily convert to DateTime or DateTimeOff
Unix Time should be preferred over ISO formats because it is just a integer and can be passed in the URL string without encoding.
The 'Ticks' property is similar to Unix time but (I believe) should only be use between a .net client and server.
Most well know APIs will use Unix Time, for example see Stripe's API:
https://stripe.com/docs/api
The obvious downsides of using Unix time are:
They are not human readable
They cannot be created by humans - making it difficult to call the API without code
Use binary format.
to send the info in url use dateTimeVar.ToBinary()
it will be something like
http://domain/api/controller/action/637774955400000000
when you reciebe the data will get like Long variable and use the static function of DateTime Class to transform to DateTime type again.
DateTime MyDateTime = DateTime.FromBinary(BinaryDateTime);
Cheers
I need a way to fake DateTime.Parse with Typemock and have it return the same date when called with any parameters.
I have a DB field that stores an encrypted string that is parsed as date when loaded. The class that holds the data has a Load() method where it copies DB data into its properties, decrypts what's encrypted and does some basic validation, such as:
public class BusinessObject{
public DateTime ImportantDate{get;set;}
...
public void Load(DBObject dbSource){
...
ImportantDate = DateTime.Parse(DecryptionService.Decrypt(dbSource.ImportantDate));
}
}
Runtime all works well.
I'm trying to write a unit test using TypeMock to load some fake data into BusinessObject using its Load method. BusinessObject has way too many properties and can not be deserialized from XML, but DBObject can, so I've stored some XMLs that represent valid data.
It all works well until DecryptionService is called to decrypt the data - it doesn't work because my dev machine doesn't have the DB certificates used in the encryption process. I can't get those on my machine just for testing, that would be a security breach.
I added this to my unit test:
Isolate.Fake.StaticMethods<DecryptionService>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => DecryptionService .Decrypt(null)).WillReturn("***");
Isolate.Fake.StaticMethods<DateTime>(Members.ReturnNulls);
Isolate.WhenCalled(() => DateTime.Parse("***" /*DateStr*/)).WillReturn(DateTime.Now.AddYears(2));
The first part where DecryptionService is faked works, social security and other sensitive strings are "decrypting", but no matter what parameters I give to DateTime I still get one exception or another (ArgumentNullException: String reference not set to an instance of an object if DateStr is null, FormatException when it's "*")
How (if) can I override DateTime.Parse with typemock so that it returns valid DateTime with any invalid paramters passed?
My name is Nofar and i'm from Typemock's support team.
DateTime.Parse is not supported in the WhenCalled API, so in order to fake it's returned value you need to wrap it with a method from your class, for example:
public class BusinessObject
{
public DateTime Load (string s)
{
return DateTime.Parse(s);
}
}
And you test will look like this:
[TestMethod]
public void TestMethodDateTime()
{
BusinessObject b = new BusinessObject();
DateTime now= DateTime.Now.AddYears(2);
Isolate.WhenCalled(()=>b.Load(null)).WillReturn(now);
Assert.AreEqual(now, b.Load(null));
}
Supporting DateTime.Parse in the WhenCalled API is in our backlog.
Please feel free to contact us via mail at support#typemock.com
Nofar
Typemock Support
I'm trying to bind Date params in my controller. I read somewhere that it should be sufficient if I have the date in format yyyy-MM-dd HH:mm:ss.S. But this doesn't work. The other option that I read was to add _day, _month, _year, etc. suffixes to the attributes that I want to parse, but this method doesn't work either.
So it's basically a one-to-many relationship, when on the many side is the date (an Action has a VisitList<Visit> and the Visit has date).
// domain classes
class Action {
List<Visit> visitList
static hasMany = [visitList: Visit]
}
class Visit {
Action action
static belongsTo = [action: Action]
Date date
String description
}
I parse all the params to the action instance like this:
// in controller
def save(){
Action actionInstance = new Action()
action.properties = params
action.save()
}
The date is sent from view and has this format:
visitList[0].date=2012-05-15 00:00:00.0000
But the date is still null. The visit also has a description attribute and it works well. The param for this attribute is:
visitList[0].description=description
Thanks for any suggestions or advices.
Did you try saving the Visit first and then save the Action? If that doesn't work you may have to convert the date from string to Date, Date.parse() method is depreciated in grails 2.0, try this:
Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(dateString)
def action = new Action()
def visit = new Visit(date: date, description: description?:"", action: action)
visit.save()
action.visitList.add(visit)
action.save()
-HTH
Without seeing more code it's difficult to tell. You may want to try a Command Object. Where is your input coming from? A View? If so, one typically uses the and tags to control the input. If you're not using those, you may have to manually parse the date using DateFormat {hint, use the parse() method}.
I need to log all the function parameters in a dozen functions.
Is there a way to pro grammatically determine all the parameters and their values (or at least their .ToString() value)? Perhaps via reflection?
Here is an example of how to do this with PostSharp
http://consultingblogs.emc.com/merrickchaffer/archive/2009/08/04/using-postsharp-to-log-method-entry-and-exit-in-net-code.aspx
You can also roll your own
http://www.developerfusion.com/article/5307/aspect-oriented-programming-using-net/3/
To the best of my knowledge there's no way to use reflection to dynamically list and determine value of local variables. You can use reflection to get type information about the parameters of a method, but only the declared type - you can't automatically get information about the actual arguments, because the reflection metadata gives information about the method definition, not the specific values passed to it at runtime.
You can, however, do something like this:
static class Extensions
{
public static string GetTypeAndValue(this object obj)
{
return String.Format("{0}: {1}", obj.GetType().Name, obj.ToString());
}
}
Then, from within each method in which you want to perform logging, do something like
private void SomeMethodToBeLogged(string some_string, int some_int, bool some_bool)
{
Logger.Log(String.Format("SomeMethodToBeLogged({0}, {1}, {2})",
some_string.GetTypeAndValue(),
some_int.GetTypeAndValue(),
some_bool.GetTypeAndValue()));
}