|
If it helps you can create Exception classes really easy in Visual Studio by just typing "exception" and hitting tab twice. But that's just automating the boilerplate, not really eliminating it. I'll usually just throw an ApplicationException until I have a need to do catch filtering on that specific failure.
|
# ? Mar 8, 2021 17:56 |
|
|
# ? Jun 8, 2024 04:45 |
|
Can anyone recommend a vendor for generating PDFs? Nothing terribly fancy, just need to be able to take a byte array and treat it as a PDF, locate input fields on it and stamp data into them, flatten it for rendering a new PDF as a byte array with the data filled in. We had been using iTextSharp but are now having licensing problems with it, and a replacement we've been working with appears to have unsolvable memory leak issues that become a problem at a high concurrent load.
|
# ? Mar 8, 2021 20:21 |
|
Hammerite posted:This post is apropos of nothing, I'm just getting some thoughts out of my head and onto the forum. If you're up for explaining it in a little more detail, I think this might be useful to me, but I haven't got my head wrapped around it well enough to be sure. In poking at the problem described in my last post (thanks to Rocko Bonaparte for the feedback, while I'm thinking about it!), I ran into related issues (I think) involving how inheritance and reflection interact. Specifically, I was disappointed to learn that if you're calling an inherited method from a subclass, if you're using the default implementation, then reflection on that method will return the type where it's defined, not where it's being called. I'm just about positive that making Subclass.MethodDefinedInBaseClassThatReturnsSubclassReflectionInfo() work will not be worth the added complexity, but the whole project is mostly educational anyway, so I'm still interested in what's down that rabbit hole.
|
# ? Mar 9, 2021 00:22 |
|
I feel like declaring your own exception types should not be something you need to do on a frequent basis.
|
# ? Mar 9, 2021 04:52 |
|
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 |
|
brap posted:I feel like declaring your own exception types should not be something you need to do on a frequent basis. I'm not sure if this is good/bad practice, but I tend to only declare my own exception types when I have a try/catch with which to use them (which is infrequent). Otherwise what's the point? Sounds like a lot of boilerplate, as mentioned, what are the advantages of throwing custom exception types (especially if you're not using them in a catch block)? Edit: ^^^gotcha, sure, I suppose there is a logging benefit. I've found the call stack and the exception message is usually enough to tell the story, though. epswing fucked around with this message at 06:35 on Mar 9, 2021 |
# ? Mar 9, 2021 06:29 |
|
Improved pattern matching makes generic exceptions easier to work with.
|
# ? Mar 9, 2021 10:13 |
|
In this specific case for my application, there are three assemblies running - 2 APIs (one for identity, one for the "store") and the web application. So even when I throw an exception in one of the APIs or in one of the class libraries supporting the APIs, I still need a way to communicate that error information back to the web application. Simply throwing an exception won't do it. That's why I'm handling it in the manner that I am, with the Either class. I throw exceptions all the time in library code, or in monolithic applications like desktop. ArgumentNullException, ArgumentOutOfRangeException, InvalidOperationException, whatever is appropriate. I also do occasionally throw custom exceptions when I need to communicate more than just an error message.
|
# ? Mar 9, 2021 16:29 |
|
LongSack posted:In this specific case for my application, there are three assemblies running - 2 APIs (one for identity, one for the "store") and the web application. So even when I throw an exception in one of the APIs or in one of the class libraries supporting the APIs, I still need a way to communicate that error information back to the web application. Simply throwing an exception won't do it. That's why I'm handling it in the manner that I am, with the Either class. APIs should indicate success or failure by using standard HTTP status codes. Specific exception details are an implementation detail that consumers shouldn't need to know about. Think of it like this: Web: API, do this thing. API: Sorry, I can't. You probably don't need to know the specifics. Web: Okay. I will let the person using me know that something went wrong. Or I'll retry if it's a transient problem. All of these application pieces should be instrumented and sending telemetry data somewhere. I like Azure App Insights/Log Analytics, but I'm an Azure shill so New Yorp New Yorp fucked around with this message at 16:47 on Mar 9, 2021 |
# ? Mar 9, 2021 16:41 |
|
Funking Giblet posted:Improved pattern matching makes generic exceptions easier to work with. The language designers had to add this because everybody involved is garbage at exceptions and exception hierarchies. It's literally 90 seconds to add a new exception type yet somehow that's too much work. Throwing 'new Exception ($"Unable to load {id} from database")' is apparently way better than "new MissingDataException(id)" for reasons I'll never understand. Bonus if you catch the actual exception and throw your own Exception (not even any subtype!) without including any of the original context. Or double bonus if you catch(Exception e) { throw e; } and blow away my stack trace when I'm trying to debug logs from prod. Or super gently caress you if you catch(Exception up) { throw up; /* he he he */ } like the actual code I found, complete with "he he he" in a comment.
|
# ? Mar 9, 2021 17:02 |
|
Toast Museum posted:If you're up for explaining it in a little more detail, I think this might be useful to me, but I haven't got my head wrapped around it well enough to be sure. In poking at the problem described in my last post (thanks to Rocko Bonaparte for the feedback, while I'm thinking about it!), I ran into related issues (I think) involving how inheritance and reflection interact. Specifically, I was disappointed to learn that if you're calling an inherited method from a subclass, if you're using the default implementation, then reflection on that method will return the type where it's defined, not where it's being called. I'm just about positive that making Subclass.MethodDefinedInBaseClassThatReturnsSubclassReflectionInfo() work will not be worth the added complexity, but the whole project is mostly educational anyway, so I'm still interested in what's down that rabbit hole. I don't know. Maybe? I'm not sure how this interacts with reflection. I'm not doing any reflection in the implementation of this I have. Or are you saying that this might be how you would avoid reflection? If you give more details of what your subclasses represent and what varies in each one I might have more idea. I would post the code that I was actually working on when I had this idea, but I haven't gone to the trouble of adding a licence yet. (It is a personal project and I already know I am going to GPL it but I haven't done the mechanical work of adding the licence boilerplate yet. I am lazy)
|
# ? Mar 9, 2021 20:05 |
|
New Yorp New Yorp posted:APIs should indicate success or failure by using standard HTTP status codes. They do. They return 200, 201 and 400 (and 500 if I mess something up in development, like forgetting to set the BasePath in my UriHelper class). And I can’t just say “something went wrong”, I need to tell the end user what went wrong. For example, when creating a new Category, the CategoryService in the portal will check for duplicate names. The API will also check (never trust data from the user). The Data Access Layer service will also check. If I didn’t do those checks, EF would throw a badly-worded exception. That message, I agree, the user should never see, which is why each of the above checks returns a message that says “Duplicate Category Name” which ends up in the ModelState.
|
# ? Mar 10, 2021 01:40 |
|
LongSack posted:They do. They return 200, 201 and 400 (and 500 if I mess something up in development, like forgetting to set the BasePath in my UriHelper class). You can return a http 400 with the body “Duplicate Category Name”. You can write a middleware in your api to catch an custom created ApiException which has a status code and message, and return the appropriate response. You can then wrap calls to your api to check the status code and display the error appropriately, or bubble it back if you’re not yet at the customer browser level.
|
# ? Mar 10, 2021 05:34 |
|
beuges posted:You can return a http 400 with the body “Duplicate Category Name”. You can write a middleware in your api to catch an custom created ApiException which has a status code and message, and return the appropriate response. You can then wrap calls to your api to check the status code and display the error appropriately, or bubble it back if you’re not yet at the customer browser level. That's exactly what I'm doing. The store APIs return 200/201 on success, and 400 on failure. The success payload varies based on the request, but the 400 payload is always an instance of the ApiException class. The portal services which call the APIs are using a generic "Either" class to retrieve the results based on RichardA's response further up in this thread.
|
# ? Mar 10, 2021 15:49 |
|
Funking Giblet posted:Improved pattern matching makes generic exceptions easier to work with. Yes, 1000%. For inter-project exceptions they more or less entirely eliminate the need for custom exception types. But if you're designing a reusable library, I'd still recommend creating and throwing your own exception types rather than saddling the library's consumers with 1) needing to know what pattern they should look for to catch the specific failure they care about catching; and 2) accidentally permanently tying yourself to having to maintain that your exception continues to match that arbitrary ad hoc pattern in future releases of your library. A (lowercase t) type is a type, regardless of whether it's a (uppercase T) Type or not; and if you make it a Type your life will be easier in the long run at the minor expense of 30 seconds of work. It's always better to be as explicit as possible. edit: and I also agree that there's a special place in hell for anyone who's ever written throw e; to rethrow a caught exception. I can't believe the compiler doesn't even at least flag it as a warning, because if you ask me, it should be no less than a compile error. biznatchio fucked around with this message at 16:53 on Mar 10, 2021 |
# ? Mar 10, 2021 16:49 |
|
Hammerite posted:I don't know. Maybe? It's been a week or so since I last took a crack at it, so I'm fuzzy on how the reflection-related issues and static-related issues overlapped. The situation I've run into is pretty much entirely because I don't want to do an easy-but-clunky thing. Mostly as a way to learn C#, I'm working on a project that interacts with an XML-RPC API. This API has some qualities that make it a little frustrating to deal with, including:
Since these we're talking about a couple dozen properties on some of these objects, I really don't like the idea of doing something like code:
code:
code:
Edit: fixed an error in the sample code Toast Museum fucked around with this message at 01:40 on Mar 11, 2021 |
# ? Mar 10, 2021 21:06 |
|
Toast Museum posted:It's been a week or so since I last took a crack at it, so I'm fuzzy on how the reflection-related issues and static-related issues overlapped. The situation I've run into is pretty much entirely because I don't want to do an easy-but-clunky thing. Mostly as a way to learn C#, I'm working on a project that interacts with an XML-RPC API. This API has some qualities that make it a little frustrating to deal with, including: Why not build a component that handles doing that field conversion for you, rather than making it a responsibility of the objects themselves. Then you can cache the result of the reflection per type inside that component if you want to. Also, is the transformation from the rpc spec to C# class rote or does it require tender loving care from you? Cause if it's pretty mechanical, you could look at Roslyn source generators to do it for you directly from whatever schema you're using.
|
# ? Mar 10, 2021 21:27 |
|
beuges posted:You can return a http 400 with the body “Duplicate Category Name”. Bikeshed alert: I like to use the 409 Conflict for duplicate requests. It's good not to dump it into the generic 400 error code because there was nothing wrong with the request itself, it just didn't mesh with the state of the data store at the time. It also works well with idempotency (which I try hard to bake into all my APIs), because then the client can just retry the requests and accept a 409 as valid ( = an earlier request went through, the client just didn't get the answer). There's a few other codes that might be suitable for this, but whatever you choose, the important thing IMO is to use 400 and 500 as sparingly as possible, since they're the generic 'wtf come get a human to read the message' codes.
|
# ? Mar 10, 2021 21:46 |
|
If I'm a Linux user who will never use the .NET platform on Windows, how painful is it to use F# for application, system or web development?
|
# ? Mar 11, 2021 01:33 |
|
salisbury shake posted:If I'm a Linux user who will never use the .NET platform on Windows, how painful is it to use F# for application, system or web development? except when the vscode plugin decides to randomly break lol
|
# ? Mar 11, 2021 01:39 |
|
Does anyone else ever look at this thread's title and ask why the method isn't named "GetGoodPostsAsync()"?
|
# ? Mar 11, 2021 03:02 |
|
salisbury shake posted:If I'm a Linux user who will never use the .NET platform on Windows, how painful is it to use F# for application, system or web development? VSCode and Omnisharp is fine. Rider is also pretty good for F#.
|
# ? Mar 11, 2021 03:35 |
|
GI_Clutch posted:Does anyone else ever look at this thread's title and ask why the method isn't named "GetGoodPostsAsync()"? I considered it. It's probably time for a new thread anyway. I'm not making it though.
|
# ? Mar 11, 2021 03:37 |
|
salisbury shake posted:If I'm a Linux user who will never use the .NET platform on Windows, how painful is it to use F# for application, system or web development? F# is as platform-agnostic as C# is. The underlying library also got very cross-platform in Core, and continues to do so. You as the developer will be the weak link, doing things like concatenating paths together instead of using Path.Combine. VSCode and 'dotnet' will do a lot more than you'd think they will!
|
# ? Mar 11, 2021 06:17 |
|
the real tricky cross-platform bits are around locales and time zones and the like imo
|
# ? Mar 11, 2021 07:02 |
|
And any stuff that needs to interface with Windows stuff like NTLM. Otherwise it is actually pretty good.
|
# ? Mar 11, 2021 08:48 |
|
GI_Clutch posted:Does anyone else ever look at this thread's title and ask why the method isn't named "GetGoodPostsAsync()"? .NET Megathread 5.0: GetGoodPostsAsync().ConfigureAwait(false);
|
# ? Mar 11, 2021 12:08 |
|
insta posted:You as the developer will be the weak link, doing things like concatenating paths together instead of using Path.Combine. <bell curve meme> low tail: concatenate paths with "\" middle of the bell : concatenate paths by using Path.Combine high tail: concatenate paths with "/", because it works on both Windows and Linux, multiple consecutive slashes have no effect, and it doesn't do that super annoying thing Path.Combine does where if a segment starts with "/" it reads it as an absolute path and it deletes every segment before it
|
# ? Mar 11, 2021 12:17 |
|
Hammerite posted:.NET Megathread 5.0: GetGoodPostsAsync().ConfigureAwait(false); .NET Megathread 5.0: _goodPostsRepository.GetGoodPostsAsync().ConfigureAwait(false);
|
# ? Mar 11, 2021 12:20 |
|
Ola posted:.NET Megathread 5.0: _goodPostsRepository.GetGoodPostsAsync().ConfigureAwait(false); .NET Megathread 5.0: return! goodPostsRepository |> GoodPosts.getAsync
|
# ? Mar 11, 2021 15:00 |
|
NihilCredo posted:.NET Megathread 5.0: return! goodPostsRepository |> GoodPosts.getAsync
|
# ? Mar 11, 2021 15:06 |
|
WorkerThread posted:Why not build a component that handles doing that field conversion for you, rather than making it a responsibility of the objects themselves. Then you can cache the result of the reflection per type inside that component if you want to. No real reason, I guess. Keeping information about each class within that class just felt like the tidiest option. Happily, I think I've figured it out. I was able to achieve the effect I was going for by making the base class generic: code:
WorkerThread posted:Also, is the transformation from the rpc spec to C# class rote or does it require tender loving care from you? Cause if it's pretty mechanical, you could look at Roslyn source generators to do it for you directly from whatever schema you're using. I've been focusing on one of the business object classes while I sort out my approach, but the logic for the C# class members is mostly pretty straightforward. The API always handles objects' properties as strings, so for the C# classes, I stick those strings in backing fields, with getters parsing the strings into more useful types (usually bool? or double?, with a DateTime or two for flavor), and setters converting back to string. In a couple of cases, the value of a bool has to be flipped to account for the C# class using affirmative member names where the API uses negative names. My familiarity with Roslyn is basically "I've heard that name," but I'm up for checking it out. Where's a good place to start?
|
# ? Mar 11, 2021 15:14 |
|
NihilCredo posted:high tail: concatenate paths with "/", because it works on both Windows and Linux, multiple consecutive slashes have no effect, and it doesn't do that super annoying thing Path.Combine does where if a segment starts with "/" it reads it as an absolute path and it deletes every segment before it
|
# ? Mar 11, 2021 15:18 |
|
mystes posted:Huh, no poo poo. Yep. It really sucks.
|
# ? Mar 11, 2021 16:18 |
|
NihilCredo posted:that super annoying thing Path.Combine does where if a segment starts with "/" it reads it as an absolute path and it deletes every segment before it Whaaat? I had to try it to believe it but... drat.
|
# ? Mar 11, 2021 18:20 |
|
Mr Shiny Pants posted:Yep. It really sucks.
|
# ? Mar 11, 2021 21:19 |
|
Toast Museum posted:No real reason, I guess. Keeping information about each class within that class just felt like the tidiest option. Happily, I think I've figured it out. I was able to achieve the effect I was going for by making the base class generic: Yeah, that seems like a decent way to handle it. It's not quite the same thing as what I was talking about in my post but it's not a million miles away. Glad you managed to something you are happy with. (I have heard of Roslyn but I don't know anything about it)
|
# ? Mar 11, 2021 23:19 |
|
Path.Combine is a real easy way to introduce a huge security issue to your web app when you directly feed it user input, thinking you're safe because you don't realize how it actually behaves (and your app isn't installed in a tightly access-controlled manner). Oh yeah look I'm dynamically serving you files from a per-user sub-directory of some mapped network drive base path. Since I'm always starting with the base path I'm fine right? Strange, why is this user requesting "C:\inetpub\wwwroot\derp-app\web.config" and why the hell is it working?? It's not just that relative paths are resolved, e.g. "X:\base\path" + "..\..\rootfile.txt" => "X:\rootfile.txt", but also if any of the Path.Combine parameters is rooted, all stuff that came before it is ignored outright, like "X:\sandbox" + "user" + "upload" + "C:\secret.txt" => "C:\secret.txt". Sure it's not difficult to safeguard against this (check if the resolved combined path still StartsWith() your safe root path afterwards), but I bet there's tons of exploits out there just because it's really not obvious it would behave that way.
|
# ? Mar 11, 2021 23:33 |
|
Toast Museum posted:I've been focusing on one of the business object classes while I sort out my approach, but the logic for the C# class members is mostly pretty straightforward. The API always handles objects' properties as strings, so for the C# classes, I stick those strings in backing fields, with getters parsing the strings into more useful types (usually bool? or double?, with a DateTime or two for flavor), and setters converting back to string. In a couple of cases, the value of a bool has to be flipped to account for the C# class using affirmative member names where the API uses negative names. Sorry, on the road and phone posting this afternoon; https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/ is where I started. It's probably still a bit too rough around the edges for production, but something I'm playing around with is similar to what you're describing-- writing a generator to automatically create C# clients for swagger files included in the solution/compilation.
|
# ? Mar 12, 2021 00:13 |
|
|
# ? Jun 8, 2024 04:45 |
Why is my list not sorted... I must be missing something obvious here. WPF on Framework 4.6.1 C# code:
The actual result is that I get several individually sorted sequences of items in the list. I'd consider putting a SortDescription on the ListBox.Items, but can't figure out from the docs how to handle the (sim) item, which needs to be last. Edit: Never mind, I figured out what I'm doing wrong. It's the if (!inserted) at the end, that should be appending the item rather than prepending it. nielsm fucked around with this message at 10:22 on Mar 16, 2021 |
|
# ? Mar 16, 2021 09:55 |