Saturday, January 23, 2021

The IFDEF Problem!


If you are using {$IFDEF} in your source - normally it's fine...

e.G.

{$IFDEF DEBUG}
ShowMessage('Foo');
{$ENDIF}


Why, because this DEBUG is handled by the IDE.

But what if you want to use your own?

{$IFDEF IMPORTANT}
Result := 42;
{$ENDIF}

If your application depends on this, you always have to do an else part to make sure the Name "IMPORTANT" is set.

{$IFDEF IMPORTANT}
Result := 42;
{$ELSE}
! Too stupid set this!
{$ENDIF}

I don't want to have this in my source in every place I just want to exclude or include something.

Like:

{$IFDEF UseLogger}
Log('Ready to run');
{$ENDIF}

In this case, I want to be able to include logging, but on the other hand, I want to be sure that I disabled logging for a good reason, not just forgot to set the {$DEFINE UseLogger}.

That's why I like to use const's:

Unit Defines;

Interface
  Const
    UseLogger = true;
Implementation

end.

{$IF Uselogger} is also not working if you just forgot to "uses" your Defines.pas Unit.

That's why I'm using the not implementation.

Unit Defines;

Interface
  Const
    NotUseLogging = false; // means use logger
Implementation

end.

Because using:

{$IF not(NotUseLogging)} has the benefit of checking if there is a symbol named NotUseLogging!

So if you forgot to use the Defines Unit you are getting an error at compile time. I'm using the approach for my FDK and also for my #D.MVVM Framework.

This works fine... But there is one drawback: You are unable to change these settings per project. In the past, I've changed the source of my defines unit, but changing this back and forth is a pain. Of course, this unit is named Delphiprofi.FDK.IFDEF.pas!

The other drawback is, you are unable to use the {$UNDEF Foo} in a Unit. So what is the best solution?

Let's collect the necessary things we want to accomplish:

We want to be sure to set important things globally for the whole framework. That's why I use the {$IF Not(Name)} statement. In the past, we all used this stupid {$I defines.inc} approach, but I hate that so much and it also has the problem that your {$IFDEF Foo} is unable to check if you just forgot to include the file. How often have you searched for a problem, because you misspelled a conditional define? I always type  {$IFDEF WINDOWS} instead of   {$IFDEF MSWINDOWS}.
Of course, we can still use normal {$DEFINE Foo} and {$IFDEF Foo} for local unit settings during development. While using the "if not trick" in every unit we are sure that all {$IF not} statements have the right setting... 
And how to use these settings on a project level? Of Course with a normal {$IFDEF} in the Delphiprofi.FDK.IFDEF.pas Unit. In my case, I take this idea one step further by using a class like:

ExcludeFDK = class sealed 
  public
    const
     Logging     = false;
     //... more in the original source
end;

With this, I just can type ExcludeFDK "." and the IDE gives me all possible settings (with the right spelling).

The If looks then like this:

{$IF Not(ExcludeFDK.Logging)}
FDKConfig.GetLogger( Self ).Warning( 'This (%s) should not be happend',[aMSG]);
{$ENDIF}

btw. The FDK is also able to disable logging, based on the Type of the Class the logger is fired from. If I want to disable all the logging from my DI - Container, I just set the exclude of this class in code. Very handy!

To be able to include or exclude - in this example - the logging from a project I can use normal defines on the project level. In this case, it is safe, because I know that all units are set correctly. This it how it looks:

ExcludeFDK = class sealed 
  public
    const
     {$IFNDEF FDKNoLogging}
     Logging     = false;
     {$ELSE}
     Logging     = true;
     {$ENDIF}
     //... more in the original source
end;

If I have no conditional defines in my project settings, the behavior is the default. But by using FDKNoLogging all the logging functionality is not linked to the project.

But this is only necessary if I want to exclude the logging completely from a project to reduce the size. If I keep the logging linked, but do not set a logging target, a NIL logger (empty procedure call) is called with the least possible CPU cycles. So you are able to activate logging - for example - over a command line param.

If you want more information about the logging features like Log to Console, Debug Window, Testinsight, SmartInspect, or to a remote server or any of the other targets, please leave a comment.

That's it for the moment... More is coming...

Friday, January 15, 2021

JWT - The JSON Web Token!

