Crash Course on .NET Core 3.0
Who is addressed to
This tutorial is aimed to C# programmers with at least 6 months experience. Also , they should have at least 6 months experience with HTML / CSS / Javascript .. This will help them to understand .NET Core 3 and how to build applications with the .NET Core framework
The class will be taken by Andrei Ignat, former C# MVP for 6 years, https://forums.asp.net moderator and OpenSource contributor( you can find his AspNetCoreImageTagHelper mentioned on https://github.com/aspnet/Mvc ). More details at his blog at http://msprogrammer.serviciipeweb.ro .
What it contains
Day 1
- .NET Core, .NET Standard, .NET Framework
- Some C# advanced
- C# 8-9 what’s new
- .NET Core 3 what’s new
- .NET Core backend – BL, DAL, Security, tests
- EF – console, ASP.NET Scaffolding
- ASP.NET Core – Heads up
Day 2
- Demo Why DI
- Anatomy of ASP.NET Core
- Plugin Architecture
- Winform / windows service / webapi
- Arhitectura html+webapi demo
Friday Links 355
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
Infovalutar
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/ )
[ADCES] Plugins .NET Core and Combining SaaS,PaaS & IaaS Realtime Micro-Communications
Today I have a presentation about .NET Core Plugins . See you at 7 PM here : https://www.meetup.com/Bucharest-A-D-C-E-S-Meetup/events/267162162/
( The code for the demo is here: https://github.com/ignatandrei/Presentations/tree/master/2020/NETCore3Plugins )
Waiting for you!
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
- remember to unsubscribe
- being forced to use html ( the async pipe)
- take operator – I want later to cache first data and then make the http call
- first operator – same with 3
- decorator – seems ok.
- 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
Infovalutar
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/ )
Friday Links 354
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
Infovalutar
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/ )
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.
Infovalutar
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/ )