C#Bot Release


Improvements to the handling of dates and times

The storage for dates and times with respects to timezones has been improved in this version of C#Bot with a more standardised paradigm for how things work on the client and serverside. Prior to version, no timezone information was ever stored in the database, with the application needing to identify how to interpret the information. With changes to Entity Framework Core 6, the date times in the database are now stored as UTC timestamps instead. This is excellent for many scenarios, however can cause issues if the date time that is being stored is related to a local time and not to UTC.

To resolve this there has been several changes made to C#Bot to facilitate better practices when using date times.

  • The DateTime attribute will now store all values in UTC time by default.
    • There is an option on DateTime to prevent the date time from being stored in the database.
    • As a general rule, UTC timestamps are good for storing data for an instant in the past, where date times without timezones are good for storing times that are in the future at a specific location.
  • The Date and Time attributes will now no longer store dates its values as DateTime with the irrelevant component ignored, but instead use the new .NET 6 DateOnly and TimeOnly types.
    • This allows for easier comparisons and queries of date and time values.
  • Date times with timezones are now stored as local timezones on the clientside and are converted to UTC timestamps when sent to the server.
    • For example, for a user in the Australia/Brisbane timezone, the date object on the clientside will have a timezone offset of +10:00. When the date time is serialised to be sent to the serverside it will be in the format of 2022-01-01T15:00:00+10:00. When this is deserialised by the server, it will be automatically converted to a UTC timezone.
  • Date times without timezones will be stored as a Date object on the clientside with the timezone component ignored. When serialised to be sent to the server, the will using the the format of 2022-01-01T15:00:00.

For more reading on date times, please read Storing UTC is not a silver bullet.

CSV Output Customisation

Addded ability to use custom CSV class maps and type converters for bot written CSV endpoints (the export endpoint on entity controllers).

  • A class map can be used to change the output of a class in the CSV.
  • A type converter can be used to change how a type is serialised and deserialised to a string for use in a CSV.
  • Examples of how to use these features can be found here.

In addition a new ICsvWriterFactory service has been added that can be used to create CsvWriter classes with the global configuration already applied.


  • Configured ESLint to ignore whitespace issues inside of comments.
  • Added between comparison type for where expressions in graphql. This can be used to find values between 2 scalar values in the database.
    • This can be used to find any date times between 2 supplied date times.
    • This can also be used to find any number between 2 supplied numbers.
    • There is an example of a between question in the migration notes for date time API changes.
  • Added overload to the TimeBufferedSection constructor to accept TimeSpan. Updated internal handling of the class to perform less unit conversions.
  • When a CrudService transaction is rolled back, any files that were created will be cleaned up as well.
    • This is done in a background job to not hold up the main endpoint logic any more than needed.
  • Added ability to change the data type of decimal attributes.
    • The default data type is double which will store the data as a double precision floating point number. This is the same behaviour as prior versions.
    • There is now an ability to set the data type as decimal. This value is a fixed range floating point number that will not have suffer from precision loss. This data type is appropriate for financial calculations.
  • Updated the types for the js-cookie package to the latest version.
  • Removed the PasswordInput component and merged its functionality with the Password component.
  • Added a clickToClear prop to the date time picker that will show a clear button on the input when enabled.
  • Added ability to configure cookie lifetime from appsettings.
  • Added ability to useAsync to suppress the loading state after the initial load.
  • Pass AbortSignal to methods called by useAsync so they can be aborted in the case the hook is unmounted.
  • Added ability to combobox to disable and add descriptions to options.
  • Added ability to use ReactNode instances as labels for all inputs.
  • Added ability to configure the serialisation logic for client side entities.

Resolved Defects

  • Fixed an issue where an incompatible version of react-error-overlay was creating an invisible iframe that would prevent interaction with the screen.
  • Fixed an issue where accounts were not being deactivated corrected when calling the deactivate endpoint.
  • Fixed an issue where order by parameters on nested graphql queries would fail if there was more than one condition specified.
  • Fixed an issue where bulk deletes from the admin crud interface would not work if one of the filter conditions contained an enum.
  • Fixed an issue where the RemoveField method on ComplexGraphType did not work.
  • Fixed an issue where the FieldsToUpdate parameter for GraphQL and CrudService updates did not work for user entities.
  • Fixed an issue where the range validator could cause certain tests to fail when placed on a decimal attribute.
  • Fixed an issue where the password reveal icon would display twice on Microsoft Edge.
  • Fixed an issue where certain tests would fail if there was a timeline entity on a user entity.
  • Fixed an issue where string length validators were being ignored in certain tests.
  • Fixed an issue where subqueries were not working in has conditions.
  • Fixed an issue where not all bot written serverside tests were flagged with the BotWritten trait category.

Migration Path

Date time API changes

When saving or querying, the data that is passed to the server must have a timezone if the field has the timezone enabled, or not have a timezone if the timezone disabled.

For example in the following query created is a field that has a timezone, where timeAndDateOfReportPublication is stored without a timezone. In the variables for the query, the values for created will also have a timezone, where the values used for timeAndDateOfReportPublication do not have any timezone information. If this was not the case, then the API would throw an error warning the user that the format is wrong.


query testQuery($createdRange: [String], $reportRange: [String]) {
  reportEntitys(conditions: [
    [{path: "created", comparison: between, value: $createdRange}],
    [{path: "timeAndDateOfReportPublication", comparison: between, value: $reportRange}]
  ]) {


  "createdRange": ["2022-07-01T00:00:00+10:00", "2022-07-30T00:00:00Z"],
  "reportRange": ["2022-07-01T00:00:00", "2022-07-30T00:00:00"]

PasswordInput Removed

With this version the PasswordInput component was removed. Please update any reference to it to use the Password component instead.

Known Issues

Failing Date Time Selenium Tests

In cases where there are entities with multiple date time attributes on them, botwritten Selenium tests for update and create can fail with a StaleElementReferenceException.

1 Like