Sometimes I use my free time to discover something new (or new for me).

This time it should be the JSON Web Token.

After the first consideration, I didn't understand the use of it at all... 

I (the server) create a token (Header. Payload), make Base64 out of it, and add a signature by hash with a key. 

OK, so far so good. If I send this token to the client, the client can take a look at it with a Base64 decode. 

(Why should I allow the client to do that?).

The client should send me this token with the next request and I (the server) can apply the hash again and check (the client doesn't know my secret key, which I used for the hash), if the hash matches, that is the way I can check, that it is still "my/valid" token. With the payload, I can then identify the user.

Fine - where is the use case?

The server generates the token after the user-login and doesn't need to store this session token. Cool.

How else was it done in the past? 

Generated a GUID, add a few random bytes, then maybe a cipher, and put this into a database. Next time you could just access the database with the token and after the access, you had everything you needed from the user. And the Client does not know anything about the token or what is stored inside - I prefer this, but:

With the JWT, the session database is not needed and the payload of the token can be used to load the user information. Perhaps for your web application, this simple "User is Valid" information is enough! 

The structure of the token is like this:

Base64(Header) "." Base64(PayLoad) "." Base64(Hash("Header.Payload",Key))

Header and Payload are JSON strings. Of course, someone has made countless thoughts about what has to be contained in the JSON. 

So the header could look like this : {"type": "JWT", "alg": "HS256"}

Token type and hash algorithm.

There is also a rule for the payload (RFC 7519). This may all have a justification and looks like this:

{"sub":"Frank Lauter","iat":1610651797,"exp":1610738197,"iss":"FDK-Token"}

Subject, Issuedat (Timestamp), exp (Expiration Time), iss (Issuer) e.g. the library used.

The algorithm works of course also, if you write completely different JSON in there.

One trick you have to keep in mind is that not all characters of the Base64 encoding can be used as URL-Querry-Param. Normally you would think that just a URLEncode is called because it makes the usual %HexValue stories, but this is not so and also the "=" at the end must be deleted. 

Facebook also uses this coding... As Marco wrote 2012!

If you google for "JWT and Delphi" the first link will be a github repo. 

These 24 units - 173KB source - work very well! ;-)

Perhaps you will like the source and if you have to address all the RFC-Rules you might want to use this... 

Or you just write this few lines in your Webbrocker application:

Yes, you have to insert the DateTime JSON Value, and I set it fix to SHA256 bit. 

You need


If you get back the token with the next call you just use:

for this you need the URLDecode:

You can of course improve this little demo and support different Hashes, or use your own content and give a shit about the RFC's - My Server, MyApp, My Rules!

Have fun...


Sunday, January 10, 2021

Outside the MVVM Pattern?

In the past, I always thought the Model is a class closely related to the MVVM pattern... However, this is not really the case. The model should be able to send notifications or must be able to do some data mapping, but in a real-world application, the Model should be YOUR Class - perhaps implementing some interfaces if necessary.

But this is not the topic for today!

Today I want to talk about colors and other effects. Spoiler: The ViewModel has no knowledge about colors. Neither does the Model. But why do I want to set colors?

To indicate a status, of course. For example, an input is incorrect or that it is a required field. Maybe in such a case, I want to switch the background to red or show a small asterisk next to the input.

So actually I don't want to set a TEdit.Background to red, but just visualize the status.

But what about Visible and Enabled? These states could be part of the view control. Do I make an exception for this?

Sure, I think this is a good idea. Already at the beginning of my MVVM series, I said that I want to adapt the pattern to Delphi and of course to Delphi users and as I know, we all love to disable elements or set the visibility of a whole panel to false, because we need the controls on the panel just in some special reasons. We could do better, but I think I'll make this exception.

If my ViewModel belongs to a RichView, it looks different, because here all font attributes are possible, but this special case I don't mean here.

So how should I send the status to the View? I don't want to create a new label for everything. I'm thinking more about the implementation of Bootstrap or similar systems. There is no color red, it's the status warning, same as not yellow but status is hint. This status can refer to the whole View or only to one or more controls. For this, I still need a nice pattern and possibly a singleton for all views or view groups, so that you can store your own settings.

