|
epalm posted:Firstly, the status code. Sometimes, the user did something wrong and returning 400 is correct. Sometimes, I have done something wrong, and returning 500 is correct. What strategies do you use to return the right status code? I could wrap all user-generated errors in some top-level AppException, catch AppException in every controller action, and generate an appropriate 400 as Bar does above. Otherwise, the exception will skip that catch, and become a 500. Do people do this? You don't need to throw an exception if you're returning a response right from the controller. The way I usually break down responsibility of each layers in your typical web service is with the controller having 2 responsibilities: validate incoming request parameters/headers/whatever, and then respond with an appropriate response code from the result it receives from the service layer. If you're validating input in the controller, you can just return BadRequest() without throwing an exception if the inputs are not valid. You shouldn't be using exceptions for controlling execution flow in general. epalm posted:Secondly, I want to log exceptions. Is there some way other than wrapping every controller action in the same boilerplate try/catch? Use Application Insights if you're using .NET and especially if you're using .NET and hosting on Azure. Gives you a ton of metrics right out of the box with no configuration and is very customizable. epalm posted:Third question, is there a circumstance where the client won't receive a json object with Message, ExceptionMessage, ExceptionType, and StackTrace fields? Or can I count on this structure always being the same when an ApiController throws an exception? You shouldn't be exposing these through your web API. It can be a security list because that stack trace could potentially include things like query strings or worse, configuration information. Even if you're careful to only throw certain exceptions and it's internal use only, you've now coupled the consumers of your API to C# stack traces that are thrown by .NET Core default HTTP error responses. Ideally you're writing web APIs so that if you wanted to, you could rewrite them in a completely different framework/language and not break compatibility with existing consumers. Older ASP.NET projects don't even throw the same errors, they return full error HTML pages or XML in the response. What you should do is return a standard message with just enough information to tell the consumers what the problem is. It could be as simple as a static string, or as verbose as a JSON blob with a bunch of descriptive status fields. e: Mr Shiny Pants posted:What a user does should not cause an exception on your server and the right handling should be in place. Yeah this is pretty much it. As far as exceptions go, here are the codes you're going to end up returning most often: 400 Bad Request - No exception thrown, you validate the incoming request and respond with this if it's not valid 401 Unauthorized - Usually is going to be baked in to your web app framework 403 Forbidden - You'll have to write the code for this usually, request is well-formed and the user is authorized to use the service but lacks the permissions for that request. No exception needed. 404 Not Found - Didn't find what was requested. Usually it'll be because your data access layer returned null/empty/empty list when you queried your database or another web service. No exception needed. 405 Method Not Allowed - Usually is going to be baked in to your web app framework 500 Internal Server Error - Some exceptional condition that isn't being handled happened while trying to process the request. Exception thrown, but you should still probably not expose a full stack trace to the consumer. ThePeavstenator fucked around with this message at 06:04 on Jan 6, 2019 |
# ¿ Jan 6, 2019 05:55 |
|
|
# ¿ May 17, 2024 17:22 |
|
epalm posted:I re-read and this struck me as odd. What's the point then of being able to catch specific exceptions? Let's take this example you posted: epalm posted:
I assume this is a minimal example and there's more in that try block in your actual code, but basically what the "throw new Exception();" does in this example is act as an expensive goto statement. If you're throwing an exception, the code you're writing should either reach a condition that it doesn't know how to handle, or is beyond the scope of what it should handle and needs something up the call stack to deal with it. As an example from the .NET Framework source code: C# code:
If you're the caller (or a caller further up the stack), you can choose to handle this condition because how it should be handled is unambiguous for your use case. For example: C# code:
So to take your code and remove the exception performing control flow: C# code:
ThePeavstenator fucked around with this message at 08:51 on Jan 6, 2019 |
# ¿ Jan 6, 2019 08:48 |
|
If you're able to just do everything through version control, it has the added bonus of getting new programmers into the habit of using it as a part of their workflow right away. Visual Studio has a decent GUI for Git so they don't have to tackle the command line if that's something you want to avoid. If you need the repos to be private, GitHub now has free private repos that allow up to 3 contributors, and Bitbucket allows private repos with up to 5.
|
# ¿ Feb 6, 2019 14:50 |
|
BIGFOOT EROTICA posted:Right but I don't just have one object making these requests, i have 10 (or however many) that each have different sessions/cookies etc for scraping Inside of the doasync() method, put the while loop around whatever async logic you want to continue.
|
# ¿ Feb 6, 2019 20:15 |
|
User0015 posted:Phone posting here, but what happens to events when a using statement completes? For example foo holds a reference to the SomeHandler action delegate, not the other way around, so foo will get GCd
|
# ¿ Feb 28, 2019 02:09 |
|
LongSack posted:The only time I’ve done anything “clever” (in the pejorative sense) is my Time class, which freely converts to/from double where, for instance, 12:30 pm can be represented as 12.5 even ignoring the comparison thing, you will heavily regret writing any time implementation yourself the second you have to deal with anything other than static time stamps if you have any logic surrounding time don't even use the .NET DateTime types, just use NodaTime LongSack posted:and (IMO) the code reads cleaner. less text =/= cleaner code
|
# ¿ Feb 28, 2019 02:18 |
|
if all of your code is basically just scripts for your own productivity and you know all the implementation details in your head than it's probably fine, but don't mistake abstraction for making things cleaner
|
# ¿ Feb 28, 2019 02:24 |
|
EssOEss posted:Oh huh what happened now? You can host .NET Core 2.2+ apps in-process on IIS itself instead of the .NET Core app running on a Kestrel host with IIS acting as a proxy forwarding requests to it. When I say "you can" I mean "you should" unless you've got multiple .NET Core apps running behind a single IIS proxy (you should not do this).
|
# ¿ May 22, 2019 23:14 |
|
LongSack posted:Oh, and if you’re wondering why use Expression<Func<foo, bool>> rather than just Func<foo, bool>, it’s because Where with the latter returns an IEnumerable<foo>, so you can’t add, say, an .AsNoTracking(). Where with the former returns an IQueryable<foo>, so you can. Expression<Func<foo, bool>> is an expression tree, which means it's a declarative set of instructions that are interpreted at runtime. Your Linq code on an IQueryable is really just adding more instructions to the expression tree. Then at runtime something like EF can interpret the expression and turn it into something like a SQL query and send it to a database. AsNoTracking() is just an extension method on Expression<> that adds to the tree and be interpreted at runtime. Func<foo, bool> is an imperative function that gets compiled and executed as a part of your program. Which means that it can only operate on .NET types, which means you need actual data structures in memory (or IEnumerables emitting them). So going from Expression to Func (or IQueryable to IEnumerable) means that your expression tree gets interpreted and executed and anything chained after that will be ran in your program. beuges posted:Just so you know, there are .AsQueryable<T> and .AsEnumerable<T> methods that are available from entity framework that will transform from one to the other. Converting from IEnumerable to IQueryable just means that your expression tree will get interpreted by the CLR and invoke methods as if your IQueryable was an enumerable. It won't tack your Linq on to the upstream expression tree.
|
# ¿ Jul 26, 2019 22:15 |
|
Communicating over a network, communicating with a database using an agreed-upon protocol, deserializing data retrieved from a database, and serializing data that you want a database to write are all solved problems. Managing a database schema, managing data object lifecycles during application execution, scoping transactions, writing queries, and migrating data are problems that have solutions. These things are subtly different. Micro-ORMs like Dapper only solve the former while traditional, thicker ORMs like EF claim to also be able to solve the latter. Often they're able to, until they can't. Complexity is inevitable if your application is going to do anything useful, and at some point you're going to have to make a change to your software that reveals someone made a bad assumption somewhere. That's how you get into poo poo like this: a hot gujju bhabhi posted:These days I'm working on a large repository of .NET Framework horseshit and I'm having some trouble with Entity Framework because the people who originally built this out clearly didn't know how to use it. I have a Windows service, with various unnecessary layers of complexity behind it, and something in there is causing the service to "randomly" crash. The people that wrote that could just suck, or maybe they did need to add complexity because the business requirements demanded it but EF didn't leave them any room to manage that complexity in a more sane manner. EssOEss posted:Well, it depends on the usage but I can certainly agree that horrible experiences with EF are possible. The main issues with EF (Core) that I have encountered are: a hot gujju bhabhi posted:Exactly, it's just about knowing what you're doing and designing your code appropriately. Lazy loading should never be a problem because you should really be projecting your queries to domain models at the outset. If you're gonna do an update, use a dto to represent the change, fetch the object and update and save it in the same method as you said. If EF brings all these footguns if it's used beyond performing basic queries or simple data writes, why not just write the SQL directly? I agree that manually mapping data between something like ADO.NET and POCOs is a huge pain, but Dapper solves that problem and seems like a better fit than what you're using EF for. ThePeavstenator fucked around with this message at 22:47 on Jan 25, 2020 |
# ¿ Jan 25, 2020 22:45 |
|
Boz0r posted:We use early bound entities for developing plugins for Dynamics 365. We upgraded our csproj files to the new 2017 format, and we've just discovered a the early bound types have stopped working. Usually, we have to add the following line to an AssemblyInfo.cs: If by "2017 format" you mean SDK-style csproj (what .NET Standard 2.0+ and .NET Core projects use), you can add assembly info stuff to the csproj file. Example: https://stackoverflow.com/a/44502158
|
# ¿ Aug 5, 2020 16:57 |
|
DO: Not build microservices. Instead build monoliths with independent, configurable, well-tested components that are injected as services. Your app will scale and be perfectly performant as a monolith and will have a simple development process, simple CI/CD pipeline, and simple architecture. Let's say you somehow get enough users to where the IComponentThatDoesShit service starts to become the majority of the load on your monolith, and it's affecting overall performance including the performance of other services. Or an alternative situation might be your app is performing fine but you're somehow making enough money to grow a dev team that's getting too large to work on a single monolith, and the IComponentThatDoesShit service is the most complex service in your system. In situations like these, you take the IComponentThatDoesShit implementation, make it into it's own webservice, and then take the existing implementation of IComponentThatDoesShit that has all the business logic and replace it with an implementation that makes HTTP calls to the new webservice. Keep repeating as needed. DON'T: Build monoliths and not follow IoC practices. Starting with a greenfield monolith and understanding that at some point some services will need to be broken into separate microservices is the way to go, but this becomes a huge PITA when there's no dependency mapping and all your services have a hellish web of dependencies where you can't break off a module without affecting anything else. e: Basically don't think about writing microservices, think about writing code in modules and being in a tree-like dependency structure. You make choices that certain chunks of the tree should be running in a separate service for either ease of development or performance reasons. These chunks are microservices. Unless you are psychic, you will not know which chunks need to be running in separate services until an obvious need arises, so don't break anything up until you actually need to. Pre-maturely creating separate services is how you get into resume jerk-off land where everything gets put in a queue and for some reason there's still a single "database access" microservice that can't be broken up because everything is coupled to it. ThePeavstenator fucked around with this message at 23:53 on Jan 22, 2021 |
# ¿ Jan 22, 2021 23:04 |
|
EssOEss posted:This code is fine and an exception being thrown does hit the catch. You must be doing something different in your real code than in your pasted example. Post a full sample project that demonstrates the issue you are facing. I just want to clarify something for people who might be new to async/await and not fully understand what "do other stuff at the same time" means. Take this example: C# code:
C# code:
Let's say that these can't be run in parallel, Thing 1 has to be called, and then Thing 2 can only be called after Thing 1 completes. More often than not I find all my async/await code looks pretty much the same as if it were sync, which is where I think a lot of people who are new to async/await get tripped up since they don't really see the point of using it. The difference between the Sync and Async examples is that in the DoAsync code, .NET can do other stuff with that thread, even if you don't write any parallel code yourself. Let's say this is some method used by a ASP.NET webservice. With async/await, in the 5 and 10 seconds it takes for Thing 1 and Thing 2 to run, the calling thread can execute other work rather than sit there and wait for the operation to finish. That single operation still takes 15 total seconds, but the thread isn't sitting there waiting and being blocked. In the DoSync example, the operation also takes 15 seconds, but 1 request calling the DoSync method also eats up the thread for 15 seconds. In the DoAsync example, 1 request will eat up the thread for as long as it takes to invoke the task and register the callback (which is basically just a few sync method calls and some object allocations), but in the 5 and 10 seconds of waiting, other work can be done by the thread (such as servicing multiple requests). Your code all still looks sync, but the .NET runtime can more efficiently assign work to threads that are just sitting there waiting for long-running calls to finish when they're awaited. This is why using async/await for long-running calls in the UI thread is desirable. If you await an HTTP request call in the UI thread, the UI thread isn't locked up waiting for the long-running HTTP request operation to complete. The UI thread can do things like update the view and respond to user input instead of being eaten up by the long-running HTTP call while it waits to finish. I think this is part of what confuses a lot of people about async/await. It's not a parallelization syntax, it's a continuation syntax. Your series of awaited calls still take the same total amount of time and execute in sequence, but they don't make the actual thread that they're executing on sit and wait for them to finish.
|
# ¿ Jan 22, 2021 23:50 |
|
I use these for mapping POCOs Alternatively these are also good (especially .NET 5 with init-only properties) For real though, auto-mapping libraries give you 5 minutes of convenience and a lifetime of pain. They're great when they work with 0 additional code because all of your objects have identical fields, but you're presumably using different object types and mapping between them to decouple data at different layers. That implies that there's a good chance that the shape of the data at those different layers can diverge. Once that happens you now have to write mapping code, except the compiler isn't able to do as much work to help you anymore because now that's all being done at runtime via reflection. It's not a huge deal to write and maintain these: C# code:
And with only a single object mapping method, you can still map collections via Linq: C# code:
Also re: performance - constructors and object initializers are pretty dang fast compared to reflection! ThePeavstenator fucked around with this message at 02:52 on Feb 1, 2021 |
# ¿ Feb 1, 2021 02:50 |
|
Custom exception types can be good in situations where you can identify what’s wrong and want to be specific, but can’t or shouldn’t handle that situation in the layer of code you’re on. For example, some method call reads Foo data from a DB and then does some processing on it and then returns the result. Foo data has FieldA and FieldB, and only A or B should have a value, not both. If you do a check in the method to make sure FieldA and FieldB aren’t both set before processing each piece of Foo data, you can define a more specific custom exception to throw in cases where FieldA and FieldB are both set. Then when your custom MutuallyExclusiveFooFieldException or whatever you call it shows up in logs it’s easy to diagnose the issue and also correlate/quantify how often that happens. This also has the benefit of upstream callers that might know how to resolve that specific issue being able to catch that specific exception. This is kind of a subjective design decision though and there are other valid ways to get easy to debug telemetry and conditional error handling.
|
# ¿ Mar 9, 2021 06:27 |
|
epswing posted:I've got an EF/SQL/LINQ question. Say I've got a table with Id (int not null sequence) and Message (string) columns. I want to produce the last 5 distinct messages in reverse order (most recent first). IEnumerable/yield just means that evaluation/enumeration will be done lazily, but the IEnumerable data source is almost certainly from an in-memory collection in this case (if it was still being done on the DB it would still be an IQueryable). Ask yourself this - can you write a raw query to accomplish what you want solely on the DB? If the answer is no, then there’s nothing EF will be able to do to make that happen either.
|
# ¿ Jun 21, 2021 17:09 |
|
mistermojo posted:yeah groupby should be what you want IEnumerable and IQueryable are different things with different behaviors even though it looks like you’re just writing the same Linq syntax. This is one of the reasons I hate EF. Linq is very powerful but also has some footguns that devs run into when they don’t understand the difference between when a Linq query is describing functions performed on a sequence (IEnumerable) and when a Linq query is actually building an expression tree (IQueryable) that can be evaluated and executed on a sequence or any arbitrary data source that has a way to translate the expression tree into instructions it understands. EF just papers over this and says “Look at all the poo poo Linq can do! No need to worry about all that complicated poo poo like knowing what your databases are actually capable of or how you should structure your data for your chosen DB(s). Oop your app is eating up all your memory and/or CPU and/or what look like simple queries are taking way longer than expected to evaluate? You should have read the docs and known how all this poo poo works under the hood before deploying it!” The paradox of EF is that it demands you understand the various intricacies of Linq and how the data providers work internally in order to avoid firing one of the many footguns it hands to you, but once you understand what EF is doing for you and how it works internally, your best choice is usually “don’t use EF and write the queries/HTTP calls/etc myself”. ThePeavstenator fucked around with this message at 21:12 on Jun 21, 2021 |
# ¿ Jun 21, 2021 20:38 |
|
Polio Vax Scene posted:There's a developer on our team that continues to use .NET Framework for all their work. I think they're intimidated by .NET Core or something. Any good resources you recommend that can be used to convince them to swap? It’s been very clear for years now that .NET Core is where all the development effort is going - https://devblogs.microsoft.com/dotnet/net-core-is-the-future-of-net/ .NET Core was also rebranded to just .NET to further drive that point home - https://devblogs.microsoft.com/dotnet/introducing-net-5/
|
# ¿ Dec 20, 2021 17:57 |
|
I've had the most success in keeping code reasonably performant and readable with the advice of "use the currently recommended standard library API first". Everyone has their own definition of "easy" and "simple" (and often that definition is "stuff I already know") but it's hard to argue with the 1st party .NET docs saying "use async/await, not .Wait() or .Result" or "use DateTimeOffset instead of DateTime". In the case of string concatenation, I think you can make the case that all of these are fine if you follow "use the currently recommended standard library API first": C# code:
C# code:
ThePeavstenator fucked around with this message at 04:06 on Mar 3, 2022 |
# ¿ Mar 3, 2022 04:02 |
|
epswing posted:Question for you warriors that have migrated projects from .NET 4.8 to .NET 6. That's weird. the TFM "net6.0" basically means "any platform that can run .NET 6 can take a dependency on this", where "net6.0-windows" means ".NET 6.0 minimum, with Windows-specific APIs" - https://docs.microsoft.com/en-us/dotnet/standard/frameworks#net-5-os-specific-tfms What happens if you just use "net6.0" instead of "net6.0-windows"?
|
# ¿ Jul 2, 2022 03:29 |
|
Are you invoking MSBuild in your ADO pipeline or are you using dotnet build? NuGet/MSBuild are integrated in dotnet, so you shouldn't need to deal with NuGet versions like that as a separate tool.
|
# ¿ Jul 2, 2022 04:04 |
|
This is 100% an XY problem. Setting the entire UI thread sounds like a bad plan - what happens if you set the UI thread to have a culture for "zh-CN" when the currency in question is the Yuan, and then the entire UI ends up translated into Chinese on a UK/US user's computer without Chinese language support installed? This is a pretty non-negotiable software design pattern IMO - Money really needs to be represented as a (Currency, Amount) tuple and the issues you're running into (someone in Great Britain needs to be shown US dollar amounts in the UI) illustrate why, here's a NuGet package if you want a pre-baked implementation of a Money data structure - https://www.nuget.org/packages/nmoneys If you're not going to update your legacy application to follow this pattern you can always set the UI thread to a custom culture where everything is the same as the user's default UI culture, but you set the currency symbol yourself, but that's not foolproof either - different cultures have different ways of expressing things like negative currency amounts, and the second this is no longer true: epswing posted:The software doesn't do multi-currency ...you'll be forced to make the conversion and wish you had done it in the first place. e: You don't necessarily have to use that NuGet package to be clear. If you know what the currency is in the UI (as in, the legacy code already has some way of identifying the currency that just isn't used when converting to a string), you can implement a GetCurrencyCulture() method that accepts the currency and then returns the appropriate .NET culture for the currency, and then you can provide that culture as a parameter in your string.Format call - https://learn.microsoft.com/en-us/d...(system-string) ThePeavstenator fucked around with this message at 02:28 on Feb 26, 2024 |
# ¿ Feb 26, 2024 01:59 |
|
|
# ¿ May 17, 2024 17:22 |
|
Thinking "oh I'll just use a decimal and make it work, making a Money type seems like gold plating" will lead you to the same land of pain as using the standard DateTime type and adding TimeSpan values to it because a library like Noda time for calendar/time arithmetic seems too complex for a "simple" use case.
|
# ¿ Feb 26, 2024 02:07 |