Monday, February 21, 2022

Front End Development Basic Tools

Overview
Npm is your toolbox, including tools such as bower and gulp
Bower is a package manager. It pulls down the javascript libraries you want locally. We (generally) don’t want to keep these in source control, as the gulp optimized ones are kept in source control instead.
Gulp is run over the top of your source files to minimize, optimize, and otherwise process CSS, JS, and Images for production use.
SASS
Sass is a stylesheet language that’s compiled to CSS. It allows you to use variables, nested rules, mixins, functions, and more, all with a fully CSS-compatible syntax. Sass helps keep large stylesheets well-organized and makes it easy to share design within and across projects.
https://sass-lang.com/
https://sass-lang.com/guide
https://css-tricks.com/the-sass-ampersand/

BEM
BEM  (Block Element Modifier) is a styling methodology that helps you to create reusable components and code sharing in front-end development.

Block: Standalone entity that is meaningful on its own.
Element: A part of a block that has no standalone meaning and is semantically tied to its block.
Modifier: A flag on a block or element. Use them to change appearance or behavior.

Official Website: http://getbem.com/
Quick Start: http://getbem.com/introduction/

NPM
npm makes it easy for JavaScript developers to share and reuse code, and makes it easy to update the code that you’re sharing, so you can build amazing things.

Official Website: https://www.npmjs.com/get-npm

Gulp
Gulp is a task runner.

Modern web development has many repetitive tasks like running a local server, minifying code, optimizing images, preprocessing CSS and more. This text discusses gulp, a build tool for automating these tasks. Gulp is a cross-platform, streaming task runner that lets developers automate many development tasks. At a high level, gulp reads files as streams and pipes the streams to different tasks. These tasks are code-based and use plugins. The tasks modify the files, building source files into production files.

Official Website: https://gulpjs.com/
Quick Start: https://gulpjs.com/docs/en/getting-started/quick-start


Also see:
https://developers.google.com/web/ilt/pwa/introduction-to-gulp

Bower
Bower is a package manager. It works by fetching, downloading, and installing packages as needed.

Official Website: https://bower.io/

.NET Core
.NET Core is an open-source, general-purpose development platform maintained by Microsoft and the .NET community on GitHub. It’s cross-platform (supporting Windows, macOS, and Linux) and can be used to build device, cloud, and IoT applications.

Official Website: https://dotnet.microsoft.com/

Also see:
https://docs.microsoft.com/en-us/dotnet/core/

