.NET Myths Dispelled
blog.devgenius.io
blog.devgenius.io
That's the best summary of the .NET stack, unfortunately it requires first-hand experience to figure it out.
In the repl?
I have no experience with .net and it looks like these repls are new
Since then I am not able to take seriously the saying of .net to be "incredibly productive".
What were the actual issues and what would've made it more productive? That's much more useful for discussion here.
The backend had to receive events from a webhook and accumulate statistics on those events, then serve these statistics via REST API
Frontend was plain old React reaching the REST API.
Issues:
* The database (MS SQL Server, as recommended by Microsoft) would randomly lock up for days. Bear in mind this was a 1GB of RAM (the minimum amount that Microsoft accepts as enough to run a SQL Server instance) RDS serving around 600 MB of data.
* The introduction of the Repository Pattern (as recommended by the ASP.net documentation) introduced a lot of complexity (including incompleted/non-defined operations) that slowed down significantly the development.
* LINQ supports interleaving DB operations with not-db operations, quickly becoming a O(n^m) footguns. If you make `row => row.x > 5` a method, LINQ will happily download all the rows and run the comparison in program instead of in the DB. Bear in mind I can't construct these footguns with django ORM, or make them typecheck with any Haskell data access framework.
* The test runner UI would pretend no tests existed if the code didn't compile for any reason. Trying to debug something by running a specific failing test? If you miss a semicolon now you have to go find your test again.
* The logger would log the message and the affected class in different lines. Do you want to grep for an error? You better know the obscure grep syntax for "previous line". Want to change the logging format? Good luck finding the code that adds the newline in order to find how to influence it. If you ask the IDE to find the implementation of the logging function it will show you the interface, nothing more.
* You better not do some type of async stuff in LINQ, because the system is going to spawn a process for each entry, obliterating your production instance by creating thousands of processes, using a bunch of MB for each process.
There were more issues, I didn't make an exhaustive list of them because, you know, I don't need to make exhaustive lists of malfunctions and bad design ideas for other programming languages.
Footguns are common.
I am not sure where the .NET community coalesces (python and similar tend to hit up IRC).
I don't understand the dotnet's extension ecosystem -- how to find quality sourcing, etc. Going from an established project into dotnet SDK makes sense. But searching GitHub for useful dotnet frameworks -- stars are probably misleading here?
https://docs.microsoft.com/en-us/sql/sql-server/install/hard...
Am I unwise for following the official Microsoft documentation for a Microsoft product?
Yes, I'm unwise for following it. I shouldn't have accepted the project because it required Microsoft technology. That would be wise.
Also, just sounds like you hate Microsoft, and are looking for (poor) excuses to continue your hatred.
Was the server running Windows? Windows doesn't perform really well in 1G of RAM, especially if you're running GUI Windows and not Windows Server Core. Then running SQL server on top of that, well that 1G RAM probably IS the performance issue. A good rule of thumb is Window takes 3G, and your programs go on top of that.
There were clearly other issues from what the OP described though, and to use LINQ you do have to have a good clear mental model of the runtime actions that it give you. It's a power tool, and can let someone experienced develop very fast, or let someone inexperienced cut their fingers off equally fast!
To provide an answer to OP, about following MS recommendations .. the reality is that not all MS advice is good advice, and also that with so many versions not all of their documentation is up to date. However it seems your team did draw the short straw! Mostly their documentation is very good for product and API level documentation, not as good for architectural documentation.
In the .Net world, if MS released a certain library, that would become the de facto choice for nearly everyone in the ecosystem. Competing with the MS options was almost impossible.
So even if the MS choice had a lot of flaws, it would remain predominant.
Which meant that as long as the MS option was good enough, you wouldn’t see too many alternatives unless they were an order of magnitude better.
And a large reason for this was the closed source nature of .NET.
In the open source world, even if the primary vendor option is great, but it has only a single minor issue, someone will invariably fork it and fix the minor issue. Which puts competitive pressure on the primary vendor to incorporate that fox, or if they’re unable to, see a lot of people migrate to the competing, slightly better offering, which is easy to do since it’s basically the same product with that 1 slightly better fix.
In practice the original vendor almost certainly incorporates the Fox, especially since it’s so easy to do as someone else has already written the code for it.
So IMO the problem with the .NET/C# ecosystem used to be it’s closed source nature, which led to very little competitive pressure for improving tools and libraries, unlike all the primarily open source alternatives you mention.
While I get your point, I personally prefer it this way. Whatever Microsoft will put out will at least be “ok”, regularly bug fixed and supported for ever and ever.
I prefer to having an ok default and just rolling with it.
But this is a tacit agreement in the .NET world. It's not only about libraries written by Microsoft. When sensible libraries such as Automapper or Newtonsoft JSON appear, everybody defaults to them.
A big thing that people often don't understand about .NET is it has the perspective of being all things to all people.
One example of this is that it gives first class support for supporting living extensible systems for long durations like decades which is often not really the case for other stacks. Hence the prevalence for approved long term supported libraries typically with first party backing from MS.
Another aspect of this all things to all people is that it has lower level closer to the metal performance features that people only used to high level stacks often mention they don't see the need for (although they don't say it like that!).
Another aspect is you can do pretty much any kind of application in it, from web to native to high performance games or latency sensitive systems (with some special techniques) to well almost anything. The ability to access low level performance while still having high level general ergonomic APIs is critical to this.
> LINQ supports interleaving DB operations with not-db operations
This hasn't been the case since EF Core 3.0, it will throw an exception if something can't be translated to prevent this problem. Prior to this (EF Core 2.2), a warning would be spat out if an in-memory operation occurs. Due to this, I assume this project was a number of years ago.
> The logger would log the message and the affected class in different lines.
The default logging format is unfortunate, although it can be made a single line in .NET 5 onwards. This issue would've been easily solved by using Serilog, swapping out the built-in logging with a few lines of code. I don't know the last time I encountered a .NET dev that wasn't at least aware of Serilog as an alternative.
The old C# stuff is indeed crusty, intermixed with hot nonsense from the Balmer days.
Latest Framework version is I'd say OK, nothing to write home about, newer stuff is much better (.net 5, 6).
I do think MS SQL Server is a bit, well, bad. But don't worry, irrelevant to the C# stuff - I used to use java servlets to query mssql, while it was better performing than mysql, I wouldn't pick it again.
The anecdote about the React frontend bit is interesting, but ultimately depends on what the UI was doing. JS is certainly good to bang out some quick UI, but if it was shell for the backend, I'd say your app was either mis-designed or just naturally backend heavy.
Again, haven't used (not in web dev right now), but Blazor exists for doing C# web UI, instead of complaining that the backend was bad/hard a better comparison would be between Blazor and React.
Or you could switch architectures and do a non-component-based web UI - faster to put together a mashup of JS junk but it doesn't necessarily perform as well as doing a web client old-style - simple request response works for a lot of use-cases, its not as flashy, but it is fast.
So it looks great for a blog post, for a linkedin thought leader article, but when actually used, you end up duplicating the same shit over and over and over unless you use extension methods. But then why having the damn Repo patterns with the basic methods in the first place?
These patterns are just awful and don't solve anything, abstraction of the DB? You don't need that pattern for that.
It's true, EF abstracts the database away by not requiring you to write SQL but EF is only usable with some SQL databases.
So, having another abstraction layer might not be a bad idea.
Then in startup.cs or program.cs, add this to your services: optionsBuilder.UseCassandra("Contact Points=127.0.0.1;", opt => { opt.MigrationsHistoryTable(HistoryRepository.DefaultTableName, "<schema name>"); });
See more here: https://efcorecassandra.readthedocs.io/en/latest/intro/getti...
You can't. There is no such thing as switching databases "with ease" for any serious application.
Postgres, Redis and Cassandra are all very different databases and it doesn't make sense to switch between them; unless your app is small and still experimental so the changes are trivial, or so large that it's a major project with very specific needs that requires far more work than a repository would solve.
But if you really want to, Entity Framework already has multiple providers including non-relational databases like Cassandra. Anyone can write a provider and there are many 3rd-party libraries for whatever data source you want.
> "having another abstraction layer might not be a bad idea."
It's a terrible idea. It's such an exceedingly rare situation that you're wasting a lot of upfront work for something that'll never be used.
Also .NET has a fantastic data system with LINQ which is built around `IQueryable` and provides powerful query modeling that can be incrementally and dynamically changed before its pushed down to the datasource. It's what makes EF so good and why repository patterns cause so many problems by breaking this interface for no productive reason. You can also use extension methods on the `DbContext` to extract complex queries or large operations to a single method.
Now all that being said, there are times where you can have an abstraction/interface to your data sources if they're very complex or spread across multiple databases or have other processing needs. But at that point you actually need it, instead of just doing it as a "pattern".
I’m sure there are issues with learning curve but the ecosystem is very capable (the corollary to being very productive) but you need to know how to properly use it.
My ego is not unfounded, I have had to do this successfully in other projects, but I can only do it if both the tools, the codebase and the framework allow me to do it
Your explanations of what went wrong show clearly that you still don't have a grasp of how async/await works. So you don't understand the concept, which is now common across a number of languages including javascript (which you claim to know) and python (which you claim to know), dart, and scala.
Based on your technical knowledge of languages you claim to know, I would say you are closer to a junior developer.
If I'm a junior, 99% of the professional programmers out there are simply not programmers at all.
I feel you on the hiring bit, there's such a glut of resume padders, bullhockey purveyors, enterprise leftovers in .Net it's hard to find good people (especially in the US). If you put feelers out to any recruiting firm you'll receive a who's who of people no one will hire. There's also not much of a community to speak of compared to other platforms (what community there is is spread out across numerous platforms or centered around MS, github) so there's not really anywhere you can post your jobs and expect a positive result.
To anyone trying to hire heavy lifting .NET expertise, I am now looking for an interesting fully remote role!
I've been using .NET since V1 and Delphi before that so I have deep exposure to getting things done with this stack and would prefer to work with it compared to most others. I've also worked commercially with about 10 languages so fairly polyglot, just find C# very powerful with a focus on GTD.
Microsoft doesn't force you to use SQL Server. I used Postgres and Redis for a quite big microservice based app.
Repository isn't mandatory, however is nice to separate the business logic from the details of the data store or database. Using a repository shouldn't be a a problem unless you are doing it wrong. I've seen enough of poor repository pattern implementation. I would question the skills of the developers here.
LINQ was not used properly if you had mixed IEnumerable and IQueryable based queries. It's not frameworks fault here, I'm afraid.
The system is not spawning threads for async requests, it's just creating Tasks which cost very little since they aren't physical threads. Think of goroutines, not threads.
All the things you mention seem to be due to lack of experience. I am not sure how using another platform would have yield better results, skill sets remaining the same.
It's not a problem if you try a new language, platform or framework as long as you don't just churn out code assembling method calls based on name (. NET makes this very easy because of intellisense) and examples found on Stack Overflow. As long as you understand what the code does, you are fine.
I think I'm going to go with frameworks that have the actual best reccomendations baked in, instead of the frameworks that recommend footguns.
For every good framework, regardless of platform and language, there is going to be a learning curve. That's because flexibility and extensibility add complexity.
Only a trivial framework with limited use cases would not allow you to make mistakes. I take it you never used C or C+=, because there's a footgun waiting for you at every keystroke. :)
* SQL Server can be incredibly fast with good access patterns, but the rest suggests you didn’t have those. * Yeah, the repository pattern is garbage. I prefer just define the operations you need and use Dapper. * I know some on here are wild about Entity Framework, but personally I’d rather write the SQL myself. You need a good mental model of what’s going on under the hood or what you’ve described happens. * Honestly never used the default test runner because it seems pretty bad. NCrunch, however, is incredible and doesn’t suffer from this. * I don’t think I’ve ever worked anywhere that used the default logging implementation and yes, that format is weird. (You can, however, step into the logging code if you want.) * Depends on what you’re doing, but yeah 10,000,000 Task.Runs is not going to perform well. But I’m not sure the equivalent code works well anywhere except possibly BEAM.
So whilst none of these things cause me problems on a day-to-day basis, I can 100% see how inexperienced devs could drive straight into that tar pit.
This is no longer the case since EF Core 3.0. Only top level projection can contain expressions that aren’t translatable to SQL.
> You better not do some type of async stuff in LINQ, because the system is going to spawn a process for each entry…
I wonder exactly what you ran into. This is not an accurate description of how EF Core’s async support works. Not even if you replace the word “process” with the word “thread”.
The entire premise is dubious, and even if the premise is correct, blaming it on the framework without any other evidence seems like a stretch.
On the projects I’ve worked on recently, the backend often ended up far more complex than the frontend, taking up more time to build and maintain.
This is natural. The backends were responsible for interfacing with other systems, like databases, 3rd party APIs and message queues, for example.
The frontends, on the other hand, generally interfaced with only one system: the backend.
Am I arguing that the frontend is never more complex and time consuming than the backend? Not at all.
But I don’t think you can blame the backend stack and tooling for the resultant imbalance of complexity between the two systems.
And asp.net is fantastic for webapps, especially now that Blazor has become so capable.
The upcoming MAUI framework is also encouraging and should make cross platform native UI development much nicer.
From an objective standpoint it's not a valid comparison. Blazor still has a number of fundamental deficiencies in regards to how it interfaces with the DOM event model via its messaging abstraction. You can't create a symmetrical set of tests without dropping concerns Blazor can't accomplish without custom JS, or limiting the scope of comparisons to what Blazor can do.
The best answer I have is the recent Blazor presentation from Steve Sanderson (the original author) from NDC Oslo conference on 2/21/2022: https://www.youtube.com/watch?v=Rn8psTi8FBk
It's 1 hour and will explain in far more detail exactly how good it is, from hot-reload (which is massive), importing other packages (including native Rust or C source like SQLite), unified server/wasm APIs, prerendering/hydration improvements, EF Core wasm, and even integration with existing JS react/vue components.
Blazor WASM is still unfortunately slow on load, however the recent Steve Sanderson video on Blazor in .NET 6 showed impressive client runtime performance once loaded, by doing virtualized UI access to in process Sqlite for a truly native client performance much better than the current gen SPAs and getting back to how good software used to be, literally instant scrolling over tens of thousands of records.
But Blazor server is really excellent, recommend it.
- https://www.youtube.com/watch?v=LUlbO5MjPjU - https://www.youtube.com/watch?v=HMYpAw2sl58
The main repo has links to all of the announcement posts for every preview milestone release which goes into far more detail: https://github.com/dotnet/maui
Node has so few "batteries included" that you spend a ridiculous amount of time searching npm.
That's especially bad because Node's ecosystem is a graveyard. There are 3-10 libraries for everything, and (if you're lucky) one will be well-tested and maintained. And even then, you're very rarely going to find something that's also: 1) maintained by more than one person, 2) used in production by well-funded developers, and 3) able to keep up with their Github bug reports.
In some cases, I have to try 2-3 libraries before picking one and often switch to another one later.
.NET, on the other hand, has a great ecosystem, batteries included, and (if needed) usually a commercial library for the really important stuff. It's just a far more stable and serious ecosystem in general.
And that is not Javascript's fault because it was never intended to be anything else that a small script language to interact with DOM in a web page and add a bit of interactivity to HTML.
For Web API maybe Go is a reasonable contender if you put up with the boiler plate and verbosity.
As for mobile apps, I didn't encounter anything as productive as Xamarin while being reasonably multiplatform.
I didn't do desktop apps since ages but I remember QT and Embarcadero's C++ builder as being quite productive.
But one platform to do it all? There isn't other. Javascript is today used everywhere but I wouldn't quite qualify it as productive or performant. And countless frameworks and libraries competing with each other kind of makes it a mess.
On the RoR comparison, while coding speed is similar, Blazor is an advancement, and then the runtime perf of .Net 6 vs RoR means having less servers, less cost, and less scaling challenges!
Techempower round 20 has ASP.NET at 309,458, compared to RoR at 8,260. That is 37 TIMES faster for .NET. Think of that as 37 times as much AWS bill for your RoR startup ..
Push they’re buttons all the time calling them Microsoft fanboys… that will get them going. Secretly they like it.
Once over the [quite low IMO] initial 'hurdle', it's easily amongst the most productive & best-supported "platforms" I've ever worked within.
Edit: thanks :)
YARP gives you all of the building blocks you need to build a simple proxy just as easily as a highly complex one.
They also removed the intermixing between server logic and db logic, which greatly reduces nonsense occurring
Btw, I know this is superfluous and very shallow, but for some reason, I can’t get over the C# syntax because of how enterprisey it is. I much prefer ruby, but I guess it’s a matter of preferences and taste
This quality is attractive to managers who benefit by increased headcount, and prefer to have their "reports" or "resources" less generally capable, and more easily replaced or shuffled. Total cost is much higher, but individuals' salaries are lower, which makes managers look good.
Java and .Net are both very enterprisey platforms.
You understand that all the things done in Java and .NET’s “enterprisy” way can be done is most languages right?
This is a programmer problem not a programming language one. Today you have to write less in C# than GoLang, to do the same tasks. Does that mean GoLang is enterprisey now, just because you have to write more?
And, it is not a programmer problem. It is a management problem. None of them would exist without management demand for minimally-productive languages.
Tell me about this secret non “enterprisey” stack you are using.
Think of that as 37 times as much AWS bill for your projects in RoR.. what were you saying about the syntax ¯\_(ツ)_/¯
Not that entity is bad in any way, it’s just not as productive. Which is sort of how I have it with most of the journey into TypeScript. It’s just a really great environment especially in Azure Function apps, and a massive cadeau to Microsoft for making the node in docker such a first class citizen in their Azure environment!
In many ways I feel like TypeScript is a mix of the best of Python and C# and that’s just wonderful, for me.
But writing things like Odata APIs in .Net sure has some benefits from the massive work Microsoft has done with the .net and C# environment since moving core into the main .net or however you describe it.
So now I’m not sure where I am going with this, I’m probably just very appreciative of the work Microsoft has done for us enterprise developers in non-tech enterprise in the past few years.
It's also lacking support for a lot of data types on PG.
It's crazy that EF Core has providers for everything from SQL Server to CosmosDB to Google Spanner to in memory DBs.
LINQ and expression trees are probably one of the best features of .NET.
Yes, I think it is the best ORM in terms of productivity, but it is very, very slow. This is usually not a concern for internal enterprise applications that only have a few people using them at a time though. I guess the other issue is just an issue with ORMs in general - you lose a lot of the in-built features of your sql database, which as projects progress, can ultimately result in you writing the same amount of code as if you didn't use the ORM.
You also can't switch programming languages without rewriting the entire database section. Personally, I stopped using ORMs altogether because I find that they make easy things a little easier, and hard things harder, which isn't a very good value proposition overall. They don't really save me time anymore.
That was long time ago and EF improved a lot since then.
But it can be slow if used improperly. But hand written SQL can be slow too if not carefully crafted.
Sometimes small changes in fragmentation, statistics or data composition will trigger a different queryplan which will affect your query immensely.
Good monitoring and a DBA nearby would be your best bets to overcome this. The point is that using a relational database is not a trivial thing once the database becomes large. Until then its relatively simple.
It does have a built in footgun where for some structures it defaults to invisibly lazy loading sub-collections, you can (almost certainly should) disable that and specifically tell it to populate that data in the first query using Include() or any of the other projection mechanisms. Is it possible you had that?
The benchmarks model simple, but real world scenarios. It has breakdowns by EF, Dapper (the StackOverflow "micro-ORM"), MySQL, PG, and raw ADO.NET.
It should be noted that EF and EF Core are not the same thing; EF Core is more or less a full rewrite: https://docs.microsoft.com/en-us/ef/efcore-and-ef6/
Recent benchmarks have EF Core catching up to Dapper. You can read more about Microsoft's focus on performance for EF Core here: https://devblogs.microsoft.com/dotnet/announcing-entity-fram...
The other thing is that for all ORMS, for the small amount of queries where it really matters, you should drop down to hand-written SQL anyway if the juice is worth the squeeeeze!
If you stopped working with .NET and C# around version 4, the language itself has transformed.
Local functions, pattern matching, records, and more!
It is good, but it's just better to learn TSQL/SQL Server if you are on a windows stack. Shouldn't use it as a crutch especially if you working on the back-end side. Entity framework was created to make data access easier for the front-end people.
Maybe I am too negative on .NET but personally find the open source alternatives easier to work with and more fun.
The interop layer than you have to go through to do a lot of stuff is actually quite tame. It just needs more time on Linux.
What do you mean?
I have software on prod on Linux for years and the only problem I had was lack of some fonts installed that made some problem when it comes to pdf generation
The first iterations of .NET were just for webapps. You could only work with and call .NET code, the only functions provided were basic IO and network.
Interop with native code was always very easy. From PInvoke to managed C++ there were a lot of ways to do it with ease. Things have changed but I still think this is one area where .NET has great support.
I'm curious to know what you needed to do with native libraries. I've been programming with .NET around 20 yrs and find it fairly rare that I need to use P/Invoke... But I'm sure it depends on what you're building.
1: https://withinboredom.info/blog/2019/11/26/detecting-if-a-sc...
You need to use them if you need to control raw GDI objects like bitmaps.
I dunno, Blazor feels like the one ASP framework that makes sense. MVC, Web Apps, Web Forms all feel impenetrable to me.
React is the other way around. Routing in React seems to be an afterthought. And I hate it with a passion.
Page based way of thinking (or "screens" if you will) is a better way to do web dev.
Also, the Dependency Injection system is extremely productive. State management in Blazor is very easy and a breeze to use.
If not for the intricacies of hosting models, and a slightly large default build size for the full WASM client mode, Blazor would have replaced React / Angular / Vue by now.
Sure, but there is a downside to it. You want to add a feature to the class that uses DI? Great, just add an injected object to the constructor. Except now a 100 unit tests broke because you changed the constructor. A 10 minute functionality change turns into a massive cut and paste operation in your Tests project.
I thought tesring was to check software,not be a constraint on software development.
Also, I think using DI in the test process itself will mitigate the issue.
It’s the same with async. Needing an async function somewhere can result in a huge cascade of changes.
Sure in theory this is correct but you can’t always anticipate future needs. The class may still have very clearly defined responsibility but it just needs another piece of information that you can get only with DI. I feel this over dependence on DI in .NET forces you to design around the framework and not around what makes sense.
Maybe I should write this up somewhere.
Please do, as it sounds interesting.
Having worked with a mix of these, I found Blazor to be clearly much simpler, approaching though not quite reaching the simplest possible implementation for a component based UI.
I think it's probably more a matter of what you are used to than inherent complexity. The things you are familiar with seem 'easy' and the unknown seems 'hard'.
Stick with it, it really pays dividends when you get good at it!
Can you give me an example of this offbeat thing you wanted to do that involves overriding an obscure interface?
.NET is big, but if you are using it for web app, your focus is only on that set of libraries. Comparing with similar stacks, none of them cover the area .NET covers.
Also, look at python. People don't see it as big because it does not have an IDE that asks you to select projects and what not, making it seem like it is a tool small enough for their work. However, if you combine every library or framework that covers what .NET does in Python (Web, Desktop, Gaming, System, ML) you will find Python is also just as large.
On any other platform, it's just a good old "console app" equivalent, and you can start multiple services in your main function, catch SIGTERM, and control each service on your own.
On .NET, the project type has to be some weird Microsoft.Web.SDK things if you wanna run asp.net, and the IDE/build system would figure out what dependencies to build. And if I wanna run other services in the same binary, tough luck.
Why can't ASP.NET just be constructed as a regular console app, where you pull in nuget dependencies, instead of a completely different app type, for example.
Here's a simple challenge for you. Create a command line app (your csproj file should say Sdk="Microsoft.NET.Sdk"), ask the user to input a port number at runtime. Use this port number to start an ASP.NET service.
I have not had any luck to pull all the right nuget dependencies to do that so far. The only way to run asp.net app I could find is switching your whole project to be Sdk="Microsoft.NET.Sdk.Web"
https://docs.microsoft.com/en-us/troubleshoot/developer/weba...
That's just an example. The point is mixing a regular console app with an asp.net service.
2. In program.cs add the following lines at the top:
Console.Write("Port number:");
var port = int.Parse(Console.ReadLine());
3. Change the bottom line App.Run()` to app.Run($"https://localhost:{port}");
You now have an application which asks for a port and launches your empty website on that port.A `Microsoft.NET.Sdk.Web` project is still a console app. The "web" variant has some other default packages and (crucially) it has some other defaults for how to compile files such as cshtml.
Several people have pointed out how a web app in .NET 5/6 is really a console app which only starts a web server configured with an application and waits for it to complete (i.e. shut down).
It really is that simple.
When I said console app, I literally meant using the project that you would create if you do `dotnet new console`.
To copy from my other comment:
That is exactly the thing. I do not want to have the Sdk=...Web/Worker. Imagine this scenario, you started a new project with the Sdk targeting Worker. Then you need that binary to also target web. What do you do?
- If you switch the project to Sdk=...Web, you won't have the dependencies to build the worker services.
- If you keep it as Sdk=...Worker, you won't have the dependencies to build asp.net
As I and several people in this thread has pointed out to you, the application the resulting application is not a "web" application. It is a console app that launches a webserver.
The Sdk (without web) is not designed to compile cshtml and/or razor source files. It has nothing to do with package dependencies.
If you do want to start of with a console app sdk, then look at "minimal API". You simply add package references to Microsoft.AspNetCore and Microsoft.AspNetCore.App to your console app, and then you can start using the minimal API samples. They will also launch a website.
The example I showed you above was literally adding two lines and changing one line; and then you had a console app which asked the port and launched a webserver on that port.
If you start from a console app, you will not have build targets configured for cdhtml and razor files. However, to prove that you can launch a webserver the same way you can do this (yes I have tried it and it works):
1) Add dependencies to your "console sdk" project:
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.8" />
2) Replace program.cs with this (this is the entire app): using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Voila. A web server. <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>exe</OutputType>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
Just create an empty ASP.NET Core project, change the SDK, add a FrameworkReference and a OutputType.Read the console args and configure the web app with a port as desired.
This still begs the question, or my original point still stands—why framework reference vs. nuget reference? I'm sure there's a perfectly rationale explanation, but this in itself, having at least two "official" ways of managing dependencies (framework reference vs. package reference on nuget), it's kind of a "code smell" imo.
Why? .NET Core 1.x tried making everything a Nuget package and it was a disaster. ASP.NET is big which meant a huge number of dependencies, easy to create conflicts, long restore and build times.
It was much better to just include ASP.NET Core in the box with .NET and simplify it down to a single reference. And most people use the web SDK which does it for you so they don't even need that.
The other question is, why isn't what you posted the default, but defaulting to this <Project Sdk=...>? To me, it's a lot more intuitive, signaling that each project can have multiple framework references, vs. just one SDK attribute.
Make the simple easy. Make the complex possible.
From Python: have one way of doing things
From Go: explicit is bette than implicit.
Is Sdk=... is just a short cut to pull in a handful of framework references? Or are there actually more things happening under the hood?
Python really isn't a great choice for making your case. "Have one obvious way of doing things" has become an ironic meme since forever, and toolchaining and dependency management has traditionally been a hot mess (yes, even with pip and virtualenv, just not the total clusterfudge it was before. And don't get me started on pipenv.), and only gotten better recently with 3rd party tools like poetry, or even conda.
It's no different to e.g. create-react-app vs npm install react.
thats because they are not directly on nuget. at least not in the included one, you need a framework reference, since for packaging reasons they have a runtime and a "web runtime" (kinda like that)
https://docs.microsoft.com/de-de/aspnet/core/fundamentals/ta...
https://khalidabuhakmeh.com/hosting-two-aspnet-core-apps-in-...
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/ho...
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/ho...
1. search Google, read few articles or posts
2. write code
3. make it compile
4. encounter bugs
5. research the bugs on yet other articles or posts
6. fix the bugs
7. ???
8. profit!
The answer the asp.net team shared below, was instead of using the SDK attribute, use a completely different thing called FrameworkReference. Which can completely replace this SDK attribute, it seems.
Hence my question to them below was, why is framework reference not the default? Especially since it does lead to better searchability, and the template shows that one could have multiple of these per project, intuitively.
I, and a lot of other devs, would be able to solve this particular problem without looking up the docs but I can’t assume any knowledge on the poster’s behalf so I posted the links to the docs about the building blocks and an article showing one possible way of composing them.
The same exact problem as posed by the poster was thought of by the dotnet/aspnet teams and the pieces (apis/docs/samples) are all there, just not the default.
Look through the rest of this comment thread and see how many failed attempts at solving this problem there were before two high profile members of the ASP.NET team came in (JamesNK and davidfowl).
It's not about looking up or not looking up. The criticism here is that the way the framework is laid out is not intuitive enough. It's very "different" from the rest of the industry (in this case, there are 3 potential ways of pulling in dependencies for ASP.NET). This requires a lot of time investment for its users to solve these slight one-off issues.
My question to them below was why isn't what they shared here the default. If they had done that, it would be intuitive to know that one can add other "FrameworkReferences" in a project, or know what to search for. Instead, the default is "each project can only target one SDK".
We got LOTS of feedback that this was all really terrible and we listened.
We did this from .NET Core's inception to .NET Core 3.0 when we pulled the plug. We set things up so that the base install/platform/framework was not composed of packages but framework references. We merged several assemblies together to get rid of some of the unnecessary layering. We invented shared frameworks so that people could install the framework once and run lots of applications using shared libraries so that:
- Customers have faster publish times as you only need to deploy your application bits, the framework can be pre-installed - Loading the same dll on disk into multiple processes allows for more virtual memory sharing (a handy performance optimization) - We could version the set (.NET, ASP.NET Core) as a coherent unit - We could pre-JIT (R2R) the built in stuff so it's installed on the machine once and usable by many apps.
As for being intuitive, the default experience is to use the Web SDK. I didn't even get into SDKs but it does more than default the framework reference. It also exposes capabilities that tooling use to light up behaviors in the build and in the IDE.
PS: This stuff is harder than it looks on the surface and we spend lots of time and take lots of care designing it (making the typical tradeoffs you make when doing software engineering).
> As for being intuitive, the default experience is to use the Web SDK. I didn't even get into SDKs but it does more than default the framework reference. It also exposes capabilities that tooling use to light up behaviors in the build and in the IDE.
It is these "does more than default framework reference" are precisely the things in discussion here. All of these hidden functionalities and dependencies are like a black box. What's the difference between what James shared here and the default Sdk=...Web, then? It's the lack of uniformity, where "ASP.NET is a first class citizen" rather than just another piece of the ecosystem that is a turn off.
Compared to other ecosystems, for example: Go, Rust, even Java for example, where everything is just code that one can pull in, and the customization is in the code, not the runtime/JVM.
- If you switch the project to Sdk=...Web, you won't have the dependencies to build the worker services.
- If you keep it as Sdk=...Worker, you won't have the dependencies to build asp.net
And
>- If you switch the project to Sdk=...Web, you won't have the dependencies to build the worker services.
Yes you will, since the worker sdk is simply a subset of the web sdk.
That's what I have been calling out. I have not had much luck in pulling in the right dependencies needed. Could not find any documentation on it. Everything relies on that Sdk=...Web thing on the official documentation.
If you’re looking for docs on what all the SDKs are/do, and their source code, start here [2].
If you’re looking to just add the asp net core packages/apis to your basic sdk/console project, here [3]. But note that your app build/publish probably won’t work 100% because msbuild won’t be configured to do so.
If you want to fix that manually (i.e do what the Web SDK does automatically), You can use the Web SDK props file as a starting point [4]. (Linked to in [2])
It seems well documented to me, but you’re welcome to propose new docs to the aspnet docs team. They’re very responsive [5].
[1] https://docs.microsoft.com/en-us/aspnet/core/fundamentals/ho...
[2] https://docs.microsoft.com/en-us/dotnet/core/project-sdk/ove...
[3] https://docs.microsoft.com/en-us/aspnet/core/fundamentals/ta...
[4] https://github.com/dotnet/sdk/blob/ee98c8c25188195fd4f8a145b...
We have almost your exact scenario in production - a (Quartz.NET-based) service for background/scheduled jobs, with a web dashboard and a healthcheck API, all from a single console executable without external dependencies. And it was super straightforward to implement.
So, if you want to do what you are saying, you should look into learning more MSBuild because .NET certainly allows you to do that without workarounds if you have your build configured correctly.
Not in the specifics of e.g. your problem, but the big "solutions" tend to be very enterprise solution-y, single-goal orientated. Spring in JAVA (also J2EE) had a similar sort of issue, where everything worked as long as you weren't veering off of the beaten path, but things got wildly over-complicated as soon as you dared to stray...
The claims made in this article also sound a lot like what Java folk would say back when their platform wasn't yet "cool" - they are nevertheless somewhat successful today, so maybe they have a point?
Regardless, you can absolutely do web dev from a simple C# console app, I don't know there are pre-build server frameworks for doing so. If you don't like MS's offering, tough.
Node benefits from being a newer ecosystem (~2009) that started out with simpler goals, so it accumulated cruft more slowly. Ecosystems like node also deploy breaking changes more often - .NET 1.0 software can still be run on a modern Windows machine using the latest regular framework, though as of 5.0 they finally decided to kill existing .NET code (the old framework still works, 5.0 and later just use a separate one).
I'm personally still writing and maintaining .NET 4.x code and some of it is working stuff I wrote in ~2005 and it has been serving me well that whole time. I have extensive experience with C++, JS, Python etc and C# is still my first choice when it comes time to solve problems (Python is a somewhat distant but still respectable 2nd place - the REPL is great.)
From time to time I've been able to solve difficult problems with built-in .NET tooling - I wrote a custom compiler for a DSL from scratch entirely using built-in 4.x features and it can do hot reloading, generate debug information, allow me to set breakpoints in visual studio, etc. I simply can't get this anywhere else.
* OOP is celebrated in the ecosystem. It's time to face the truth: the mainstream (i.e. not smalltalk) implementation of OOP is fundamentally flawed. I have done some pretty fancy stuff with aspnetcore and, OH BOY, does it take a while to unravel and understand that decoupled OOP wet dream.
* Nobody does the high performance stuff in the real world. DDD (which has several valid merits) has many idioms in netcore that are fundamentally incompatible with writing high performance code. You might be able to dilute DDD to achieve tighter code, but if you value explicit clarity above all else then you have limits. Modern procedural languages suffer from fewer opinions when approaching the best of both worlds.
Really this is a rant about OOP and, disagree with me about OOP being broken or not, OOP and OOP idioms are deeply entrenched in netcore (F# included).
Any nice readings you could link me about this view? Thank you!
My personal tipping point was the realization that OOP forces you to first figure out how you solution maps to OOP, before figuring out (or iterating on) how it maps to code. It creates nothing more than accidental complexity: https://emangini.com/2021/07/05-accidental-complexity/
Im just watching now and he advocating for your code to be "procedural" rather than "object-oriented".
And when he says "procedural", he doesnt specificlly mean "functional programming". So, when he says "imperative procedural programming" he means that you have no explicit association between your datatypes and your functions/behavours.
And just to be clear they are not saying its a problem to see an object in your code!! Its the traditional OOO (Object Oriented Objects) that have state and method calls/behaviours.
And thats pretty much the way I code in C#. My data objects are just that. Simple data! And I have other objects that are a collection of functions that take in POD (Plain Old Data Types) objects or return PODs.
He goes on to explain how encapsulation is the problem. Thats where you have an object that holds state/information hidden behind a public interface as well as methods to mutate the state. And when you call that method, it might call through to many other methods on other classes. And if thats the case, it means the object your calling the method on has references to those other classes it depends on. Which means those dependencies/objects must be provided to it via construction.
I have not watched the whole video but I tend to agree with what he is advocating.
- In later versions of .NET, struct enregistrering is very powerful, it promotes struct's contents to CPU registers. You can write high-performance and allocation-free implementations for value objects, monads and wrappers of all kinds without much issues nowadays.
- Guarded devirtualization helps a lot if you heavily rely on interfaces because it allows further inlining and reduces method calls cost.
- Unfortunately LINQ is no match to Rust iterators which get easily vectorized. However, there are low-allocations and simd-ified implementations which might help with your goals. See https://github.com/asc-community/HonkPerf.NET
After all, DDD requires special care when describing its domain definitions in code but you really don't have to go OOP route nowadays for the core logic of your applications. Also records and record structs make it very easy to define contracts and state on the go without having to go with tons of boilerplate I keep seeing in a very much DDD-oriented project my team is responsible for.
And that's the unavoidable reality. My team are extremely open-minded, but I have no idea how to bring up this subject with them.
As for devirtualization: https://www.infoq.com/news/2017/12/Devirtualization/
https://devblogs.microsoft.com/dotnet/performance-improvemen... - you have to go to the section where he talks about devirtualization.
I tried to bind an IConfiguration section to a record but I couldn't since in condensed form a record lacks a default constructor. So I had to write a class like record and add Init to each property to make them immutable.
public record Foo(int X, int Y)
{
public Foo():this(0,0) { }
}
Or make all parameters optional public record Foo(int X = 0, int Y = 0);public Record Foo(int x = default, int y = default);
and it still complained about missing a constructor. I didn't try to add an constructor like you suggested, it's still shorter than defining all members.
How much C# is functional these days? I know linq had the beginnings of it waaaay back in 2010 but do you see a shift in more c# devs going functional instead of OOP? Or is it just another JavaEnterpriseFactoryFactory.cs
We're also stuck with structured exception handling, so we'll have none of that Rust Result<T>, or Go tuple, goodness.
That isn't also the case with Haskell, OCaml and F#?
IMO, if you care about performance you go procedural and watch how your data is aligned and how many allocations you do. Functional programming kind of requires to use immutable data structures, so you end up making copies and that will impact performance.
I don't think you can have both highly performant and expressive code.
I think the main problem with functional .net it that all function types are nominal. Functional C# can get really verbose because of that.
If you don't make use of encapsulation, inheritance and polymorphism, there isn't much OOP. Nobody forces you to use builders, factories, singletons and what not.
https://docs.microsoft.com/en-us/dotnet/fsharp/what-is-fshar...
One of the best functional features in C# is probably pattern matching: https://timdeschryver.dev/blog/pattern-matching-examples-in-...
Lucky you! But most of us, poor folks, are getting paid to write software in an OOP language. The huge majority of the most used programming laguages, C aside, are OOP.
>How much C# is functional these days? I know linq had the beginnings of it waaaay back in 2010 but do you see a shift in more c# devs going functional instead of OOP? Or is it just another JavaEnterpriseFactoryFactory.cs
You can write pretty functional code with LINQ, pattern matching, records. Discriminated unions will be also added in the future.
In the last two projects I was working on, people mostly uses procedural programming. Where you could find some design patterns it was mostly juniors wanting to show off.
C# itself has many functional constructs.
With the modern minimal APIs, you can create a single file web application servers, without ever creating any objects.
OOP is the bread and butter of .NET, just like Java.
-ish. You can't have true FP without a high level of referential-transparency, that's something the CLR doesn't support due to restrictions in the CLR's type-system, which in-turn restricts languages on-top of the CLR like C# and F# (and we see that in the limitations in the F# language).
Back to C# though: Function-references are passed as strongly-typed delegate objects (which include a bound `this` reference), but there's no reification of function parameters: so there's no spread-operator for parameters, nor currying, nor equivalence of delegate-types. There are workarounds for most (but not all) of these issues, but it just results in the tedious writing of wrappers everywhere, which drives me mad.
A trend with C# that I've noticed is that it gets a lot of cool features, but each cool new feature always has a wart on it somewhere.
* User-defined implicit type conversion, but only between user-defined types, not between interfaces, and there's no in-box interface that expresses such a conversion for use as a generic constraint (i.e. we still need an `IConvertTo<T>`).
* If you use interpolated strings you're forced to use CurrentCulture. You need to jump through a lot of hoops to use InvariantCulture or your own interpolation formatting logic (improved in C# 10, but still doesn't address the jump-through-hoops problem).
* Generic type covariance/contravariance, but only for interface types, and when the type-arguments are reference-types.
* Generic type constraints, except they don't participate in overload resolution.
And so on...
I tell people Alan Kay’s 97 OOPSLA keynote “I invented the term object oriented, and this is not what I had in mind”, but I find it difficult to articulate to people who are doing “mainstream” OOP, what they’re missing. It’s like trying to explain the taste of salt.
Just curious if you have any better way of explaining it.
Oddly, I’ve been learning Elixir/Erlang for the last year, and though it’s definitely not OOP, there’s something oddly resonant about it with my Smalltalk past from 10 years ago.
Is it this one?
https://www.youtube.com/watch?v=oKg1hTOQXoY
Edit: I suspect it is this one, at 10:33 Alan says "Actually I made up the term <<object-oriented>>, and I can tell you I did not have C++ in mind."
He cribbed OO for Smalltalk from Simula, same as Stroustrup did for C++. (Smalltalk-72 was not OO.) "OO" is just a name for something that already existed.
Anyway there is nothing very meritorious about OO: it is sometimes the right thing for part of a problem. But organizing a whole language around it is as idiotic as organizing a car design around making left turns.
OOP has its place. I think it's decent in the small - when you're dealing with data structures which inherently have state and need to maintain invariants - and it's decent, in the agent form, in the large, where you have encapsulated state in separate agents which communicate with one another using messages, as long as you have other actor-model things like fault tolerance.
It's in the middle, when you're trying to write a big app filled with communicating mutable objects with lots of mutual references, that things can get pretty sticky. My experience is that it's better to favour complete knowledge of concrete types than to minimize knowledge of concrete types and leave them open to extension. That is, pattern matching is generally preferred to polymorphism and it's better to get a compilation error when you add a new subtype than it is to try and always squish your new subtype into a polymorphic interface straitjacket to use virtual dispatch instead.
There are other problems with object orientation, particularly the way it produces very pointerful code and isn't friendly to - doesn't take advantage of - high latency high bandwidth memory.
If you are referring to ASP.NET then I think you might be describing DI and IoC more than OOP in general.
The evolution of ASP.NET has definitely be one of embracing DI and IoC design patterns.
With ASP.Net Core the conversion is complete as the foundations of that framework are built on DI and IoC design principles.
However, the trouble with DI for newcomers is it can be very hard to understanding what's going, only because of much of the action happens in code that is not visible.
It also means anyone using the framework really has little choice but to also adopt DI and IoC design principles, otherwise they'll just find themselves fighting the framework.
You can, how ever, to not use DI at all. Write the business logic in controllers. Write business logic in static classes. Write business logic in regular classes but instead of registering in DI container you instantiate them yourself.
But .NET is not a beginners coding environment, it is instead designed to support being all things to all people. That includes including high assurance, and high performance. The DI and IoC is there to support high assurance.
.NET is also quite reasonably approachable for beginners, but as a tool with advanced capabilities too there is of course a bit more of learning curve, and if the reasons why the IoC are there are explained earlier on it helps people to understand that it is designed very sensibly, just with a bit more scope than beginner oriented platforms.
I have begun to think that OOP creates more problems than it solves. Added complexity and performance loss being the biggest. It's insane if you peek into a big projects where many developers came and went and each of them read an article about what it seemed an interesting design pattern and tried to implement them.
You can have some kind of procedural programming if you use classes just to store data and use static methods. But the frameworks are OOP and there is no way around that unless you write your own frameworks.
I am a big fan of Mike Acton's Data Oriented Architecture speeches, but I didn't find a way to implement something similar in C#.
For those interested in something better than OOP, here's a few links:
We run an high performance, allocation free automated trading platform on .NET. I guess we are nobody…?
In the future even systems programming might be possible with push towards native apps and direct memory access. If at some point it will be possible to disable the garbage collector and manually manage memory, .NET could be used for everything.
For a company investing in .NET is a good idea since you can move with ease a developer from one role to another. And even if you don't move the developer, having a mobile developer who can read and understand the code for the backend APIs can be quite beneficial.
For me, personally, working with .NET was quite a win. I moved from desktop apps to web, then, when I got bored I moved to the gaming industry as a game developer and now I am again a happy web developer writing microservice based web apps. Meanwhile I also developed a few mobile apps for myself.
While I haven't seen anyone disable the GC completely, plenty of people avoid using it in the Unity/gamedev world. You simply avoid allocating memory (outside of loading) and the GC isn't a problem when it has no work to do. Making sure none of your code allocates at runtime is only difficult if you "don't optimize prematurely" (write shit code without any understanding or regard for performance).
In real life it's next to impossible to avoid GC completely (especially if you rely on assets/libraries/even built-in engine features), but that isn't the goal - it's enough that you avoid allocating managed objects during gameplay simulation. GC can do its thing during level loading, cutscenes, in UI, etc.
.NET was already used for systems level programming, you can read about an operating system build in it called Midori, by MS for research. While slower for some things it was actually faster for other things due to being able to make smarter runtime analysis than VMless code.. there's a fascinating series of articles about it floating around online.
I can clear this one up.
I was lead on a .Net production system launched in August, 2001. It's 21 years.
You can build for:
- Linux (x64, arm) - even raspberry works fine
- Windows (x64, arm)
- MacOS (x64, arm)
The only thing I'm missing atm is BSD, although it might work with Mono, it is not officially targeted. More: https://docs.microsoft.com/en-us/dotnet/core/rid-catalogSome libraries / frameworks I came across that are definetely worth checking out:
- https://github.com/gnaeus/OperationResult - Rust style error handling for .net
- https://github.com/Tyrrrz/CliFx - Command Line Parser library
- https://github.com/Tyrrrz/CliWrap - Shell exec for c#
- https://github.com/Zeugma440/atldotnet - Audio tagging
- https://avaloniaui.net/ - Cross Plattform UI (WPF Style)
- https://github.com/quozd/awesome-dotnet - Other awesome stuff
- VS Code and JetBrains Rider - alternative IDE for c# development
You can also target Android, iOS, game consoles and microcontrollers.
And they forgot 2...
Myth 7: The .NET branding dept sucks.
Myth 8: The .NET desktop strategy has sucked since Build 2011.
Oh wait, both of those are still true.
only if you need cross platform. WPF is pretty good and WinForms still ain't broken. oh you said strategy .. I think the strategy is wait for something to get popular, maybe something will happen with BlazorWebView
But hHow many new official-way-to-do apps have there been? I've lost count.
Actually, what's the current one(s)?
Nearly all commits are bot commits updating dependencies, some are to keep the CI process up to date, and all others only fix typos or other strings.
2 months ago somebody fixed a few things but no activity since then. Microsoft is trying to transition WPF into a community project as indicated by the current roadmap and I don't see this meaning anything different that them abandoning WPF for good.
They've managed the transition well on the technical side of things - as you can see there are plenty of people who are happy with the end result. But it's clear from comments that pop up here that they've really missed the mark when it comes to actually describing the intent behind the whole project, because a surprising number regard it as just an unnecessary exercise in rebranding.
Try to build desktop app in Ruby or in Python, no one cares about desktop apps. If you want to build native desktop apps you go with QT or something C++ based.
.NET branding being confusing is a theoretical problem. When you work day to day with the code you don't care and it does not affect anything I work on. It is not like it somehow affects compilation or some of my code stops working. I use .NET 4.8, .NET standard and .NET Core and now .NET 6 in projects and no problems there.
I take it you never used Photoshop, 3D Max, Autocad, Word, Excel, Visual Studio, Paint or Notepad.
Check out web.autocad.com
There are more and more painting tools available online.
Cloud based IDEs are popping up more frequently.
Not to forget about all web based note apps.
That is the trend and no one cares about creating next Photoshop or Autocad competition on desktop.
Let alone that I mentioned that if someone cares about building desktop app he goes with C++ and QT or something like that and not .NET or Ruby or Python.
We have no more CORE, just .NET.
>And the questions around the GUI toolkits don't help. WinForms is the only thing that is (still) consistently developed - kind of.
MAUI is going to be released soon.
Have you tried to make a desktop app in Ruby or Python? Java desktop apps are also not having some great approach where stuff was changing through years AWT, Swing, JavaFX.
Of course Electron is winning but it is basically a web app wrapped around.
That is such a moot argument.
Winnig from the side of the business or developer, but absolutley not as a user. UX ist just so bad with many Electron apps. They feel slow (and usually they are), they miss a lot of OS specific usability. That's not a win-win.
Myth 10: if Microsoft decides to kill .NET or go in a new direction, you are screwed (at least more than with the mentioned community-developed open source alternatives).
I'd be happy to see these myths dispelled.
Nobody in this thread has mentioned WinUI yet (https://microsoft.github.io/microsoft-ui-xaml/) which makes me think very few people actually know what they're talking about here.
I guess apples-to-apples benchmarks are so hard to agree on that any statement of the form "A is slower than B" is always to some degree a myth. If that's the author's position, fair enough. But if we actually want to make comparisons, "C# is faster than Rust" is a bold claim.
I didn't spent time to investigate further because I feel that this headline is not really useful in the first place.
Comparisons of benchmarks with C# vs. Rust or whatever are unproductive and it's a shame that the article focuses on that. The reality is that you can write C# or F# code today, focus on solving your problem instead of performance, and have it handle a production workload admirably well. That used to not be true circa ~2010. Thankfully it is true now :)
If you don't understand what's happening underneath, these mistakes are easy to make. The worst part is these compound over time, and also aren't obvious at small scale.
This isn't a problem unique to .net though.
I wouldn’t use it now because the big cost is always humans in a project and anything .Net turns into a damage amplifier because of the amount of fettling and dealing with churn you have to do to get anything done. Even with .net 6.
I had a web app in 2006 handling 20k RPS on three dual core/2GB servers without breaking a sweat. This included per-server connection pooling to MSSQL and lots of UDP traffic on top of memcached. It was rock solid.
If it really wasn't slow, why would they have to defend it? We don't see "C is not slow" articles.
Because there’s a justifiable concern from some about a bytecode system being slower than raw machine code. After all, bytecode requires, at a minimum, interpretation to run. And with JIT systems, there’s still a cost associated with it.
You don’t see “C is not slow” because no one is arguing that it is.[a] There’s nothing faster than machine code[b].
[a]: Maybe back in the day when assembly was still king? If the internet was as prevalent 20 years ago as it is now, I’m sure you’d’ve seen articles arguing “C is not slow” compared to assembly.
[b]: Ignoring optimizations. Machine code is as close to the processor you can get.
Maybe. Probably not as bad and slow as you think it is. .NET and Java really don't have the performance overhead that everyone thinks they do, but a corollary of that is C and C++ aren't as fast as you think they are. All that GC tuning you see on JVMs is the same work you do converting to data oriented code in your favorite systems language, you're just fighting the memory wall. While GC's can do it smarter than a human can, they just can't do it for free.
I can't think of a time when Python, PHP, Perl, or Ruby were faster than Java and yet I saw people acting as if they were.
On benchmark C# is giving go run for its money! But again, it is easy to get carried away by benchmarks. Go-routines are a killer feature, .Net async/await come with gotchas.
The weird space of .Net/.net is because the first 15 or so years - it was hostage to Windows. There by tainting its mind-share and engineering culture.
Links (a bit old ones about C# low level chops) https://mattwarren.org/2019/03/01/Is-CSharp-a-low-level-lang... https://www.youtube.com/watch?v=mLX1sYVf-Xg
What are the gotchas?
The only snags I see with async/await are when developers don't know what they're doing and try to force async methods to be synchronous with .Result. If you async it all the way down the stack: your web controller methods are async / your program's main is async, you'll have no issues. It's actually great, because you don't even have to know the internals or what it's doing.
Practicality speaking, this isn't much of a concern for most code, though. I've only really run into this in a couple specific scenarios: unit tests, and when using something like a message bus or cache layer that has a local/in-memory implementation. I noticed only incidentally (as opposed to because of a perf problem): on unit tests where the time got slightly longer when we changed to async, and in the message bus case when doing some performance profiling and using the "local" dev version.
But I had to laugh at their example that “crushes” (why the embarrassing phrasing?) node.js.
Why, returning plain text is as simple as declaring a private “PlainTextActionResult” class that implements the IActionResult and the IActionResult method ExecuteResultAsync, creates an HttpContext.Result, sets the status code symbolically and the content type textually, manually calculates the content length, and returns an asyc Task object!
“Crushed it!” (with Enterprise-y code).
All the enterprisey things in .NET are a god send in a 10k loc web app with solid debug and profiling capabilities.
And all that will save you time and money.
So many developers try to compare the structures of different stacks based on "hello worlds", whereas, the actual issues crop up in actual web development.
With both .net and nodejs.
They both do the job fine (you mention 10K LOC, but I’m not sure that you mean because that’s still comfortably tiny — a one-person app at most, where pretty much anything works.)
In my experience they both scale just fine. Your limiting factors are much more defined by your app architecture, dev group politics (as reflected in response to management), and what I’ll call your dev workflow process (how many minutes is it, between when you as a dev make a final, correct source change, and the change makes it far enough that another person can see and evaluate it in the software?)
var app = WebApplication.CreateBuilder(args).Build();
app.Map("test", () => "hi there");
app.Run();So why the tortured code for the performance test?
Click through to the link to the code. BTW, the link is a screenshot of the code, but that doesn't happen to show the ugly part.
Could be shenanigans, could just be a minor stupidity. IDK, but it doesn't fill me with confidence in the article's general message.
I kinda had the opposite myth, that .NET core is cross platform, in my head. Then one day someone handed us something to actually run on Linux so off I went to try and install .NET on our linux box and run it. That's when I found it was anything but trivial and in fact, nearly impossible to install it without root permissions on the server we were using (HPC compute cluster where admin access is forbidden). Then we ran into all sorts of problems with having the wrong version so about 3 or 4 random attempts at different versions later and after emulating the install in a VirtualBox clone of the OS so we could manually fetch out dependencies, we finally got a version of it that ran.
So yeah, maybe it's technically cross platform but it's a far cry from the portability and deployment story that other languages like Java or even Python offer.
You can compile with the platform/arch specific flags to get a regular linux exe that doesn’t require the .NET runtime to even be installed on the system, and that’s advertised on page 1 of the docs
But I was just super surprised after years of "download JVM, unzip, run, don't care about what linux you are running on" with Java that when I tried to do that with .NET core it was so different. Java is so easy I often embed a JVM for each app I am running. Meanwhile for .NET I could only find operating system specific packages, they all required root to deploy and installed it system-wide rather than locally. Could not find any easy way other than docker to make a self contained deployment.
I see people below telling me this is not so but if that's the case it certainly wasn't obvious when I was doing it (2 years ago).
It took an experienced .net developer two weeks to deploy a .net app to ec2. You had to install .net framework (the versions are so messed up) and then configure IIS to serve the app which due to some weird reason was not picking up the app due to some app pool issue. It was a nightmare.
With Java everything all configurations are in one file and I am done. No tinkering with myriad hidden registry values.
It took an experienced .net developer two weeks to deploy a .net app to ec2. You had to install .net framework (the versions are so messed up) and then configure IIS to serve the app which due to some weird reason was not picking up the app due to some app pool issue. It was a nightmare.
With Java everything all configurationst are in one file and I am done. No tinkering with myriad hidden registry values.
Either they weren't what they claimed to be or, it was so long ago they were using the old Windows-specific Framework versions not Core, or there were some really esoteric requirements, or there was a need to get automatic sign-in using a local Windows account.
For virtually every type of app out there (which doesn't need automatic local Windows account recognition) there is no need to install the .Net Framework at all, and certainly no need for IIS.
Unfortunately, the commenters who actually read the docs and understand the tech are being buried in preference of people who are either deliberately trying to ignore the official documentation (literally just ‘dotnet publish’ and run the exe ‘./myApp’), or are just that green in using a compiled language that isn’t handled by a nice GUI tool in their cloud vendor of choice.
A deployable Linux build of a .Net app (if produced with the proper [and simple] commands) can usually even be deployed onto a bare-bones default server using `scp` and `systemd` for example. I would struggle to think of inventive ways to break an app's codebase in such a way as to make it require what you've described.
This feels disingenuous. The author uses this heading for proof that ASP.net performs faster than similar frameworks in Node/Python. I could be convinced C# is faster than Go, but absolutely not for Rust. The simplicity modern C# provides (look at those code samples) comes at the cost of runtime performance optimizations.
In general, even the best JIT is going to underperform an AOT optimizing compiler for those reasons. Microbenchmarks (and compiler quality) will always vary, but the macro picture is difficult to change.
However, claiming outright that .Net outperforms Rust feels like an apple-to-petticoat comparison.
In practice this mostly means speculative devirtualization. This is absolutely true for C++, which tends to use virtual methods a lot, but Rust doesn't use virtual methods much. Moreover, profile-guided optimization (PGO), which Rust supports [1], allows the Rust compiler to take advantage of these speculative sorts of optimizations just as .NET does.
Granted, PGO is annoying to set up compared to the .NET VM, which "just works". PGO'd Rust is deployed in production, though.
[1]: https://doc.rust-lang.org/rustc/profile-guided-optimization....
I think that one of the things that JIT proponents seem to miss is that JIT compilers have practical limits to the scope of analyses and optimizations that can be done...quick, single pass analyses, basic inclining, etc.
An AOT isn't relying on competing with runtime resources to analyze and optimize code, and it can take a lot of time to do whatever it needs to. I've found that AOT with PGO is the performance holy grail for just about any use case.
(Another benefit is that it allows for generic virtual methods, but that's only indirectly a perf thing.)
That's a very, very slim "may", at least before .NET 6 (I don't keep up with .NET anymore.)
https://web.archive.org/web/20100627105951/http://blogs.msdn...
I'd be surprised if this works in practice because the String processing in C# is surely going to keep making Heap objects ?
You're immediately in a better place here in Rust because people (sensibly) keep developing standards encoded in UTF-8 and so the bytes on the wire are Rust's built-in str type, whereas C# needs to turn them into UTF-16 and store that somewhere as a String.
The new Span<T>, specifically Span<char>, stuff allows you to slice and read strings without creating new objects, and string has both a c-tor for a (readonly) span and a Create method that takes a delegate that allows you to fill the string already allocated on the heap.
Maybe I'm mistaken and magically my C# code which says "string" everywhere is actually converted at runtime to use Span<char> and go real fast? But it doesn't look like it.
The Rust APIs really do take the slice reference &str, it's just normal in Rust to say &str unless you very specifically want a mutable String for some reason (e.g. you're going to insert stuff into it)
While it works (and game developers using Unity tend to use that A LOT to get decent performances), it's also an enormous pain in the ass because you lose most of the “modern” features of C#.
What makes C#/Rust special? If you can't name anything in rust that would actually effect the dataflow analysis then you may need to reconsider.
I say this because I often see Rust people say isn't a great that rust can do xyz and then I look into it and it's actually just basic dataflow analysis that any compiler does or just LLVM being clever.
Garbage collection can make certain programs harder but I promise you can write absolutely awful memory allocators in any language.
Right. Here are measurement results based on the Are-we-fast-yet benchmark suite: https://github.com/rochus-keller/Oberon/blob/master/testcase.... The version of the benchmark translated to C and compiled with GCC or CLANG -O2 runs about twice as fast as the CLI/.NET version. Rust's performance is close to C's. And before you say that Mono is slower than the CoreCLR have a look at these measurements: https://www.quora.com/Is-the-Mono-CLR-really-slower-than-Cor.... But apparently bringing data is a waste of time.
Frankly, bringing apple production data to an orange framers' convention is a waste of time...
I keep seeing you pop up in comments what feels like every time there is something about C# or dotnet or CoreCLR, again and again with your questionable comparisons and "data":
- You're compiling Oberon+ to CLR/IL code using your own compiler. Oberon+ is a language you yourself maintain it seems. It's not C# or F#, which are by far the dominant languages for dotnet. To me at least, Oberon+ seems like a rather esoteric niche language without wide adoption, but I could be missing something.
- The quality of the codegen your Oberon+-to-CLR/IL compiler manages to achieve compared to the dotnet compiler that people would actually use most of the time, that's a big unknown. But I see a real chance that the dotnet compiler, that saw countless hours of development time from a large team of some of the brightest domain experts that MS could find, is outperforming your compiler's codegen.
- How well Oberon+ translates to CLR/IL (or CIL, basically bytecode for compatible .NET runtimes) is another unknown (is it straight forward, does it require the compiler to add a lot of "glue" code or structures to accommodate that language?)
- You're not running your benchmarks on the dotnet CoreCLR, but on mono. And you're trying to handwave this important fact away by linking one of your own quora posts that again uses your own Oberon+-to-CLR/IL-with-my-own-compiler benchmarks that allege to show that there isn't much of a difference between mono and the CoreCLR runtimes. Maybe there isn't, or maybe there isn't just for the very narrow specific IL your Oberon+ compiler produces for the Oberon+ benchmark code you use. But even looking at your own results in your quora post, there seems to be a significant difference in performance even with your narrow use case when comparing mono to CoreCLR 5/6 performance, in favor of the CoreCLR.
- You're running the result of what your own Oberon+-to-CLR/IL compiler spits out on mono-3 (last release 2015, EOL) and mono-5 (last release 2019, EOL) runtimes. Current stable mono-6 was released in 2019. So you're not even running on a current mono release, let alone a current CoreCLR release. The old (mono) runtimes and standard libraries lack a lot of performance-related features that modern CoreCLR versions have (especially when it comes to value types, Span<> and stackalloc, etc, that can be used explicitly in code or in a lot of cases even implicitly by an optimizing compiler)
- You're running on rather old hardware, and a laptop hardware no less. The Intel Core Duo L9400 you mention was released in Q1'06, but according to my google-fu the HP EliteBook 2530p actually uses the SL9400 (is that a typo in your benchmark results pdf?), which was released in Q3'08. It still only comes with DDR2. Would be interesting to know what storage option yours has (as cold-start times of your benchmarks might be dominated e.g. by a slow 5400 rpm laptop grade HDD that is one of the 2530p's storage options). And you run benchmarks on a 32 bit OS. All of which is fine, if you're interested in results on such hardware, but I'd think most people would be more interested in results on slightly more modern hardware.
- You managed this time to comment on a Rust-related post, agreeing that Rust is probably faster, trying to justify this assertion with a set of benchmarks that do not include Rust whatsoever, just saying that Rust performance might be close to C. Which is not a bad hypothesis to start with, but when you go on linking your data and nonchalantly proclaiming that "bringing data is a waste of time" when you didn't bring any data regarding Rust, then I don't get your point.
It is not irrelevant from my perspective. It might be mostly irrelevant if Oberon, as you say, "fairly directly" translates to CRL/IL, that is, there is no need to introduce any (inefficient) glue constructs to support Oberon features. I didn't/do not know this, but if you say this to be the case now, good, that answers my doubts in that regard.
However, this still does not speak to how good the codegen of your Oberon-to-CLR/IL compiler is. Yes, the mono or CoreCLR JIT will apply further optimizations, but in a significant part it relies on the quality of the codegen of the IL it gets passed to do so.
>The fact that Mono is only a factor of two behind is pretty good.
According to your benchmarks. I'd still be a lot more interested in how well the CoreCRL would fare when handed CLR/IL generated from idiomatic C# or F# by the dotnet (Roslyn) compiler. On recent hardware. Or at least a recent hardware architecture.
Right now, it seems to me you're doing something analogous to compiling C with tcc and then making general performance statements about C performance based on tcc generated machine code. Even your own mono-3 and mono-5 results differ, so choice of runtime is clearly a factor.
>It is irrelevant that C# is the most commonly used language on .NET; it is by definition and design a "common language infrastructure", and the article comments on .NET in general (and makes claims at least as adventurous as yours, the ones discussed here also without supporting evidence).
It is not irrelevant. The claims unsupported by any evidence are yours by the way. You made statements about performance, and all you presented is what I consider at best highly questionable methodology. If you make such claims, and try to back them up by "data", you'll have to demonstrate that your Oberon+-benchmark-code-compiled-to-CLR/IR-as-run-on-old-mono-on-outdated-hardware benchmark methodology is indeed something that can be used to make such claims about ".NET" in a sound manner. As I said, I doubt that, and that's all I did, express doubts about your methodology, and why I have these doubts.
> Regarding your nonsensical claims about Span<> and stackalloc, I recommend that you take a look at ECMA-335 and its development over time (and at the generated code).
I have been following standard library and CLR/IR development, and Rosyln compiler development, and therefore know that my statements are not nonsensical. E.g. here[0] is the dotnet "Augments" document that lists, aside from many clarifications, outright additions not present in the latest ECMA-335 spec. See e.g. the changes/additions regarding Byref-like types, which in practice allow for all kinds of optimizations, a lot of them implemented in CoreCLR 5 or 6, but of course only enabled if the compiler's codegen emits these new byref-like type variants.
Furthermore, a lot of the optimizations that current-generation to-CLR/IL compilers and runtimes/JITs perform do not rely on changes to ECMA-335 at all. E.g. as I mentioned above, your mono-3 runs the CLR/IL your compiler generated significantly faster than your mono-5.
>Also your assertion about the relevance of the HDD and the other mentioned hardware aspects makes me doubt whether you have any idea at all about what you are writing here
You're running on a somewhat memory-constrained old machine, so even if you try to run your benchmarks "hot", i.e. have everything required loaded into OS-level caches before the timing starts, I wouldn't be convinced that this is necessarily the case (disk cache pages might have been evicted, and pages in general might have been swapped out and need swapping back in again during a run, and if that happens the HDD performance would play a major role). Additionally, laptops (with relatively early versions SpeedStep-capable CPUs, as your is) are particularly susceptible to additional issues that might adversely affect the reliability of benchmark results, e.g. thermal throttling.
If any of this happens, it might be (but is not necessarily) detectable in e.g. stddev (your benchmarks pdf lacks any mention of stddev, so I cannot know).
I remember trying to benchmark something compute-heavy on my HP Elitebook 8440p[2] back in the day, and gave up after I couldn't get the thing to produce any sane results for different runs of the same code.
The choice of your hardware might as well matter and create vastly different proportional results between the different runtimes you test when the same benchmarks are run on different hardware, even if there aren't any of the problems I described.
As I wrote, your choice of hardware and software (and my anecdote) does not necessarily invalidate your results, but it might render your results rather meaningless for other, more commonly used current generation hardware. And that's something to be aware of.
>so why should people take the effort of making measurements and publishing data?
Sorry, but the effort you obviously put into generating your benchmarks and data does not preclude your work from being poked-and-prodded, questioned and criticized.
[0] https://github.com/dotnet/runtime/blob/main/docs/design/spec...
[1] I am furthermore not sure if you run the same CLR/IL; the mono-3 vs mono-5 seem to be using different versions of your OBXMC as indicated by the different dates that seem to correspond to version numbers for the other things benchmarked?
[2] The variant with the Core i7-720QM if I remember correctly, slightly newer than yours, but probably even more susceptible to SpeedStep and thermal throttling.
…and that’s if you can even figure out how to manage your VS licensing within the deep abomination that is the MS sign-on and management. Most frustrating experience of my life entire professional life was dealing with O365, Visual Studio, and Azure subscriptions.
It's also rare to need what Enterprise has that Professional does not.
I've been forcing myself to use VS Code for my last few C# projects and it's actually quite usable once you get used to the quirks and limitations. The biggest issues:
1) You really need to understand the dotnet CLI tools or you're going to be in for a world of hurt
2) Omnisharp craps the bed way too often. Restarting it from the command palette fixes 99% of the issues though.
3) You need to know the ins and outs of launch.json and task.json in VS Code if you want to do anything more complicated than build and attach. Full VS is much easier to work with here.
FWIW I've had a much better experience with OmniSharp since they shipped a version running on .NET 6 (opt-in with the "omnisharp.useModernNet" setting). YMMV but I need to restart it much less now. https://www.strathweb.com/2022/01/hello-omnisharp-on-net-6-0...
The main stumbling blocks are really around debugging setup. A lot of stuff that VS IDE proper sets up for you automatically you have to manually wire up in VS Code.
But point #5 - "Myth 5: .NET Isn’t Open Source Friendly" is unfortunately still not good enough. It's not enough that Microsoft is no longer actively hostile to open source (especially in .NET), the ecosystem needs to be too, and right now the ecosystem is dominated by first-party offerings and have little serious third party involvement, even when they do exists a lot of them are not open source.
I'm not a great fan of how the whole dotnet open source ecosystem has sped up to monthly and biweekly releases. Official Microsoft packages are some of the worst.
But the industry as a whole has moved to fast releases and MS responded to keep up with the industry. This includes faster releases, and shorter support timeframes.
As many senior devs I also want to retire early from tech. But unlike many, even if I spend hundreds of hours in leetcode, mock interviews, etc. I'm not sure if my work experience would be even considered for an interview at FAANG. Of course I could interview at Microsoft, but it's the only one. Google, Amazon, Facebook, they don't use/hire C# devs at all.
I'm guessing the only path is to learn some Java and sell myself as a C#/Java dev in order to be able to at least get an interview. Any former dotnet dev here that has successfully transitioned into a FAANG position that wants to share advices/experience?
As an aside, I'd be surprised if any of those companies hired specifically based on programming language, surely Are you good at programming is more important than the specific language you have experience with? If you have learned one, you can learn others.
While you are correct, it's not difficult to get hired regardless of the tech stack you work with if you are competent. However, if you care about the tech stack as well (and it is .NET), then the task becomes much harder.
I’ve been noticing what you’ve posted for awhile in regards to interesting opportunities and .NET, or lack there of.
Not sure how to make the switch to something else though.
Don't get me wrong, I have a lot of fun working with other languages and I have learned a great deal. If nothing else, then I feel these experiences made me a better C# developer. It's just that I feel underwhelmed by what the other languages have to offer.
Also take into account I'm looking for some serious amount of money in order to work there for 3-5 years and then retire.
Or maybe a US company that hires remote and pays well? Until now they all prefer to hire in the same timezone so I've had no luck so far (and I haven't seen a remote salary as good as a faang one)
You should move to Scandinavia!, or how about Poland? Also, Ukraine (when things calm down)
But I think it's possible. Most FAANG now are just another big corporation and they are always hiring for all levels of experience. Especially since so many developers seem to retire early I think its doable
Forget the hundreds of hours in leetcode. If you actually want to work for one of those companies, get in touch with a recruiter and see if there’s a role that suits. Ask for prep time later if you need it.
You can certainly get into FAANG as a .NET dev, but I do think there is still a stigma. Not so much the .NET tech stack itself, but the types of companies that .NET typically get used at.
are you saying that there should be more packages in nuget?
>There's also the legacy reliance on XML.
you mean project file?
or WPF's XAML?
Those, and many other things. XML is just an embedded idiomatic part of the language. There's nothing really wrong with XML, but the web runs on JSON now. And all other modern languages (Go, Rust, NodeJS, etc.) are built with that in mind first.
.NET has Newtonsoft Json which makes working with Jsons pretty easy, the built-in System.Text.Json probably works well too (I didnt use it directly yet)
When it comes to XAML, then XML-like structure is way better for describing interfaces than Json
After all, the web is built on HTML which's kind of similar.
That's kind of weird to say these days; I never ever deal with XML in .NET. I'd go as far to say it's 1000:1 JSON to XML for me.
Why? Explain more.
> "legacy reliance on XML"
What reliance? Are you talking about .csproj files? They're very minimal now. XML vs JSON is an old discussion: both are trivial to deal with when small but get unwieldy as they grow (however XML has much better structural support).
Also the .NET configuration system reads from JSON files by default.
- Why do some packages behave differently depending on whether they were installed from an install or restore command? This shouldn't have any observable difference, sync (restore) should be the only operation that touches the package cache at all.
- Opaque reliance on invisible plugin hooks. Back when I had to use it, it was pretty common to get told "oh, just add this random dependency" to fix whatever weird behaviour NuGet got up to that time. Why or how did it fix it? Nobody really seemed to know.
- Binary package managers suck. They make your supply chain more vulnerable, and they are an additional repository to set up and manage. And they tend to lead to losing the knowledge of how to do a full source rebuild at all.
As far as the supply chain, .NET assemblies are IL (intermediate language) and can be inspected and signed to ensure integrity. There are trade-offs but I find it much better than the source-first mess of NPM. Go is interesting but only recently got official module approach and still relies on convoluted path-based references.
I don't see how you'd lose knowledge though, you're still building your own source. You can always copy the raw code from an (open-source/decompiled) package into your project and build that way if you really want to.
Finally, I guess.
> and all nuget ops are part of the main dotnet CLI which is used by the IDEs and other tooling.
Okay? I don't really see what the difference is between `nuget foo` and `dotnet nuget foo`.
> No plugins needed because everything is consolidated to the same process.
Err.. what?
> As far as the supply chain, .NET assemblies are IL (intermediate language) and can be inspected and signed to ensure integrity.
Sure, and you can disassemble all the x86 binaries on your system, too. But that's not the source code that people are reading or writing, nor is it what's tracked in your Git repository. Even if it's signed, the most you have to go on is "the author promises that this is the same as the corresponding source release".
> There are trade-offs but I find it much better than the source-first mess of NPM.
This is a fun example, because it NPM is also binary-first and has exactly the same problems! (Except arguably even worse, because your typical package will ship in 3+ different forms, and good luck finding out which one is actually used when).
For an actual source-first package manager, take a look at Cargo, Nix, or Cabal.
> I don't see how you'd lose knowledge though, you're still building your own source.
You're building your own code (for now), but not that of your dependencies.
> You can always copy the raw code from an (open-source/decompiled) package into your project and build that way if you really want to.
Sure, but you shouldn't have to give up on package management to have a reasonable and trustable build process.
I also had some issues with Nuget, but fair to say that's been the case with pretty much every package manager I've used.
Re trustable build process, some of the .NET team has been blogging about reproducible builds in the last year.
Nuget is not terrible, its not as simple as npm but not far off. Anything that uses native code is painful, but then so is node-gyp..
The language runtime might technically be open source, but it’s got a huge number of closed-source packages and the ecosystem appears to be only begrudgingly open source.
> It’s slower than Node/Python/Go/Rust
One of 2 of these things, aren’t like the others. I’d believe modern .net can outpace Python, but matching or outpacing Rust is something I’d have a hard time believing, especially in the “vast majority of code” sense-I’m aware that .net can be written to stack allocate everything. I’m also aware that basically no .net code I’ve ever seen in business world has ever done that (precluding games here, because I’ve not worked with them).
> It’s for boomer enterprise development
Yes. Uncharitable presentation and framing, but yes. Every single place I’ve worked at that has used .Net has had the same attitude and approach to solving problems and writing code. Use Kafka for our events like every other company in industry? Nah, use some bizarre MS thing that nobody outside of .Net has heard of or can use. Use websockees or SSE? Nah, use some bizarre .Net version instead. Use Postgres because it’s more than good enough and other teams might need to use the database? Nah MSSQL, and all the tables are named and optimised according to EntityFramework and if you have to suffer through ODBC issues that’s a you problem!
Never mind the obtuse naming and the dogged insistence on dependency injection at every possible turn.
Am I not a fan of .Net? Correct. Is it because every time I’ve had to touch it, it’s a painful and frustrating experience.
Other than that: if you go to a .Net shop who want Microsoft Certified Developers and you expect anything than low quality-stay-on-the-Enterprise-support-contract-rails then that's the problem.
> Nah MSSQL, and all the tables are named and optimised according to EntityFramework and if you have to suffer through ODBC issues that’s a you problem!
That's not in any way true - it's an ORM and it can handle any database naming scheme you happen to have. I still wouldn't use it - ORMs in general are a bad idea outside of a couple of use-cases (i.e. CRUD-heavy systems).
.NET Core is open source, free, and comes with the guarantee of no litigation from Microsoft. As far as the ecosystem, it fully embraces open source too. At my company, all .net libraries we use are free and open (AWS, Consul, Elasticsearch, EventStore, Kubernetes, etc).
You will do yourself and your career a favor if you learn it!
I understand it fine, but I think it's far too situational, and greatly overrated. There's so much focus on "abstraction magic" and a desire to avoid admitting you have a dependency or daring to ever actually implement something. It made writing code and debugging code more annoying (everything shows up with "0 references" in VS because...it's all behind DI magic). To say nothing of the verbose, boilerplate setups for it, which were closer to actual incantations than logical code.
I'm sure there's more lightweight ways of doing it, or we should have used a different DI tool, or it shouldn't be done x/y/z-way anymore, but the reality of most DI-afflicated .Net code that I've had to deal with is that it's never done 'well' and all it did was add noise and code that was more difficult to write, debug and maintain.
It falls in the same bucket as most of those other OOP/SOLID/design-pattern principles - half-decent situational guidelines for software that morphed into what amounts to 'holy covenants' that must be strictly applied at all turns.
VS shows all references for code, even if the code is called through DI. If you highlight a method call or a property and press CTRL+F12, you will actually jump to implementation.
>It falls in the same bucket as most of those other OOP/SOLID/design-pattern principles - half-decent situational guidelines for software that morphed into what amounts to 'holy covenants' that must be strictly applied at all turns.
I actually dislike GoF patterns, SOLID, Uncle Bob principles and OOP in general, but DI in .NET is quite decent now. Maybe your experience is from old .NET Framework.
What language have you moved on?
Maybe your setup is better than mine, but I distinctly remember ctrl+f12 not working for a bunch of stuff and having to keep stacks of tabs open.
> Maybe your experience is from old .NET Framework.
Was a mix of framework 4.5 and core 3.1. The other devs worked across both, the projects I was on were core 3.1 with C# v8 specified, basically as close to “as modern as I could get” without running into compatibility issues haha.
> What language have you moved on?
Rust for personal projects and some work stuff-it’s by far my preferred language-, the rest of the work stuff is Scala and Java, largely dealing with Spark.
1. It remains a walled-garden language, subject to Microsoft whims. The only reason Java ever took off was that it offered people freedom from Microsoft sharecropping. It is deeply foolish to yoke yourself and your career to Microsoft again: Microsoft will always ensure they get the major benefits on the platform, not you.
2. It is still almost as badly designed, as a language, as Java.
I had a look at how to deploy a modern ASP.NET thingee the other day and it was super enterprisey. It doesn't produce a single file, it produces a 'publish' folder, and you need something called a "kestrel" server...
Say what you will about node.js but you just run the script and slap caddy or nginx in-front of it.
[0]: https://docs.microsoft.com/en-us/dotnet/core/deploying/singl...
[1]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/se...
Building an app that has the runtime bundled with it (no need to install .Net) or a single file executable is just a matter of setting a few build flags.
Adding an nginx as a proxy is also simple.
Nothing enterprisey about it. Also, the "Publish" folder is basically the "build" folders you get from other stacks.
Native AOT is on the roadmap for net7 which is good but very minimal support. For instance asp.net mvc is a non-goal (https://github.com/dotnet/runtime/issues/61231), so probably another 3 or 4 years before it's well supported.
The author does a good job pointing out that it probably can't be the only language you will need to use - for AWS Lambda functions I still reach for Node instead.
Not really dispelling the notion that ".Net is MS Java" there, but I suppose similar technologies will have similar performance, even if it's politically impossible to acknowledge the lineage. Also, responding to claims that your runtime is slow by bringing up Python, Node, and Go is conceding the point that C is faster, but I find it especially humorous that Java isn't explicitly mentioned. Can't compare Our Product to Brand X, I suppose.
But it was not all terrible, C# was a pleasant language, polymorphism useful, unit testing (nunit) worked well, Team Foundation Server is worth a mention for being a zillion times better than Source Safe. Linq was a sane abstraction. By 2007/2008 MVC looked promising and Visual Studio Pro ran quite reasonable on current spec machines and the things around .net such as SQL Server and IIS were far more pleasant to install and work with on desktop machines.
PS, Let's not forget the MSDN library, documentation and software on CD/DVD and having to strategize what you can fit on your HDD and what you will load from disk.
For those wanting a simple browser UI then use the Nancy framework. Its brilliant for tooling and simple desktop apps.
fav language of all time is Python having used since 2001. There are libs and examples online for everything and then some.
Now learning Go and after that plan to tackle Lua.
Nothing wrong with most mainstream languages for 90% of use cases in their chosen domains. Sometimes the road is rocky but if the basic premise of the language suits your use case then stick with. The speedbumps are good learning experiences.
I work in a large corporate environment, and .NET is expensive. Nobody just 'uses the Community Edition', because there are pre-established licensing arrangements and costs. I've seen the costs.
.NET, whether it's good or not, is slowly going the way of the dodo. What keeps it around is the corporate lock-in they've established for the Microsoft stack, and that's a hard thing to crack.
As for Visual Studio, Professional is all you would need and it's not too expensive, I saw $45 a month mentioned, which is around $2 a working day.
In my opinion, it's actually kind of a good thing that it's not the cheapest option, because it tends to avoid the bottom feeding employers who are more likely to scam their employees.
Just look at his example and how slow dotnet run is, even for a program just outputting hello world.
Not comparing for large compiles. Like the article says, the problem is cold-start performance.
Now you can get a lot of your work without the app restarting.
dotnet watch only helps the developer by not compiling the entire project all the time.
Until .NET 7 aot comes, ready to run is the best it can do.
C# is still on the old OO path coming from Java with respect to that and decorating something with multiple base implementations is still a pain.
https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...
I’m working on a C# project right now where default interface implementations would save me thousands of lines of kludges with extension methods and duplicated class code. Sadly, it’s stuck on .NET 4.8 and can’t be migrated to .NET 6 right now.
> Like many .NET myths, this one originates from the days of Microsoft under Steve Ballmer
- Yes it’s cross platform. However, that does not include Winforms or WPF. Apparently the “multi-platform” in MAUI is “Android, iOS, macOS, and Windows” which means if you don’t care about Linux, you have a potential cross-platform UI option. However, the decision to not include Linux, while not really a terrible act in and of itself, does hint at a bit of the limits of Microsoft’s “friendliness” towards open source.
- Dotnet Core makes async easy, and that’s great. However, when playing around with it, I did notice that it’s the kind of “async” where you need to manually yield if you are not heavily IO bound. It’s not quite idiot proof and you can cause a lot of trouble by holding it wrong. This is not any different from JS or Rust, but it’s worth noting.
- Big eyeroll at the knock on Go regarding generics. I’ve written a lot of Go code and while I think adding generics will be helpful, I can think of exactly one place in existing code I definitely want to put generics after 1.18. It’s one thing to expound on C# language design, which I agree has its merits, but getting into tit for tat comparisons with other languages that have vastly different design goals like Rust and Go is losing enough nuance to be basically meaningless, and then using that to elevate your opinion is just poor form.
- Friendliness towards open source is still sketchy. They did indeed do most of the important things, including, well, move almost everything into the open. Well, almost.
But not quite. Not the debugger for example. See this long-standing issue for some backstory: https://github.com/dotnet/core/issues/505
(There was also some issue with .NET governance that pissed off the community, but I’m not in-the-know enough to grok it, so I’ll just not attempt to poorly explain it.)
Microsoft seems to have a tendency to do this. They give you almost everything, but they hold back some important components. It’s the same with VSCode; try using VSCode OSS. No remoting, no liveshare, no official extension repo. Mozilla doesn’t lock off access to AMO from Firefox forks. Chrome doesn’t lock block access to Webstore from Chromium or its forks. Open source Firefox can log into Sync. Open source Chromium can log into Sync, too. Open source Edge… well, no. Edge is closed source.
Microsoft is indeed not the company that it was under Ballmer. That’s not all sunshine and rainbows, though.
For what it’s worth, I’m not saying that Microsoft is obligated to do anything, or that we’d be better if they never changed. Even vscode-oss and monaco editor are quite nice to have. That said, Microsoft bills themselves as being allies of open source when I feel like this is a pretty dubious position. They’re clearly operating very strategically here; there is little guise of actual goodwill.
At risk of sounding like a nut job, I suspect MAUI not supporting Linux is perfect to go alongside WSL2. From my perspective, Microsoft doesn’t seem to just want to mutually benefit from open source in the traditional way, they also seem interested in trying to shift the community in a certain direction where Windows and Microsoft binary blobs are an important part of open source developers toolkits. A slowly increasing number of killer features will rely on closed source blobs, allowing Microsoft to exert substantial control over the ecosystem, while still maintaining the ability to say “why are you so afraid? VS Code is open source*!”
I still use VS Code despite my concerns, so I’ll leave it up to you to decide what that says about me.
Of course, this move was not received super well either.
It also has many footguns — especially how easy it is to make a seemingly asynchronous action blocking, and ‘async void’ can be a big bag of evil if you’re not careful.
I also really wish that chaining things together with ContinueWith wasn’t so clunky.
Hopefully over time it keeps becoming that little bit better.
Since then, I think It's fair to consider performance benchmarks coming fom Microsoft to be less than trustable.
https://bytes.com/topic/c-sharp/answers/230230-visual-c-net-...
> 3.4 Benchmark Testing. The Software may contain the Microsoft .NET Framework. You may not disclose the results of any benchmark test of the ..NET Framework component of the Software to any third party without Microsoft's prior written approval.
The downvotes are likely because it's 20 years later and TechEmpower benchmarks are neutral and open-source: https://github.com/TechEmpower/FrameworkBenchmarks
> And it works (mostly) flawlessly.
It’s very hard not to roll my eyes when I read this.
No it doesn’t. It’s not mostly flawless, it’s slightly better than using notepad.
It’s considerably worse than the general experience of using vscode.
This has been gone over many times in the past, and I would put it as my #1 c# myth:
1) you can just use vscode
Microsoft has made a business decision to cripple the c# support in vscode to prop up their visual studio division.
It doesn’t “happen to no be as good yet but it’s getting better”.
It will never be a first class c# experience until the business priorities at Microsoft change.
It’s free. So is the visual studio community edition; honestly, if you have to use c# just use that.
C'mon now, syntax highlighting, build integration, debugging, code navigation...
> It’s very hard not to roll my eyes when I read this.
It's not as good as Visual Studio proper but Microsoft has put a lot of effort making C# work well in a variety of editors. VS Code, VS for mac, VS Community Edition are all free to use and I'd argue that any of them offer a better experiences than you'd get with a lot of other languages. Rider is my IDE for C# now, macOS and Windows, so I'm having a hard time buying your argument that Microsoft is trying to aggressively protect this particular turf.
Surely many people are happy with that. Good for them. What is right for them might not be right for me.
For my sanity I don't even want to try. How many times do I need to be burned. "This time is different", fine maybe it is. I'll never find out if MS has really reformed for the better.
I don't think Microsoft cares which tools developers use as long as the result ends-up deployed in Azure.
This is remarkably similar to their old strategy of supporting the ecosystem of Windows applications and then monetizing on Windows licenses.
Context: I’m mostly working as an iOS Developer, but I do have some experience with other languages that are not Swift/Obj-C. I did not have any prior experience with the dotnet ecosystem, though.
When I chose F#/.NET Core for my side project 2 years ago, I was looking for something similar to Swift in terms of pragmatism and reliability (big chunk of available standard/first party libraries), but more mature as an API technology and slightly more functional.
Why more functional? Because I was interested in it. I’m not a religious person.
F# ticked all the boxes. Most libraries you’ll find, that interact with the outside world, are basically functional wrappers around established, mature C# libraries. Those are either first party (ASP.NET Core) or “the standard” (Npgsql for interfacing with Postgres).
A couple of tools and libraries that I use, off the top of my head: Saturn, Npgsql.FSharp, FluentMigrator, NLog, Flurl
Sometimes it feels like I’m the only person tendering that the initial betas for .NET were available on FreeBSD
The tools don't make the developer, and the truly expert developers focus on productivity and results, regardless of environments.
The code-oriented portion of the IDE was also decent, IIRC, with very fast edit-compile-debug loop (something Borland was traditionally good at from TurboPascal days), a capable debugger, and excellent hyperlinked and contextual documentation.
But I haven't used it in more than two decades and it makes me sad if it's really true that it's no longer good.
I also loved Delphi's WebBroker technology, their visual web components were awesome and that tech was so far ahead of it's time I still pine for it. Was writing compiled ISAPI web performance, with fast development, huge amount of high quality libraries, and hot reload! In the year 2000! The only tradeoff was manual memory management, and I guess lack of generics and LINQ.
using Foo;
using Bar;
using Baz;
// somewhere else
var foo = new Bublicon(...); // where tf does this come from?
vs. use std::option::Option::{Some, None};
// ...
Some(1234) // clearly std::option::Option::Some which I can then go find easilyJust hover over it, and you'll find out. Or Ctrl+click to navigate to its implementation, possibly decompiling from IL if the source is not available.
> use std::option::Option::
C# can accomplish similar effect through using alias directive.
Do you have a problem editing HTML? Because that's quite literally XML.
I doubt very much that this is the case..
One of the reasons I love go is that everything seems to be explicit. Notice something occurring? Well chances are you can set a breakpoint and trace what’s happening
What does it mean? dependency injection?
From the tone of the OP I would assume that things such as encouraging good engineering practises such as good interface design and using appropriately sized units of code are also "problems" with .Net. You hear that a lot from inexperienced developers.
The thing is - the modern framework is far nicer and has largely avoided the problem. Even to the point that I prefer occasionally having to deal with some of the ugly enterprise libraries to the constant hunting down of broken dependencies, vague runtime bugs or massive framework churn you see in the Python/Javascript world. Or having an overly verbose and ugly language like Go or Java.
WCF had problems with configuration complexity, but that was because it was ambitious! It had so many capabilities and provided a uniform configuration interface for all of them, so it was complex.
.NET was built as a platform to allow ALL sorts of programming, not just beginners level - therefore it comes with a degree of complexity.
I've come to appreciate that mostly people calling it 'too complex' or 'enterprisey' just haven't understood why someone else needs the features they don't understand yet.
Search for info on .NET and you will find stuff on ASP.NET, .NET Framework, .NET Core at the very least. Probably more.
You have to really know what you are looking for and that's hard sometimes because everything is just .NET
Sometimes I feel like being on JEE 1.4 days.
Gotta love those enterprise architects.
Now go on to work on codebases with rules that every class must have an interface, there are no news, everything must come over service locators, 3rd APIs aren't accessed directly, rather over wrapper classes,....
Ah and no PR ever gets accepted if the rules aren't followed.
Anyway if you hate developing in .Net dont do it but I personally find it a lot more enjoyable than other languages ive worked with.
But like any language, it just takes discipline to stop your team building this bloat.
A CLI app in .NET is as clean as you build it, and sensible frameworks are now available for web stuff too.
It is starting to settle down into a sensible place since .NET 5 though.
If only they would drop ".NET" and "C#" and officially replace them with dotnet and csharp in all material.
I wish they would have just called the new version ".core" and be done with it.
For a long time, it was difficult to figure out if a particular piece of information you found by googling ".net" was for the old or the new. Things are improving though, as the old version gradually fades, so you can reasonably assume the new version unless stated otherwise...
It is , it also is slower to start than Go/Rust, and it takes a while to reach steady state due to the JIT nature of the language
> trailing node.js
yes, it's a shame to be behind node.js
> It’s for boomer enterprise development
It kinda is, other than ASP.NET and Entity, what else do you have? it's bloated enterprise stack only
You need to configure your project with XML, you need to do build scripting with XML, and you can't cross compile, and you can't properly deploy without spitting 400 dlls in your directory
> It’s a legacy platform
It kinda is, containers are all in Go, there is no SwiftUI like frameworks, it still is split between WinForms/WPF/WinUI, and you need freaking XAML scripting
> Myth 1: .NET is for Windows
It depends what you mean by .NET, doesn't it? In-ecosystem a .NET-enjoyer might be thinking about .NET Core, and thinking about building a nice new web API service. But besides that specific case, it still is all just Windows. And I'm not talking about API and ABI dependencies or hard-coded win32 assumptions, I'm talking about making a first-party GUI Desktop application or an application that works together with the OS, natively. And no, until MS dogfoods MAUI in production for a few years, that isn't the silver lining it seems to be (just like SwiftUI doesn't help at all if you're trying to escape NIBs and XIBs - same problems, different flavour).
None of this should come as a surprise, Microsoft does after all still make a separation between 'free' stuff with C# and 'making money' with C#, where the latter is designed as a funnel towards buying something from Microsoft and making sure that it works with Microsoft's stuff (which is: Windows). This isn't a "haha .NET bad" thing, it's just a reality. The same goes for the .NET Foundation. It's essentially still just a shell, controlled entirely by Microsoft. Again, no surprise, but a bit dishonest at the very least.
> Myth 2: It’s Slower than Node/Python/Go/Rust
A few examples where it can be marginally different (faster and slower) but nothing extreme that would make it 'the best choice'. This whole "my language is better because performance metric X" thing might make sense if we're talking orders of magnitude, but we're not (mostly). Also, the bust points out bandwidth, but here is a surprise: bandwidth matters a lot less when it's not the amount of bytes you need to have flowing, but the latency at which the flow starts.
> Myth 3: It’s a Legacy Platform
It's not a legacy platform because you can build new things with it, it's a legacy platform because everything .NET that is already out there is largely legacy. Ironically, this can work out both ways, since well-written C programs can both be legacy and current at the same time. But for .NET, the problem lies with the rather recent pseudo-community opening up and not with only the very last most recent .NET Core release.
> Myth 4: The Tooling is Expensive
It is still expensive because the good tools are always expensive. That is not always a bad thing, if you make money, good tools can be worth their money. But pretending that all tools are the same and therefore the expensive ones don't count as "the tooling is expensive" is not really honest. Again, if you were to make a new project, in isolation, targeting building a self-contained CLI application or API server, you can do that with any text editor. But we're not really exclusively writing code for those, are we? (more on this later)
> Myth 5: .NET Isn’t Open Source Friendly
It's looking friendly but is also very dishonest. See earlier text about the foundation (and earlier posts in HN about the same issue).
> Myth 6: It’s for Boomer Enterprise Development
Not sure how this myth came to be. Existing long-lived applications definitely start entering the Boomer Enterprise Development zone, but that applies to pretty much any language and framework that's been around for a while. See rant about greenfield development and the reality of existing software above.
Now, don't get me wrong, none of this makes .NET explicitly good or bad, but it does smell like a "we are really good, why don't you love us" type of Myth-post. When you start a new, non-Desktop, non-GUI application with proven technologies, then .NET works fine, just like Go, Python, NodeJS and even Java. But in that same sentence, a problem pops up: it always irks me personally that you apparently can't say C# on its own. It's always C#, with a .NET Framework, and a .NET Compiler, and a .NET Runtime. None of that is really swappable, you can't just say "I want to use a different framework" or "I'd like to compile to a native binary". The "one true solution" doesn't exist. A compiler that wants you do use its one and only project management structure seems wrong to me.
Perhaps nobody wants that anymore, or the concept of monoculture being generally bad hasn't landed everywhere yet, but when thinking about a concept of a language, a framework, a compiler and a runtime becomes muddy and developers generally cannot detect a distinction anymore, that just smells enterprise to me. And not in a good way.
yes, mono exists, but the language is created and steered by Microsoft for windows.
you can also run a lot of windows apps with WINE, but that's not gonna make me write windows apps for Linux.
> It’s slower than Node/Python/Go/Rust
literally never heard this complaint, and the first 2 languages have never held the torch of being fast.
> It’s a legacy platform
as I understand, it's pretty actively developed and gets newer features more regularly than Java, but again, it's a Microsoft language.
> The tooling is expensive
Of course you can write and compile C# with other tools. This is the same strawman as #1.
> .NET isn’t open source friendly
TFA said that Microsoft is friendly to OSS since Ballmer retired.
K.
> It’s for boomer enterprise development
This is a stupid argument. Another strawman.
Look, I'm not arguing the merits or tech of the dot Net platform or C# or anything there. By and large, I think it's a good platform, but it's Microsofts baby, so setting up a bunch of strawman arguments for why non MS platforms should adopt a proprietary tech from a company that is overall hostile to open source efforts just comes across as corporate propaganda.
After years of witnessing or being on the receiving end of the things Microsoft did, I'd rather not develop with .NET. Same goes for Google's Go. Rather I'd happily use C++ / Python / Rust / Java / Perl, and never look back.
I think it's bitter to be associated with acts done to undermine and stifle competition for whatever it takes rather than being a tech company known with good products. Yes, I pay for an Office license and like their hardware, but I can't forget what they've done over the years.
Are they selling tools for it? Not that I see.
Are they selling the compiler? Nope (they don't even 'own' it, it's open source)
You really need to explain your thought process here because it doesn't sound based in reality.
Unless and until the "installation strategy" for a .Net program is "copy the binary to the target system" they aren't going for the same kinds of people. That's OK, diversity is good, but don't pretend the differences don't matter.
Super handy for customers who insist on running ancient versions of windows server too.
Compiling to binaries is an advantage but I can guarantee it's not why most people use Go.
Also the rise of containers has obviated much of the issues around deployment and I've never seen "native static binaries" be a requirement for choosing a language stack.
I think I'd still take JS over either though.
"never use ms tech for web, or you be vendor locked and ripped off"
How exactly do you mean this, .Net can be run on most platforms. Or could it be that you didnt read the article since you assumed it was propaganda?
I don't know whether or not that statement is true, but I think this is the point worth discussing.
then somebody has to say some some specific stuff instead of "ms will lock you"
I do use Excel/Word/Outlook etc because companies provide it for me
I do use Visual Studio because I believe it is very good IDE for C# + I know it very well
Azure - is not required to run .net, and .net is not required to use azure.
Sql server - has no advantage on .net than any other wellknown database.
windows net containers - Not sure what you are talking about here but if you use containers, docker linux containers are the default choice.
visual studio premium - As the article mentions there are many alternatives here. For example Jetbrains Rider or VS Code.
dev/test subscription/reservations/devoos - Maybe you are talking about Azure devops. But this is in no way required by .net.
office 365 - Has no whatsoever connection to .net other than being developed by MS.