Caching data backend–.NET Core–part 49

We have 2 options to cache data: One in webAPI, one when returns from database.

For WebAPI, I have read https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-3.1

and

https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-3.1

It is also important to read the conditions for caching : https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-3.1#conditions-for-caching ( e.g. only GET or HEAD is cached)

It is just very easy – see github commit https://github.com/ignatandrei/InfoValutar/commit/b8d38658b5135e4d3c93da78f77ffb9f01376829

Also, can be tested by setting a breakpoint in VisualStudio  – see that is activated just 1 time.

Now, the interesting part – I need the cache for the remaining of the day, in case the exchange rate is in the same day .

Because I need this functionality for both ECB and BNR banks( and may for others), I either create a C# extension, either a base class (instead of an interface ) , either I use a feature of C# 8,  interface that have implementations.

The first try is here: https://github.com/ignatandrei/InfoValutar/commit/3aeeab7a5c519493764a365885b812f3da6ccb8e

Where I have do the code wrong: the key to cache and the items to cache are different. See

https://github.com/ignatandrei/InfoValutar/commit/a68da1f16a27ae06c7978d3acd9b2f1ba1bebc0f

I am using Memory Cache

namespace InfoValutarShared
{
#pragma warning disable IDE1006 // Naming Styles
public interface BankGetExchange
#pragma warning restore IDE1006 // Naming Styles
{
public string Bank { get; }
Task<IEnumerable<ExchangeRates>> GetActualRates();
DateTime Key()
{
var now = DateTime.UtcNow;
if (now.DayOfWeek == DayOfWeek.Sunday)
now = now.AddDays(-1);
if (now.DayOfWeek == DayOfWeek.Saturday)
now = now.AddDays(-1);
return now;

}
IEnumerable<ExchangeRates> TodayFromCache
{
get

{
var keyDate = Key();
string key = $”{this.Bank}_{keyDate.ToString(“yyyyMMdd”)}”;
var mc = MemoryCache.Default;
if (mc.Contains(key))
return mc[key] as ExchangeRates[];

return null;

}
set
{
var keyDate = Key();
string key = $”{this.Bank}_{keyDate.ToString(“yyyyMMdd”)}”;
var mc = MemoryCache.Default;
value = value
.Where(it => Math.Abs(it.Date.Subtract(keyDate).TotalDays) < 1)
.ToArray();
if (value.Any())
{
mc.Set(key, value, DateTime.UtcNow.AddDays(7));

}
}
}

}
}

and using this like this

public async Task<IEnumerable<ExchangeRates>> GetActualRates()
{
var b = this as BankGetExchange;
if (b.TodayFromCache != null)
return b.TodayFromCache;

//code omitted

}
b.TodayFromCache = ret;

return ret;

 

And this is it…

Caching data frontend- Angular interceptors for Observable–part 48

Now I want to cache data for fast loading site- if it comes next time with the same browser, should have some data returned fast – and then load from HTTP. So first return from cache, then make the request

So I need to create an HTTP interceptor to cache things-  fortunately, Angular already provide tutorial about this: https://angular.io/guide/http#intercepting-requests-and-responses  – see CachingInterceptor. And the question is how to return 2 results ( of the same type ) from the same function  ?  Fortunately, the answer is: Observable ! ( It took me a while to figure that intercept returns Observable …). Also, when making the http request, the code should also store the result for the next time.

So I need to combine the 2 observables, one from cache and one from HTTP result  – or I can use startWith ( to start with the value).

First, I wanted to put into a static dictionary ( key: url, value: value of the request) the data. It did not work. Why ? Because of this

 

static cache: Map<string, any> = new Map<string, any>();

//code for finding if we have something in the case