For verification I dislike the RegEx approach, I would normally call a method. Perhaps the Method is also not in the ViewModel - depends on the problem. In this case, I would trigger the ViewModel and the ViewModel could ask the Model. As everything is just a call for "get status", you can do everything you want with this. This should also be possible from a background thread (perhaps it's a REST or DB request).

I have already implemented a DeepSetter to enable the ViewModel to set everything on the View with a change event. But this was just for the proof of concept. Because if you use this kind of call, you are perhaps unable to change the View. (Bad Idea)

Let's do a list with a bind and not bind. For a TEdit -  of  course, you can bind to everything in code-behind or with an event-token-call, but this list is for the default bindings.

Align - not bindable
Cursor - not bindable
Enabled - bindable
Height - not bindable // But what if I have to resize the control on content?
Hint - not bindable // But perhaps connected to a translation table?
MaxLength - not bindable // Tuff desicion
Password - not bindable // Should be handled by the View (Button show PW)
ReadOnly - not bindable // Fix by design
StyleLookup - not bindable // Fix by design

Perhaps the StyleLookup is the entry point for the status info.

TabOrder - not bindable // Fix by design
Text - bindable // of course
Textprompt - good question // I will decide later
Textsettings - bindable to global Textsettings?

Visible - bindable
Width - not bindable

Now to the Onxxxx Events: (Everything could handle by the View)

OnCanFocus - good question // I will decide later 
OnChange - bindable
OnChangeTracking - bindable

OnClick - not bindable // for a TEdit - a TButton would have this event.
OnDblClick - not binable
... // Skip the list of not bindable events here
OnValidate  - good question // I will decide later 
OnValidating - good question // I will decide later 

Please Remember: For everything not bindable - this is just for the default setting. You are the Developer and if you like to screw up the pattern you could bind to everything.

So what do we have outside the MVVM Pattern?

- Enabled
- Visible

The Status is well inside the MVVM Pattern like:

- TStatus = (Valid, NotValid, Warn, Hint, Information, Mandatory) // Perhaps more?

The View could ask the StyleView-GuideLine-Singelton for display colors based on the TStatus.

That's it, are we done?

It will be a time-consuming process, but I will provide some examples with the #D.MVVM-Framework to demonstrate all these things.

I can't wait to convert my first 780.000 LOC legacy App to #D.MVVM.

Have a nice Week...

PS.: If you've made it so far - Spoiler: Next step is to open the alpha user list. If you are a Delphi 10.1.x - 10.4.x User (VCL & FMX) I will provide a link where you can submit your request.


Friday, January 1, 2021

Happy New Year!

 Hello, my friends!

I hope you are all healthy and have a safe job in these crazy times. The year is over, but I think we will still have a long time of "fun" with it.

For the new year, I have clear priorities. (Besides my main job of course)

1. I want to get my #D.MVVM framework up and running as soon as possible and then release it as the first alpha version.

2. The new version 2.0 of the FDK lay, unfortunately - not at least because of these crazy times - a little bit untouched on disk. Of course, I made some bug fixes and added new features. Not everything I wanted to implement is ready yet, but the #D.MVVM framework has priority because it is the base for all new and old projects. Because such a framework as my FDK, actually has no clear version jumps, but rather a continuous improvement, there is no reason to wait. So if you are interested in my FDK, you could order the current version. Updates will still come.

3. Youtube. I hardly found the time to create a new YouTube video in the fourth quarter of 2020. In addition, unfortunately, the Vol.03 of the D.MVVM series (45. Min.) is destroyed. (Sure I have a backup, unfortunately, the file directory structure of Camtasia is completely stupid and does not collect the necessary clips in one place (or at least there is no function for this), but can use links across all disks and network drives. Unfortunately, there is no warning when saving and so you can easily overlook that large parts of the clips that you dragged into the project are outside the file structure or in temp directories. Actually, you should create a zip and reload it every time you save - this is also the workaround that Camtasia gives).

Actually, I would like to do a live project with the Apocalypse Coding Group again, but we can't agree on a project at the moment.

This brings me to the topic: Comments!

Your comments on Youtube videos or also on my blog post would be very helpful to adapt the topics to your wishes. Of course, I am happy about every subscriber and every reader of my blog, but your comment and a suggestion would be helpful!

So get to the keys... I wish you all a successful new year. May the virus not be with you.