Razor Pages
Razor is a server-side markup language that lets you embed server-based code (Visual Basic and C#) into web pages.

See:
https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-2.2&tabs=visual-studio
https://www.w3schools.com/asp/razor_intro.asp

Nuget
NuGet is the package manager for .NET. The NuGet client tools provide the ability to produce and consume packages. The NuGet Gallery is the central package repository used by all package authors and consumers.

Official Website: https://www.nuget.org/

Moving or pointing a SQL Server database to a new disk location

Sample SQL for Moving SSISDB:
From:
C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA

To:
D:\SQLData

– Check SSISDB settings and they should point to the From files paths

use master
ALTER DATABASE SSISDB SET SINGLE_USER WITH Rollback Immediate
ALTER DATABASE SSISDB SET OFFLINE WITH ROLLBACK IMMEDIATE
ALTER DATABASE SSISDB MODIFY FILE ( NAME = data, FILENAME = ‘D:\SQLData\SSISDB.mdf’)
ALTER DATABASE SSISDB MODIFY FILE ( NAME = log, FILENAME = ‘D:\SQLData\SSISDB.ldf’)
ALTER DATABASE SSISDB set online
ALTER DATABASE SSISDB set multi_user

– Check SSISDB settings and they should point to D:\SQLData

Further docs


See: https://www.sqlshack.com/move-sql-database-files-mdf-ldf-another-location/

Microsoft Doc covering all scenarios:
https://docs.microsoft.com/en-us/sql/relational-databases/databases/move-user-databases?view=sql-server-2017

Moving System Databases:
https://docs.microsoft.com/en-us/sql/relational-databases/databases/move-system-databases?view=sql-server-2017

SSL Cert No Private Key Issue

https://www.ssl.com/how-to/fix-the-iis-7-no-private-key-error-message/

Import and Export Business Central General Journal Entries

Import and Export General Journal Entries Go to my settings and choose accountant
Go to (on top-navigation-men) Journals -> General journals Go to Page Edit in Excel
Microsoft Dynamics Business Central Office Add-in If you have not done so, add the Microsoft Dynamics Office Add-in Open Up the downloaded Excel Since you have the Office Add-in, after a minute or so you should be connected to the server automatically as seen on the right hand side:
Edit or add cell and then “Publish”. Changes should be reflected on the Business Central App. Reload the page on the app. Other Ways Other ways worth exploring: Configuration Package: https://www.youtube.com/watch?v=Gfpazi1PR0k

Sunday, February 20, 2022

OAuth Bearer Token Business Central

Problem Description

The current Microsoft implementation of Web Services authorization is a giant security hole. Anyone who knows the current NON-expiring user id and the access key should be able to read and tamper with the accounting data. Moreover, anyone with sufficient access in user card could generate a new access key.



Microsoft has deprecated the feature and in future releases will not make it available to the Cloud installations of Business Central. (On-premise installation could still use it though for the foreseeable future.)

The OAuth token has a limited lifetime and needs to be constantly refreshed. We could automatically refresh the token - forever. (Only generating the first token requires Azure active directory login.)

(Should we go to prod before Microsoft totally removes the current Web service Access Key method, we need to wipe out any existing web access keys used by the consultants or internal users.)

Register Azure app as described here in detail:

https://www.youtube.com/watch?v=lCzqg2N0vbA 

( Microsoft’s documentation is absurdly insufficient in implementing the plumbing - in this article they the general road map is listed:

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/webservices/authenticate-web-services-using-oauth 
)

The already-registered app is shown below. Note that you don’t need to ever create the actual app. The registration is sufficient - the registration is a proxy to get the access and refresh tokens.

https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade 

In Prod you may have to either alter the registered app’s parameters to point to the Prod URLs or create a new registered app with the new Prod URLs.



Get the first token from PostMan:

Set the parameters and click on “Get New Access Token”. (I could provide you the Postman parameters on Teams. Basically they are derived from the registered app.)
Active Directory login will pop up and you need to supply your credentials.



Copy and paste the access token. and then scroll down and copy and paste the refresh token.

You will put the tokens into a SQL server database. But before executing the SQL, stop the instance of the PDP OAuth Token refresher scheduled task shown below.

update [dbo].[BusinessCentralOAuthToken] set [access_token]=‘YourNewAccessToken’,
[refresh_token]=‘yournewRefreshToken’

Token Refresher Micro Service

// refresh token and the acces stoken are sent as params in a custom object instance of type  BusinessCentralOAuthToken_Result       

private static void UpdateNewTokenFromRefreshToken(BusinessCentralOAuthToken_Result oInputModel)

        {


            // https://docs.microsoft.com/en-us/linkedin/shared/authentication/programmatic-refresh-tokens



            HttpResponseMessage responseMessage;

            using (HttpClient client = new HttpClient())

            {



// Before it expires, refresh the close-to-expiration token using the latest refresh token

                HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, oInputModel.AccessTokenURL);


                HttpContent httpContent = new FormUrlEncodedContent(

                        new[]

                        {

                                        new KeyValuePair<string, string>("grant_type", "refresh_token"),

                                        new KeyValuePair<string, string>("refresh_token", oInputModel.refresh_token),


                                        new KeyValuePair<string, string>("client_id",oInputModel.ClientID),

                                        new KeyValuePair<string, string>("client_secret",oInputModel.ClientSecret),

                        });

               // let the app server provide the date, in case the clocks do NOT match

               tokenRequest.Content = httpContent;

                responseMessage = client.SendAsync(tokenRequest).Result;

            }




            string oJsonReponse = responseMessage.Content.ReadAsStringAsync().Result;

            ResponseModel oModel = JsonConvert.DeserializeObject<ResponseModel>(oJsonReponse);

            if (string.IsNullOrEmpty(oModel.access_token))

            {

                ReportError(new Exception("access_token and refresh_token is no longer valid. Update [dbo].[PDPBusinessCentralOAuthToken] set access_token, refresh_token"), "manually (PostMan) generate a new access and refresh token");

            }

            else

            {

                // write the Model to DB with the new acsess token and the new refresh token

                // this database write code is not shown. Create a table to store the token url, access token, and refresh token and last update time



// this is a verification method to read the latest access token                

BCOAuthBearerToken(oModel.access_token);


            }


        // this is a verification call to insure refresh of a new token worked
        static void BCOAuthBearerToken(string access_token)
        {
            var client = new HttpClient();
            client.SetBearerToken(access_token);

            string result = client.GetStringAsync(ConfigurationManager.AppSettings["BCPlaygroundOdataChartofAccounts"]).Result;
        }


OAuthMicroService

All apps get the latest token from the database through a call to OAuthMicroService project which writes the latest refreshed token into the database

    private static string GetOAuthAccessToken()
    {
        var client = new HttpClient();

        Task<string> resultOrder = client.GetStringAsync(ConfigurationManager.AppSettings["OAuthMicroService"]);

        return resultOrder.Result;

// or get it from the database:
/*IntegrationEntities model = new IntegrationEntities();
var lst = model.usp_GetBusinessCentralOAuthToken().ToList();
return lst[0].access_token;*/
}


Since the token expires every hour or so by Microsoft, we have to get the common token from DB, and NOT form config file(s), and refresh it 24/7 .

(Extending the expiration period of the access token was not possible with an Azure cmdlet. Also the refresh token has a much longer expiration period than the access token. However since we are constantly refreshing with the BusinessCentralOAtuhTokenRefresher
task, our taken would be up-to-date indefinitely. I’ve tested this for days running though automation. )



Backup of logs failed in SQL Server

 Can’t backup in RECOVERY SIMPLE mode. Insure RECOVERY FULL Mode is set:

-- to check recovery ode
SELECT name, recovery_model_desc  
   FROM sys.databases  
      WHERE name = 'Forecast' ;  
GO 

use Forecast;
ALTER DATABASE forecast SET RECOVERY FULL ; 

USE Operations
GO

ALTER DATABASE Operations SET RECOVERY FULL;


USE CreditRequest
GO

ALTER DATABASE CreditRequest SET RECOVERY FULL;



USE FortKnox
GO

ALTER DATABASE FortKnox SET RECOVERY FULL;


Use Model
GO

ALTER DATABASE FortKnox SET RECOVERY FULL;

Also need to do a full backup so that you could do incremental backup of log again:

Solution: BACKUP LOG cannot be performed because there is no current database backup. So run the FULL backup jobs again and should be good.

DBCC ShrinkFile. Transaction Log Full on SQL Server database.

 


Backup and log full errors are handled as follows:

Tran log full:
https://blog.devoworx.net/2016/04/26/the-transaction-log-for-database-sharepoint_config-is-full-due-to-log_backup/

If you are unable to perform any of the previous alternative solutions. In this case, you can perform a shrink operation to reduce the physical file size. By running the following below commands.

--  This example is  for a database named sharepoint_config. Substitue your database here
use sharepoint_config
go
alter database sharepoint_config set recovery simple
go
dbcc shrinkfile('SharePoint_Config_log',100)
go
alter database sharepoint_config set recovery FULL
go

Sample SQL Server RESTORE DATABASE script from backup

-- Sample restore script for a database named "Sample"  whose back up is on Disk at ’C:\YOUR_PATH\Sample_Monday.bak’


ALTER DATABASE [Sample] SET SINGLE_USER WITH ROLLBACK IMMEDIATE

ALTER DATABASE [Sample] SET SINGLE_USER WITH NO_WAIT

USE master
RESTORE DATABASE [Sample] FROM DISK=’C:\YOUR_PATH\Sample_Monday.bak’ WITH REPLACE;

--- After the restore completes

ALTER DATABASE [Sample] SET MULTI_USER