Open Closed

Disable receiving DateTime in UTC from Client for a specific property #8963


1
alwefaq created

How can I receive a DateTime from the client exactly what the user choose without changing clock provider.

when the user choose a specific time, the server will receive it as UTC. I need to disable this behavior for a specific property, while keeping everything working as normal. I need to know exactly the selected time by the user.

Current behavior: Startup.cs - ClockProviders.Utc Client - 10:00 +3 Server - 07:00 +0

Trying to do: Startup.cs - ClockProviders.Utc Client - 10:00 +3 Server - 10:00 +3

---------------------------------------------- <span class="colour" style="color: rgb(0, 0, 0);">product version: </span>5.1.0<span class="colour" style="color: rgb(0, 0, 0);"><span class="colour" style="color: rgb(0, 0, 0);"> </span>.net core</span> Angular: 6.1.7 Angular  CLI: 6.2.3 Node: 12.13.0 OS: win32 x64


37 Answer(s)
  • 0
    maliming created
    Support Team

    You take a look and try Disable DateTime Normalization.

    https://aspnetboilerplate.com/Pages/Documents/Timing#disable-datetime-normalization

  • 0
    alwefaq created

    I tried it and it didn't work as expected, it kept the same behaviour. after some more investigation, it works only if it on a parameter directly, but it does not work if it was on a DTO property.

    is there something i can try to make it work on a DTO property?

    ` public async void TestDate([DisableDateTimeNormalization]DateTime datetime){} // this works

    public class SomeDto { [DisableDateTimeNormalization] public DateTime datetime {get; set;} } public async void TestDate(SomeDto dto){} // this does not work `

  • 0
    ismcagdas created
    Support Team

    Hi,

    Could you share the class wich contains TestDate method which doesn't work ?

    Thanks,

  • 0
    alwefaq created

    Hi,

    This is what the class looks like, please let me know if there's something specific you need to know.

    public class SomeDto {
        [Required]
        [DisableDateTimeNormalization]
        public DateTime DateTime {get; set;}
    }
    
    public abstract class BaseDDDApplicationService : ApplicationService, IApplicationService {
    }
    
    public interface IBookingAppService : IApplicationService {
        Task TestDate(SomeDto dto);
    }
    
    public class BookingAppService : BaseDDDApplicationService, IBookingAppService {
        public async Task TestDate(SomeDto dto){
            // do stuff
        }
    }
    
  • 0
    maliming created
    Support Team

    hi @alwefaq

    What is the version of your abp package?

    If you are using service-proxies.ts please share the ts code of the TestDate method in it.

  • 0
    alwefaq created

    abp package version is 5.5

    service-proxies.ts

        /**
         * @param body (optional) 
         * @return Success
         */
        testDate(body: SomeDto | null | undefined): Observable<void> {
            let url_ = this.baseUrl + "/api/services/app/Contract/TestDate";
            url_ = url_.replace(/[?&]$/, "");
    
            const content_ = JSON.stringify(body);
    
            let options_ : any = {
                body: content_,
                observe: "response",
                responseType: "blob",
                headers: new HttpHeaders({
                    "Content-Type": "application/json", 
                })
            };
    
            return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => {
                return this.processTestDate(response_);
            })).pipe(_observableCatch((response_: any) => {
                if (response_ instanceof HttpResponseBase) {
                    try {
                        return this.processTestDate(<any>response_);
                    } catch (e) {
                        return <Observable<void>><any>_observableThrow(e);
                    }
                } else
                    return <Observable<void>><any>_observableThrow(response_);
            }));
        }
    
        protected processTestDate(response: HttpResponseBase): Observable<void> {
            const status = response.status;
            const responseBlob = 
                response instanceof HttpResponse ? response.body : 
                (<any>response).error instanceof Blob ? (<any>response).error : undefined;
    
            let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }};
            if (status === 200) {
                return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
                return _observableOf<void>(<any>null);
                }));
            } else if (status !== 200 && status !== 204) {
                return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
                return throwException("An unexpected server error occurred.", status, _responseText, _headers);
                }));
            }
            return _observableOf<void>(<any>null);
        }
    
    
    export class SomeDto implements ISomeDto {
        dateTime!: moment.Moment;
    
        constructor(data?: ISomeDto) {
            if (data) {
                for (var property in data) {
                    if (data.hasOwnProperty(property))
                        (<any>this)[property] = (<any>data)[property];
                }
            }
        }
    
        init(data?: any) {
            if (data) {
                this.dateTime = data["dateTime"] ? moment(data["dateTime"].toString()) : <any>undefined;
            }
        }
    
        static fromJS(data: any): SomeDto {
            data = typeof data === 'object' ? data : {};
            let result = new SomeDto();
            result.init(data);
            return result;
        }
    
        toJSON(data?: any) {
            data = typeof data === 'object' ? data : {};
            data["dateTime"] = this.dateTime ? this.dateTime.toISOString() : <any>undefined;
            return data; 
        }
    }
    
    export interface ISomeDto {
        dateTime: moment.Moment;
    }
    
    
  • 0
    maliming created
    Support Team

    hi @alwefaq

    Can you share the project with me? liming.ma@volosoft.com

    I will download and check it.

  • 0
    alwefaq created

    Hi, I have sent an email containing the sample project show the issue.

  • 0
    maliming created
    Support Team

    OK, I will check it as soon as possible.

  • 0
    maliming created
    Support Team

    hi @alwefaq

    I have downloaded your project, please provide the steps for me to reproduce the problem.

  • 0
    alwefaq created

    Hi, 1- Open DateTimeIssueProject.sln 2- Run DateTimeIssueProject.Migrator 3- Run DateTimeIssueProject.Web.Host 4- Run Angular Project 5- go to http://localhost:4200/account/register 6- fill required info and click submit 7- debug Register method in AccountAppService 8- check FirstDateTime and SecondDateTime from RegisterInput dto

    ** note that the values are provided from register.component.ts and both are set to moment("2014-02-27T10:00:00")

  • 0
    maliming created
    Support Team

    hi alwefaq

    Can you check if your code uses this change?

    https://github.com/aspnetzero/aspnet-zero-core/pull/2573

  • 0
    alwefaq created

    Hi, our code does not use this change.

    current angular version: Angular CLI: 6.2.3 Node: 12.13.0 OS: win32 x64 Angular: 6.1.7

  • 0
    maliming created
    Support Team

    hi

    Can you try to apply the changes in pr, or try using the latest demo project?

  • 0
    alwefaq created

    Hi, I got a the latest demo for testing and it worked fine, but for some reason adding the changes to my project didn't fix the issue. please note that the angular version from the demo is Angular CLI: 9.1.0 Node: 12.13.0 OS: win32 x64 Angular: 9.1.0

    and for my project is: Angular CLI: 6.2.3 Node: 12.13.0 OS: win32 x64 Angular: 6.1.7

    The changes as below:

    // AppPreBootstrap private static getUserConfiguration(callback: () => void): any {     //...     AppPreBootstrap.configureMoment();     //... }

    private static configureMoment() {     moment.locale(new LocaleMappingService().map('moment', abp.localization.currentLanguage.name));     (window as any).moment.locale(new LocaleMappingService().map('moment', abp.localization.currentLanguage.name));     if (abp.clock.provider.supportsMultipleTimezone) {         moment.tz.setDefault(abp.timing.timeZoneInfo.iana.timeZoneId);         (window as any).moment.tz.setDefault(abp.timing.timeZoneInfo.iana.timeZoneId);     } else {         moment.fn.toJSON = function () {             return this.locale('en').format();         };         moment.fn.toISOString = function () {             return this.locale('en').format();         };     } }

    // add LocaleMappingService import { AppConsts } from '@shared/AppConsts'; import * as _ from 'lodash';

    export class LocaleMappingService {     map(mappingSource: string, locale: string): string {         if (!AppConsts.localeMappings && !AppConsts.localeMappings[mappingSource]) {             return locale;         }

            const localeMappings = _.filter(AppConsts.localeMappings[mappingSource], { from: locale });         if (localeMappings && localeMappings.length) {             return localeMappings[0]['to'];         }

            return locale;     } }

  • 0
    maliming created
    Support Team

    but for some reason adding the changes to my project didn't fix the issue.

    Is there any error message?

  • 0
    alwefaq created

    No error message, it just does not work.

  • 0
    ismcagdas created
    Support Team

    Hi @alwefaq

    Can you try below statement instead ?

    Date.prototype.toISOString = function () {
    	return moment(this).locale('en').format();
    };
    
  • 0
    alwefaq created

    Hi @ismcagdas, This works prefectly, Thanks. Can you please explain why this works if you don't mind?

  • 0
    alwefaq created

    I am sorry here , I was mistaken , the last provided solution did not work for me, still I am getting notmalized datetime on the server. Any other suggestion please ?

  • 1
    adamphones created

    Hi @alwefaq,

    Can you have a look at this ticket, I raised this issue and I think this is exact same issue you are facing. No clear answer to the isuee yet.

  • 0
    alwefaq created

    any updates here please?

  • 0
    alwefaq created

    Reminder please .. please let us know if this is a unkoun issue and has no solution from your side so we can find another way to solve it.

  • -1
    ismcagdas created
    Support Team

    Hi @alwefaq

    I couldn't reproduce your problem. Here is what I did;

    1. Set Clock.Provider = ClockProviders.Utc; in PreInitialize of my web module.
    2. Define a datetime field in my Dto like below;
    [DisableDateTimeNormalization]
    public DateTime MyDate {get; set;}
    
    1. Send a date to server as below;

    2020-06-01T10:33:10+03:00

    Then, I get the correct value on server side.

    Could you share the date string you are sending to server ?

    Thanks,

  • 0
    alwefaq created

    Hi @ismcagdas

    a sample project contains the issue already has been sent to you before , you can find it here

    https://support.aspnetzero.com/QA/Questions/8963#answer-d97287ad-bfec-df6d-ab05-39f517bc2e47

    would you check it again and let me know if it works with you or not.

    Thanks

  • 0
    ismcagdas created
    Support Team

    Hi,

    Sorry, my mistake. I will check it.

  • 0
    maliming created
    Support Team

    hi @alwefaq I didn't find the proiejct you shared before(this transfer has expired and is not available any more), can you send it again? Thank you.

  • 0
    alwefaq created

    Hi @maliming, i did send the project to you at liming.ma@volosoft.com again, please check it, find reproduce steps below:-

    1- Open DateTimeIssueProject.sln 2- Run DateTimeIssueProject.Migrator 3- Run DateTimeIssueProject.Web.Host 4- Run Angular Project 5- Go to http://localhost:4200/account/register 6- Fill required info and click submit 7- Debug Register method in** AccountAppService** 8- Check FirstDateTime and SecondDateTime from RegisterInput dto

    ** note that the values are provided from register.component.ts and both are set to moment("2014-02-27T10:00:00")

  • 0
    ismcagdas created
    Support Team

    Hi @alwefaq

    Sorry, I have tried several times but couldn't download your project. Can you share related part (see https://github.com/aspnetzero/aspnet-zero-core/blob/dev/angular/src/AppPreBootstrap.ts#L190) for your AppPreBootstrap.ts ?

  • 0
    quantavn created

    I got a strange error related to this issue, don't know where and how to investigate. Hope DEV team can help! It works as usual at LOCALHOST (Vietnam time GMT+7) when developing but the DateTime is substract by 7 hours (-7 hours) when deploying to Azure (location: Southeast Asia). I've tried using DisableDateTimeNormalization (applied to the CreateOrEdit DTOs) but it did not work (there's no differences before and after changed).

  • 0
    ismcagdas created
    Support Team

    Hi @quantavn

    1. Do you use UtcClockProvider ?
    2. Could you share the date string send to server from client and also the one saved to database ?

    Thanks,

  • 0
    quantavn created

    Hi @ismcagdas,

    About #1, I've tried several options when deploying to Azure:

    1. First, don't use either ClockProvider or DisableDateTimeNormalization:
      1. In CreateOrEdit view: input a date with value the '15:30'
      2. In List view: the date is display as '08:30'
    2. Use ClockProvider.Local and DisableDateTimeNormalization:
      1. It displays well in both views (CreateOrEdit and List) in my laptop (Vietnam, Hanoi timezone) with the value '15:30'
      2. But in my partner laptop (another TimeZone, Sydney), it displays as '08:30' in both views
    3. Use ClockProvider.Utc and DisableDateTimeNormalization (the same result as the 1st option)
      1. In CreateOrEdit view: input a date with value the '15:30'
      2. In List view: the date is display as '08:30'

    About #2, here is the string I got from my laptop when using Option 3:

    1. Client: The string content at service-proxies.ts after using JSON.stringify(body)
    2. Server:
    3. DB (MS SQL Server):

    What I want is: the value '15:30' is displayed in both views (CreateOrEdit and List), at any TimeZone.

  • 0
    ismcagdas created
    Support Team

    Hi,

    Could you also share how do you display the date values in List view ?

    AspNet Zero only modifies your date values when you use ClockProvider.Utc. So, in other cases ASP.NET Core converst string send from client to server to a DateTime value.

  • 0
    quantavn created

    Hi @ismcagdas,

    In List view, I'm using this momentFormat:'HH:mm'

    I've just update to not use ClockProvider.Utc, I still got this strange issue: In CreateOrEdit view, input 15:30 ~ 16:00: Then in List view, it displays as : Open CreateOrEdit view again: In Server: In DB:

    Wonder if it is related to this or not:

    UPDATE: Try to udpate the date to September, the issue still occurs: In CreateOrEdit: In Server: Then in List: In DB:

    UPDATE 2: In Client, CreateOrEdit component: In Client, ProxyService:

    UPDATE 3: After deploying to Azure, the time is input as 15:30 but inserted into DB as 05:30 (PC's timezone: UTC+10:00)

  • 0
    ismcagdas created
    Support Team

    Hi,

    This problem might be related to https://github.com/dotnet/aspnetcore/issues/11584.

    Is it possible to share your project via email with info@aspnetzero.com and also explain steps to reproduce this problem ?

    Thanks,

  • 0
    quantavn created

    I've solved the issue temporarily by:

    1. Adding Application Settings WEBSITE_TIME_ZONE to the Web Host's App Service
    2. Use Clock.Provider = ClockProviders.Local;

    It's better if we check deeper to know why not using Clock.Provider = ClockProviders.Utc the time is still normalized.

  • 0
    ismcagdas created
    Support Team

    Hi @quantavn

    Thanks for sharing the workaround. I will check this deeply.