@@nickchapsas I love the video and your work. Wonderful stuff. I am even a PRO on Domtrain to support you! But it is more about how the the Dic variable is pronounced :-)
params was only legal with an array type, not even list, enumerable or the alike. So we also get that, and full support for spans, making the feature complete. Though I still reckon it useless now that we've got collection expressions, which were made for the sole purpose of making it more convenient to express a collection of elements.
I really tried to adopt HybridCache ahead. Although the flags is a great feature to control how items are handled, it is too simplistic. I really missed the plain Get(Async), and the ability to gracefully cancel adding something to the cache. The backplane is also something that is a must for L1+L2 caching IMHO... So for now HybridCahce is the way to go for me...
If you are interested in HybridCache, you may take a look at FusionCache that Nick mentioned, too (shameless plug 😅). It has a very similar design (L1 MemoryCache + L2 IDistributedCache) but it has been around for years, battle-tested in production, is even used by Microsoft itself (eg: see Data API Builder) and has a ton of extra features, particularly around resiliency. Not posting the link to avoid bans, but it’s easy to find. Hope this helps.
We implement feature flags via database settings. By doing it this way, we are able to update the flags value runtime and enable/disable features. With this implementation, we always need to deploy the application with the changed flags values. I haven't found a way around that. Do you have any suggestions?
If the newer stuff in your database is more relevant, and you start using V7, then eventually you will get the benefits I believe. Maybe not as good as if all the guids were V7 but I think it will in the long run. I'm just guessing so take this comment with a grain of salt
Delivering just the standard OpenApi document allows users to use whatever they want. So if one is more of fan of Postman, Insomnia, Rider, etc. you can just import that spec. The other thing that one should worry about is external dependencies, both "what" and "how many". Every external dependency you have could become a risk. For example it might die, get stale, become monetized, even becoming a security risk.
So... "Feature switching" was implemented in COBOL in the 60s and it was WAY simpler to use. Color me unimpressed by this feature. It's also redundant as you've been able to use arguments to do the same thing since probably .NET 1. And if you wanted to drop code out of the compiled output, you could use compiler switches and #ifdef.
FeatureSwitching is a strange mix of compile time and runtime. The project file settings getting built in and the stripping of the code for AOT has compile time behavior while the actual lookup from the static AppContext is runtime. They use that way to setup parameters for GarbageCollection etc. since NetCore and i kinda like choosing between a json and project file better than the old appConfig. In a way it is probably more convenient than building your own static config class or #ifdef but it doesn't seem very elegant to me.
It completely removes the code. Reduces the evaluation by a single if check. Basically, the same as using a ConditionalAttribute w/ a compilation symbol.
Not really seeing the benefit of the new feature flag system. If it's all in memory, then how can I do A/B testing on it. Like, there needs to be a way to toggle the flag externally while the process is running, like feature flagging systems do today.
I am still disappointed that params IEnumerable (or a collection expression converted to IEnumerable) constructs a hidden ReadOnlyArray behind the scenes from the array. Like why? An array is already an IEnumerable, and since it gets created too at that point, there is no code that cares about the elements after the call. Nothing except the target may observe any modifications, and not having access to the underlying array misses out on optimizations performed by the target. "params" or collection expressions should construct the strongest implementation of the interface (that being an array in the case of IEnumerable), not the weakest implementation. Just don't use params or collection expressions with interfaces.
Am I smoking something? LOL... In your first example, my first thought (before you changed the code to use the || operator), I thought you ought to default that to false, b/c if the TryGetFeature fails, you wouldn't want to default to TRUE... but anyway... then you converted the statement to use an OR for the result... but isn't the result of one of these TrySomething(...) calls the result of the "try"? Meaning that if it fails, it returns FALSE, and if it succeeds, it returns TRUE, and the actual result (assuming that the try succeeds), is whatever is output (in this case TRUE if the feature is enabled and FALSE if not)... so in that case, since the TRY always succeeds (e.g. TRUE), and you did a || isEnabled, the result of TRUE || anything is always going to be TRUE. Sorry to be so wordy... Maybe I missed something, because clearly your demo worked, but I'm just wondering what I failed to catch there.
basically if the feature switch can't be found the feature is on by default, otherwise use the configuraiton that was found in the settings. You can change that behavior however you like
Unions is still years off at this stage. It has only been proposed. They're still at the preliminary stage at having proposed an API. They still have to incorporate feedback, implement and validate prototypes, etc. But we still have nice packages in the meantime that can help cross the gap, e.g. OneOf.
So the AggregateBy and CountBy allow us to do what we could already do easily and more readable as follows? from lesson in completedLessons group lesson by lesson.CourseId into g let totalWatchTime = g.Sum(lesson => lesson.LessonDurationSeconds) select $"Course id: {g.Key}: {totalWatchTime} seconds"; from lesson in completedLessons group lesson by lesson.LessonId into g select $"Lesson id: {g.Key}, {g.Count()} times"; Am I missing something?
Feel like he's a little too old to use sexual innuendos in his videos. What is this .NET for middle schoolers? I don't know if anybody actually finds this funny but it really makes him seem less credible and immature.
Thanks for the overview Nick. I still write C# at work, but personally I never create a new project in C#, when there is Go. Overall .NET 9 is a disappointment to me, there are some nice features, but it seems they are trying to please everyone, and lack a strong vision for the future of C#/dotnet. It's a perfectly capable and productive language, just not for me anymore. Thanks
@nickchapsas it still doesn't sort right. You can sort a classic GUID, too, if you wish. Its going to be random order. You can see it from your own video that those 3 values would sort into wrong order.
@@GigAHerZ64you look at them as if they were strings and try to sort them lexicographically left to right. There's a specific bytes placement logic, some of them are even sorted in reverse. Try to sort 20 GUIDs, you'll see.
LIKE this who wait video about EF Core changes
The variable Dic really got me laughing :-)
it's all about that new dic
@@nickchapsas I love the video and your work. Wonderful stuff. I am even a PRO on Domtrain to support you! But it is more about how the the Dic variable is pronounced :-)
Dic, hello 69
Followed by hello 69
Try not to let your dic get too big. You want to keep it managed
params was only legal with an array type, not even list, enumerable or the alike. So we also get that, and full support for spans, making the feature complete. Though I still reckon it useless now that we've got collection expressions, which were made for the sole purpose of making it more convenient to express a collection of elements.
07:17 Nick turns to a salesman for a couple of seconds, his tone, his character even his gesture changes x)
Noticed 😅
I didn't know there were people who existed on the internet without adblocks. Thats crazy!
@@fredrikjosefsson3373 Hahaha, I like my favorite UA-camrs to be paid 😂😂
Genuine question, why did you use the decimal.Add instead of just + the operands?
Stone cold face when referencing the holy numbers. Impressive.
We're doing decimal.Add() over + now?
Yeah, not sure the point. Why would that just be the implementation for the + operator?
I really tried to adopt HybridCache ahead. Although the flags is a great feature to control how items are handled, it is too simplistic. I really missed the plain Get(Async), and the ability to gracefully cancel adding something to the cache. The backplane is also something that is a must for L1+L2 caching IMHO... So for now HybridCahce is the way to go for me...
Having mentioned the backplane I assume you are using FusionCache now, glad you’re liking it (creator here).
Do you plan any Dometrain courses about .NET Aspire or/and GenAI with C#? This would be very helpful :)
Yes and yes
Personally I liked the backing field keyword addition the most.
Great Video, please video for Blazor!
They’re probably slow rolling `HybridCache` because stampede protection feels like such big deal. Gotta be sure it works.
If you are interested in HybridCache, you may take a look at FusionCache that Nick mentioned, too (shameless plug 😅).
It has a very similar design (L1 MemoryCache + L2 IDistributedCache) but it has been around for years, battle-tested in production, is even used by Microsoft itself (eg: see Data API Builder) and has a ton of extra features, particularly around resiliency.
Not posting the link to avoid bans, but it’s easy to find.
Hope this helps.
"some number" 🤭
At this point we really need a reboot of the whole thing where allocations are minimized by default
I dont really follow what benefit that feature flag has over using normal IOptions. Unless you want the AOT trimming that Nick mentions
MORE SPANS!
More about ASP .Net Core and EF
We implement feature flags via database settings. By doing it this way, we are able to update the flags value runtime and enable/disable features.
With this implementation, we always need to deploy the application with the changed flags values. I haven't found a way around that. Do you have any suggestions?
I suppose that is the intended use case. So you can have your own internal features that never get shipped into production.
The weather is the same within like 5 minutes unless you live in London or something 🤣
Came here looking for this comment 😆
Hey Nick, if I switch from monthly Dometrain Pro to yearly will I be able to use Black Friday Promo code?
I wonder why they didn't add SumBy and AverageBy
Why is AggregateBy using decimals (instead of ints or longs). And why use decimal.Add instead of simply + ? Am I missing something?
I wonder if it's a meme or an internal joke.
There's no reason why you'd aggregate integers into a decimal, that's for sure.
Thank GOD for the discount code. I missed my chance the first time and flat out couldn’t afford it lol
Can the V7 Guids replace the old Guid in an existing application or you have to start with it in order to see it's benefits?
If the newer stuff in your database is more relevant, and you start using V7, then eventually you will get the benefits I believe. Maybe not as good as if all the guids were V7 but I think it will in the long run. I'm just guessing so take this comment with a grain of salt
Interesting. Can i use IMemoryCache without the HTTP stuff? In normal .NET, like in a console / WPF app ?
Wonder why the whole swagger ui was removed.
Of course we can go in and add it our self but I need some explanation.
Because its not maintained anymore I think
Delivering just the standard OpenApi document allows users to use whatever they want. So if one is more of fan of Postman, Insomnia, Rider, etc. you can just import that spec. The other thing that one should worry about is external dependencies, both "what" and "how many". Every external dependency you have could become a risk. For example it might die, get stale, become monetized, even becoming a security risk.
I am purely guessing, but I think the original solution might not be AOT friendly as they might use Reflection for discovering endpoints, etc.
So... "Feature switching" was implemented in COBOL in the 60s and it was WAY simpler to use. Color me unimpressed by this feature. It's also redundant as you've been able to use arguments to do the same thing since probably .NET 1. And if you wanted to drop code out of the compiled output, you could use compiler switches and #ifdef.
I also thought it was a useless feature since you could use appsettings.json or #defines.
FeatureSwitching is a strange mix of compile time and runtime. The project file settings getting built in and the stripping of the code for AOT has compile time behavior while the actual lookup from the static AppContext is runtime.
They use that way to setup parameters for GarbageCollection etc. since NetCore and i kinda like choosing between a json and project file better than the old appConfig.
In a way it is probably more convenient than building your own static config class or #ifdef but it doesn't seem very elegant to me.
18:06 "... and kill another library" 😭
Dic is back! :D
Totally random numbers 69 and 420 :)
How is the new Features thing different in practice from reading a bool from IConfiguration?
It completely removes the code. Reduces the evaluation by a single if check. Basically, the same as using a ConditionalAttribute w/ a compilation symbol.
Does domtrain have some certifications I can add to linked in? XD
Press X to Jason.
I’m annoyed Microsoft is still using out parameters in new features. Is it so hard to return an option or result type or just use null?
Press X to JSON
If there a way to configure this feature in runtime (let’s say we are using configuration from aws appconfig)
Nice choice of variable name for a dictionary 😂
"And kill another library" yep Ms doing Ms things 😅
Not really seeing the benefit of the new feature flag system. If it's all in memory, then how can I do A/B testing on it. Like, there needs to be a way to toggle the flag externally while the process is running, like feature flagging systems do today.
dict instead of dic for the next one :D
why was helloWorld greyed out after you changed it to readonlyspan?
because it wasn't used, and was offering a refactor to get rid of it.
@@billy65bob but it wasn't before that either
I am still disappointed that params IEnumerable (or a collection expression converted to IEnumerable) constructs a hidden ReadOnlyArray behind the scenes from the array. Like why? An array is already an IEnumerable, and since it gets created too at that point, there is no code that cares about the elements after the call. Nothing except the target may observe any modifications, and not having access to the underlying array misses out on optimizations performed by the target.
"params" or collection expressions should construct the strongest implementation of the interface (that being an array in the case of IEnumerable), not the weakest implementation.
Just don't use params or collection expressions with interfaces.
Bro had to guess two random numbers, and he guessed "69" and "420", totally random numbers, I don't even know why I am pointing that out.
What's so special about 420?
It’s a drug reference. Personally I think it’s pretty lame.
Am I smoking something? LOL... In your first example, my first thought (before you changed the code to use the || operator), I thought you ought to default that to false, b/c if the TryGetFeature fails, you wouldn't want to default to TRUE... but anyway... then you converted the statement to use an OR for the result... but isn't the result of one of these TrySomething(...) calls the result of the "try"? Meaning that if it fails, it returns FALSE, and if it succeeds, it returns TRUE, and the actual result (assuming that the try succeeds), is whatever is output (in this case TRUE if the feature is enabled and FALSE if not)... so in that case, since the TRY always succeeds (e.g. TRUE), and you did a || isEnabled, the result of TRUE || anything is always going to be TRUE.
Sorry to be so wordy... Maybe I missed something, because clearly your demo worked, but I'm just wondering what I failed to catch there.
basically if the feature switch can't be found the feature is on by default, otherwise use the configuraiton that was found in the settings. You can change that behavior however you like
No discriminated unions again :(
Unions is still years off at this stage. It has only been proposed. They're still at the preliminary stage at having proposed an API. They still have to incorporate feedback, implement and validate prototypes, etc. But we still have nice packages in the meantime that can help cross the gap, e.g. OneOf.
Nothing really new for blazor. They said “Aspire” almost hundred times in this .net conf.
Very disappointing.
ORMs are only for simple ABMs, procesing through and ORM is asking for trouble. That is what SQL is there for.
So the AggregateBy and CountBy allow us to do what we could already do easily and more readable as follows?
from lesson in completedLessons
group lesson by lesson.CourseId into g
let totalWatchTime = g.Sum(lesson => lesson.LessonDurationSeconds)
select $"Course id: {g.Key}: {totalWatchTime} seconds";
from lesson in completedLessons
group lesson by lesson.LessonId into g
select $"Lesson id: {g.Key}, {g.Count()} times";
Am I missing something?
"dic"
what a waste
Feel like he's a little too old to use sexual innuendos in his videos. What is this .NET for middle schoolers? I don't know if anybody actually finds this funny but it really makes him seem less credible and immature.
'Dic' is not the same as 'dick', a synonym for 'penis'.
Thanks for the overview Nick. I still write C# at work, but personally I never create a new project in C#, when there is Go. Overall .NET 9 is a disappointment to me, there are some nice features, but it seems they are trying to please everyone, and lack a strong vision for the future of C#/dotnet. It's a perfectly capable and productive language, just not for me anymore. Thanks
24:30 "sequential", really? They are not sequential, did you look at it? That's the issue. You need ULID, not this mess called UUIDv7.
Sortable would have been the right word
@nickchapsas it still doesn't sort right. You can sort a classic GUID, too, if you wish. Its going to be random order. You can see it from your own video that those 3 values would sort into wrong order.
what do u see as the purpose of a GUID?
@@nickchapsas monotonous
@@GigAHerZ64you look at them as if they were strings and try to sort them lexicographically left to right. There's a specific bytes placement logic, some of them are even sorted in reverse. Try to sort 20 GUIDs, you'll see.
First!
first view and comment
42069. nice....
youtube.com/@ididathing 😂