if (CachingInterceptor.cache.has(req.url)) {

//code to put into the cache

this.cache[req.url] = event.body; // Update the cache.

 

Can you spot the error ? ( Yes, I know: Dictionary in C# has tricked my mind)

Last line should be this:

CachingInterceptor.cache.set(url,event.body); // Update the cache.

Now the caching works – but only for local .  And only in memory .

You can find the commit at https://github.com/ignatandrei/InfoValutar/commit/2bde8130add59c84d11d7348ad0a88bb576e356a

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

RxJS–Unsubscribe automatically –part 47

I am searching for a simple method to unsubscribe from Observables. Some of methods are detailed here : https://blog.bitsrc.io/6-ways-to-unsubscribe-from-observables-in-angular-ab912819a78f

I do not want

  1. remember to unsubscribe
  2. being forced to use html ( the async pipe)
  3. take operator – I want later to cache first data and then make the http call
  4. first operator – same with 3
  5. decorator – seems ok.
  6. tsLint – no, can be easy to disable

 

So Decorator it is. More reading

https://www.typescriptlang.org/docs/handbook/decorators.html

https://netbasal.com/automagically-unsubscribe-in-angular-4487e9853a88

Added code the autoUnsub

export function AutoUnsub( constructor ) {

const original = constructor.prototype.ngOnDestroy;

console.log(‘from unsubscribe’);

constructor.prototype.ngOnDestroy = function() {

// tslint:disable-next-line: forin

for ( const prop in this ) {

const property = this[ prop ];

if ( property && (typeof property.unsubscribe === ‘function’) ) {

console.log(‘unsubscribe !’);

property.unsubscribe();

}

}

console.log(‘finish unsub’);

// tslint:disable-next-line: no-unused-expression

original && typeof original === ‘function’ && original.apply(this, arguments);

};

}

Modified code to make property of unsubscribe, e.g. from

this.banksService.GetBanksIds().subscribe(

it=>{

console.log(it.length);

this.banks=it;

},

err=> window.alert(“error:”+ JSON.stringify(err))

)

}

to

banksObs: Observable<string[]>;

//ommitted code

this.banksObs = this.banksService.GetBanksIds();

this.banksObs.subscribe(

it => {

console.log(it.length);

this.banks = it;

},

err => window.alert(‘error:’ + JSON.stringify(err))

);

Created also a new component, for programmers, in order to observe the unsubscribe moving from component to component,

See commit https://github.com/ignatandrei/InfoValutar/commit/66e358848652ce761cb6ef2d69a460f052b12e09

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

Routing angular with .net core and RxJs switchmap- part 46

Now the problem is that the route

 

works if I access first the index.html file, but it does not route when entered directly

Trying to get from SPATemplate

https://github.com/ignatandrei/InfoValutar/commit/a364dc57653ac2ba04ab0596f1540a8f9fdb73f6

However, this will redirect ALL routes to index.html – including swagger and API.  Trying to learn more – looking at the code.

I have observed that I have put

app.UseOpenApi();
app.UseSwaggerUi3();

after

this.route.params.pipe(

tap(rp => {

this.idBank = rp.id;

})

, switchMap((it) => this.bs.GetRates(it.id))

, tap(v => this.rates = v)

).subscribe();

What If I put first?

app.UseOpenApi();
app.UseSwaggerUi3();

app.UseSpa(spa =>

 

And it works! https://github.com/ignatandrei/InfoValutar/commit/726ebd07095ea62387d4eeebb017b4f6ae4ab8e6

What I need more, is to retrieve the exchange rates for today for the selected bank.

The code to retrieve the bank id was:

this.route.params.subscribe(rp => {

this.idBank = rp.id;

}

);

I can put into subscribe the next call, but it will be not so nice ( subscribe into subscribe into subscribe)

this.route.params.subscribe(rp => {

this.idBank = rp.id;

this.bs.GetRates(it.id).subscribe( ….)

}

)

 

Instead of this, I use switchMap , pipe and tap

this.route.params.pipe(

tap(rp => {

this.idBank = rp.id;

})

, switchMap((it) => this.bs.GetRates(it.id))

, tap(v => this.rates = v)

).subscribe();

To fast show data, I use the Json pipe from Angular

<ul>

<li *ngFor=”let rate of rates”>

{{rate | json}}

</li>

</ul>

Modifications at https://github.com/ignatandrei/InfoValutar/commit/a27c7c7beb4ea10b9f8a522b01d558c6003d5386

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

Displaying banks with Angular routing-part 45

Now I want to have a separate URL for each bank, like  https://infovalutar.azurewebsites.net/bank/ECB

For this I read routing in Angular, https://angular.io/tutorial/toh-pt5 .

However , a small problem : when we change URL , from

https://infovalutar.azurewebsites.net/bank/ECB

to

https://infovalutar.azurewebsites.net/bank/BNR

we should re-load component – or the component be aware of changing.

Reading

https://kamranahmed.info/blog/2018/02/28/dealing-with-route-params-in-angular-5/

makes me change from

this.idBank = this.route.snapshot.paramMap.get(‘id’);

to

this.route.params.subscribe(rp=> {

this.idBank = rp.id;

}

    );

Seems little to do, but I have had problems with changing the router-outlet – figuring where to put it. The creation of dashboard component and the routes

const routes: Routes = [

{ path: ”, redirectTo: ‘/dashboard’, pathMatch: ‘full’ },

{ path: ‘dashboard’, component: DashboardComponent },

{path:’bank/:id’,component:BankComponent}

]

were enough trouble.

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

.NET Core 3.0 to .NET Core 3.1 and .NET Core SSL (https )with VSCode + Docker –part 44

To pass from .NET Core 3.0 to .NET Core 3.1

  1. Modify the .csproj
  2. Modify the devops
    • Modify the GitHub Actions
    • Modify the Azure Devops ( because was on Docker , just modify the docker FROM sdk
  3. Modify the dockerfile in the  .devcontainer folder to run in VSCode Container

Some of the modifications here : https://github.com/ignatandrei/InfoValutar/commit/2d5b138ccd6225a6bf69dca47fe76e2270920d2d

However, to have running in Docker container with SSL it is much more difficult. The instruction were here 

https://github.com/microsoft/vscode-dev-containers/blob/master/containers/dotnetcore-3.0/.devcontainer/devcontainer.json

However, some of them implied sharing local pfx , others implies modifying the dockerfile.

And the fact that I should be rebuild the container does not help …as time goes by.

If you look at

https://github.com/ignatandrei/InfoValutar/commit/c371e67aea3a283d3b8c208eec168c795f6fe680

you can see what is necessary that now I have for InfoValutar both .NET Core WebAPI and Angular WebSite running in VS Code on Docker containers.

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

Configure Angular Environment(local and remote) and CORS for .NET Core – part 43

I want to be capable to run Angular with data obtained from local .NET project in development – and from remote website in production. One of the techniques is detailed here

https://angular.io/guide/build

Generated service :

ng g s banks

Now I want to see that every modification of the Bankservice will re-compile. Tried in Docker to run

ng serve –host 0.0.0.0  –poll 200

but it does not show modifications of files changing.

The problem is that not show the files changing generated inside. Time to re-build the docker container for angular

docker container prune -f

docker images “vs*”

docker image rm <id of the prev image>

No modification. The problem was: the BankService was not referenced yet! If I refeerence to the BankComponent, the poll works!

Now let’s see if the Angular Web can access .NET Core WebAPI – no. I forgot to add CORS:

public void ConfigureServices(IServiceCollection services)
{
     services.AddCors(options =>
     {
         options.AddPolicy(“AllowedAll”,
         builder =>
         {
             builder
                 .AllowAnyHeader()
                 .AllowAnyOrigin()
                 .AllowAnyMethod();
         });

    });

// code

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{

    if (env.IsDevelopment())
     {
         app.UseDeveloperExceptionPage();
     }

    app.UseCors(“AllowedAll”);

and now it works – I can see in Angular Web App the banks.

The modifications are in

https://github.com/ignatandrei/InfoValutar/commit/2106328935b972a4411f5412ba3fc810a46399b8

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.