|
Thanks for the feedback so far.Mr Shiny Pants posted:What a user does should not cause an exception on your server and the right handling should be in place. Let's say it's not an input validation problem. The user tries to execute a command that, it turns out, shouldn't be executed because of some business logic reason. My controllers are generally thin and just call some service method. Somewhere in the service, an exception is thrown (e.g. "You can't delete X because of Y"), and eventually the user sees the message of that exception. Where else would be the right handling for this scenario? ThePeavstenator posted: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. I'll check this out, thanks. ThePeavstenator posted: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. Sorry, I should have included more context. I'm using WebAPI basically for RPC. (Years ago this was all WCF.) The client is an internal WPF app. I never even deal with json, as ApiController and HttpClient take care of all the serializing/deserializing. So, while I agree with you that in general I shouldn't be exposing certain data, and shouldn't be coupling my API to C# responses, in my case I think it's acceptable because I control both the server and the clients. ThePeavstenator posted: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. ThePeavstenator posted: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. The client POST might fail for several reasons, and should react differently based on which reason was given. I don't particularly want to check the verbose message I show the user (if (responseMessage == "Error: Unable to compute because X") { ... }). I could include an explicit internal error code in the response, and the client would then check if (responseCode == ErrorCodes.FAIL_X) { ... }. I was thinking somewhere between those two might be to throw an exception, and use the exception type, leading the client to check if (responseExceptionType == typeof(MyXException).ToString()) { ... }. If using the latter method, my service could e.g. throw new MyXException() or MyYException() and the client would get a 400, an exception message to show the user, and an exception type to act upon. The bottom line is the consumer needs to act differently based on why their request failed. Is throwing an exception in a service, letting a controller package that up for the client, and having the client decide what to do based on the type of exception thrown a major no-no (given that I control the server and clients)? epswing fucked around with this message at 07:46 on Jan 6, 2019 |
# ? Jan 6, 2019 07:39 |
|
|
# ? Jun 8, 2024 08:58 |
|
ThePeavstenator posted:You shouldn't be using exceptions for controlling execution flow in general. C# code:
|
# ? Jan 6, 2019 07:47 |
|
The advice you are getting is for how to design a REST API, because that is what people most often do with Web API. From your mention of RPC however, I see that you actually have nothing like a REST API here. Thus what you effectively have is a custom protocol that just happens to be based on HTTP on some layer. Do not expect any standard web API design guidelines to apply to your situation - this is not how people generally create web APIs at all. That being said, we can take a comparison with gRPC, Google's state of the art RPC API. It does not expose any information beyond its equivalent of "500 Internal Server Error" when an exception occurs. They probably know what they are doing, so follow suite. What I do in my gRPC APIs when I want the client to differentiate error types is that I include an ErrorCode in my response. My response types look like: code:
|
# ? Jan 6, 2019 08:03 |
|
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 |
|
downout posted:Anyone have some good recommended reading regarding DI? I've used it in various settings, but it was always more from a format of "this is how we do it, what we use, just keep doing it that way". It was never covered in my formal education (and mostly abstracted away by libraries in my post-education experience), so I think it might be really helpful to see a more formal usage/construction in real world scenarios. Dependency injection demystified. Read that first and maybe if you're feeling adventurous, the stuff he links to at the end of the post. For an example of how to set it up in a project (this uses simple injector, there other other DI frameworks like autofac, and asp .NET core has a DI framework build in) Simple injector quickstart The two links give like 95% of what you need to know to understand DI and DI Containers. Bruegels Fuckbooks fucked around with this message at 08:57 on Jan 6, 2019 |
# ? Jan 6, 2019 08:54 |
|
epalm posted:Thanks for the feedback so far. Well if you control both the server and the client, it is not exactly user facing, the only consumer is a WPF application and it won't become an API endpoint in the future for other applications: it depends. Going from the above explanation: If an exception occurs in the service layer you probably know why it happened, why not handle it in your controllers?
|
# ? Jan 6, 2019 09:03 |
|
Bruegels Fuckbooks posted:For an example of how to set it up in a project (this uses simple injector, there other other DI frameworks like autofac, and asp .NET core has a DI framework build in) Exactly what I was going to post. The entire Simple Injector docs site is easily one of the best software doc/wiki resources I've ever seen. Even if you don't care about DI, read this guide to learn how technical documentation should be written. Another example would be the Postgres docs. Again, even if you don't use Postgres, it's like a full RDBMS/SQL training course. I actually use StructureMap for my container, partially due to inertia and partially due to its convention-based auto-registration, but SimpleInjector would be my choice if I was starting fresh.
|
# ? Jan 6, 2019 15:52 |
|
B-Nasty posted:Ugh. So what do you do when, as is typical in the real world, Foo has 5 dependencies all of which have multiple dependencies themselves, ad infinitum? I prefer not to manage my dependency tree myself - we have containers that do that for us. I'd much rather change RealBar to BetaRealBar in one spot than have to dig all around the codebase to find where I new'd up a bunch of hard-coded dependencies. Foo’s default constructor will provide the “prod” dependencies (repeat transitively) and the mock IBar used in testing just returns hard coded results so it doesn’t need the RealBar dependencies specified. Am I missing something?
|
# ? Jan 6, 2019 18:43 |
|
brap posted:Foo’s default constructor will provide the “prod” dependencies (repeat transitively) and the mock IBar used in testing just returns hard coded results so it doesn’t need the RealBar dependencies specified. Am I missing something? I didn't communicate it well, but I was referring more to common (repeated) dependencies. If you had many classes that took a dependency on, say, ILogger and they all were responsible for constructing FooLogger, changing that everywhere you manually wired up the instance would be a pain. Not to mention that containers (subject to how they are configured) won't construct a zillion instances of FooLogger for every ILogger dependency in a given 'request'; they'll create one and share it. See StructureMap's 'Transient' lifecycle: http://structuremap.github.io/object-lifecycle/supported-lifecycles/
|
# ? Jan 6, 2019 18:58 |
|
Well this is going to be a rather flip-flop post on DI: On one hand, I wanted to note that while I can see the benefit of offering a default constructor with the production implementation included, my experience with it has been that in larger projects it can create a tricky situation where you end up needing to constantly be on-guard for misuse. And by that I mean: code:
But on the other hand, I guess I'm curious about how best to handle DI at a scalable sense. Using IOC containers as service locators has (mostly) felt a bit ugly to me. But at the same point, having to pass around dependencies manually especially when dealing with deeper object graphs, seems to get kind of hairy as well. The examples and quickstarts are always too simple to see the picture at scale. Consider the SimpleInjector quickstart: Ok, an CancelOrderHandler. But that's captured in Main() - and it doesn't necessarily make sense to me to also have an VerifyOrderHandler, ConfirmOrderHandler, OrderPaymentHandler, RefundOrderHandler, CreateOrderHandler, and all the other various domain objects in a quick 'ok just grab it off a global container' sense, especially in Main. So what, then?
|
# ? Jan 6, 2019 21:09 |
|
Cuntpunch posted:But on the other hand, I guess I'm curious about how best to handle DI at a scalable sense. Using IOC containers as service locators has (mostly) felt a bit ugly to me. But at the same point, having to pass around dependencies manually especially when dealing with deeper object graphs, seems to get kind of hairy as well. The examples and quickstarts are always too simple to see the picture at scale. Consider the SimpleInjector quickstart: Ok, an CancelOrderHandler. But that's captured in Main() - and it doesn't necessarily make sense to me to also have an VerifyOrderHandler, ConfirmOrderHandler, OrderPaymentHandler, RefundOrderHandler, CreateOrderHandler, and all the other various domain objects in a quick 'ok just grab it off a global container' sense, especially in Main. So what, then? Maybe I'm not following you, but there should only ever be one place where you grab a service directly from the container. For a web application, this would be when the controller being hit is instantiated or in a console app once in Main. In the web case, before Core, there was some boilerplate you had to add to the project that would tap into ASP.Net internals to resolve controllers from the container, after that, everything is injected in the constructors. With Core, that's all built in, and you can use the default service locator or plug in one of the 'aftermarket' ones. In your example, you'd want to have a highest-level OrderDoer that has all of those other handlers as dependencies. Then, in Main, you'd have one service location from the container that resolves OrderDoer and all the dependencies below it.
|
# ? Jan 6, 2019 22:32 |
|
New Yorp New Yorp posted:
What do you do if you have two different types that depend on IBaz and they need to use the same one?
|
# ? Jan 6, 2019 23:53 |
|
B-Nasty posted:Maybe I'm not following you, but there should only ever be one place where you grab a service directly from the container. For a web application, this would be when the controller being hit is instantiated or in a console app once in Main. In the web case, before Core, there was some boilerplate you had to add to the project that would tap into ASP.Net internals to resolve controllers from the container, after that, everything is injected in the constructors. With Core, that's all built in, and you can use the default service locator or plug in one of the 'aftermarket' ones. So to some degree I'm thinking less in ASP terms and more in standard app model terms. And I am likely just somehow blurring in my head the logic of doing stuff manually with doing stuff via an IOC container building the graph at startup. But I think the question starts to become having classes that involve multiple layers of dependencies. Trying to think through the 'register everything, then just resolve 'the root class' - doesn't that end up in a hypothetical root class with huge injection footprint? In a hypothetical inventory management system, for example, your main() would want an order management service, an inventory status service, a user management service, etc etc. And if each of those involves their own data-access dependencies, for example, do you just accept that this root class will have (n) dependencies injected, and for each of those dependencies you just let the IOC container sort it out? But if a single layer here ends up with a bit of a monolithic dependency situation(say 5-6 injected args), then is that just an architecture smell of 'go back and find the abstraction layer you're missing'?
|
# ? Jan 7, 2019 00:01 |
|
raminasi posted:What do you do if you have two different types that depend on IBaz and they need to use the same one? Needing to maintain a long-lived instance that's shared between multiple users makes me twitchy because it starts to smell like a singleton, so the lovely answer is "don't do that in the first place". I understand that this may be unavoidable if, say, you have a very-expensive-to-construct object. The real answer is that you either use an IoC container that manages this for you, or fall back to the trusty factory pattern.
|
# ? Jan 7, 2019 00:30 |
|
Cuntpunch posted:So to some degree I'm thinking less in ASP terms and more in standard app model terms. And I am likely just somehow blurring in my head the logic of doing stuff manually with doing stuff via an IOC container building the graph at startup. But I think the question starts to become having classes that involve multiple layers of dependencies. Trying to think through the 'register everything, then just resolve 'the root class' - doesn't that end up in a hypothetical root class with huge injection footprint? In a hypothetical inventory management system, for example, your main() would want an order management service, an inventory status service, a user management service, etc etc. And if each of those involves their own data-access dependencies, for example, do you just accept that this root class will have (n) dependencies injected, and for each of those dependencies you just let the IOC container sort it out? But if a single layer here ends up with a bit of a monolithic dependency situation(say 5-6 injected args), then is that just an architecture smell of 'go back and find the abstraction layer you're missing'? One of the good things about using a DI container is that your root class ends up being the DI container itself - you're avoiding having to write a custom XXXManager class that initializes everything.
|
# ? Jan 7, 2019 00:33 |
|
Cuntpunch posted:Trying to think through the 'register everything, then just resolve 'the root class' - doesn't that end up in a hypothetical root class with huge injection footprint? In a hypothetical inventory management system, for example, your main() would want an order management service, an inventory status service, a user management service, etc etc. And if each of those involves their own data-access dependencies, for example, do you just accept that this root class will have (n) dependencies injected, and for each of those dependencies you just let the IOC container sort it out? You might be overthinking it. How would you do it without a container? You probably wouldn't have your Main method new-ing a bunch of stuff; you'd have it new a something which new-s another couple things and those...and so on. If you had an entry point that was driven by a queue with a bunch of different queue message task types, for example, you may want to request specific handlers from the container depending on the message, but that's more of an advanced approach.
|
# ? Jan 7, 2019 01:14 |
|
Now that my hobby site is Capital F Finished, I am going to look into one of two things: 1) Look into alternative hosting sites besides AWS for my .net core projects. 2) Write me some Vue.js As far as 1) goes, what is everyone's preferred docker cloud service hosting PaaS VM container <more bullshit words> here place they deploy hobby code to? So far I've come across Heroku, Digital Ocean, Pivotal, and then the big ones, AWS and Azure. I never hear anything about Googles platforms for some reason.
|
# ? Jan 7, 2019 02:41 |
|
User0015 posted:Now that my hobby site is Capital F Finished, I am going to look into one of two things: I like Azure, but I also work for a Microsoft partner and do a lot of work in Azure, so I'm biased.
|
# ? Jan 7, 2019 02:46 |
|
User0015 posted:]Digital Ocean Congrats! I use Linode to host my SaaS app. I'm going to move to Azure .... soon.... someday. A $10 linode box goes a really long way though, lol.
|
# ? Jan 7, 2019 03:08 |
|
I have used Azure for VM hosting (and other stuff) for years and it is okay. The automation has royally sucked, though - they invented their own JSON template based "language" that is nearly incomprehensible to humans and trying to get something automatically created is an exercise in frustration trying to get their "templates" to do the right thing. I think they are now up to 3 versions of their PowerShell commands for using Azure, each incompatible with the other. And with fun situations like "why does this 0.3 second API call take 600 seconds if I do it via the Azure PowerShell commands?" But for a hobby site where you are not automating multi-tier deployments and can live with just the (reasonably okay) web portal, it is probably golden. Note that for a simple web app, you might be better off with an Azure Web App (basically an oldschool webserver managed by Azure). It does not give you a full VM but gives you a webserver. Maybe have an easier life managing it, plus you can stuff multiple sites onto the same webserver at no extra cost.
|
# ? Jan 7, 2019 06:56 |
|
EssOEss posted:
Considering the amount of bullshit I've had to put up with, I'd almost prefer having nothing but an open box to do as I'd like. gently caress it, I'll spin up my own nginx server. It's probably easier than some of the crap I've had to deal with recently.
|
# ? Jan 7, 2019 07:02 |
|
B-Nasty posted:You might be overthinking it. How would you do it without a container? You probably wouldn't have your Main method new-ing a bunch of stuff; you'd have it new a something which new-s another couple things and those...and so on. Yeah I think that's just it - I'm overthinking it a bit, and getting a little confused by the inversion. I've spent my entire professional career working in projects where IOC was either completely absent or horribly irregularly implemented, so I've just not got hands-on experience with a large codebase which handles it 'well'. Thanks for setting my head straight
|
# ? Jan 7, 2019 07:53 |
|
EssOEss posted:I have used Azure for VM hosting (and other stuff) for years and it is okay. The automation has royally sucked, though - they invented their own JSON template based "language" that is nearly incomprehensible to humans and trying to get something automatically created is an exercise in frustration trying to get their "templates" to do the right thing. New Yorp New Yorp posted:I like Azure, but I also work for a Microsoft partner and do a lot of work in Azure, so I'm biased. Since you both are familiar with Azure, let me ask you a few questions. Is there a good write up on spinning up your own sites on Azure, that also are cheap? Right now, the way I keep costs down on AWS annoys me because I have to deploy to three different areas to get things to work. AWS feels like it was designed with bigger businesses in mind. As it stands, a single EC2 instance is about $12 a month on their smallest size, and a SQL server about the same. $24 to run a website? Uh no thanks.
|
# ? Jan 7, 2019 15:57 |
|
User0015 posted:Since you both are familiar with Azure, let me ask you a few questions. I'm running a low-volume site, static on Azure at the lowest tier that supports custom domains and SSL. It's about $20 a month. Azure has a free tier, too, which is free, but doesn't support SSL/custom domains. Look at the pricing calculator: https://azure.microsoft.com/en-us/pricing/calculator/
|
# ? Jan 7, 2019 16:23 |
|
20 a month just seems high to me. And static files only? No database?
|
# ? Jan 7, 2019 16:28 |
|
User0015 posted:20 a month just seems high to me. And static files only? No database? Correct. It's a site for my wedding. Super simple, straight HTML/CSS/JS. If I didn't need a domain or want SSL, I could use the free tier, which is, well, free. Just a domain, about $10. I get $150 / month of free Azure, though, so I'm fine with "paying" for it.
|
# ? Jan 7, 2019 16:37 |
|
If it doesn't get many hits, you can host static sites on Azure Functions, pay literal cents, and get free custom domain support and SSL. https://thinkbeforecoding.com/post/2018/12/07/full-fsharp-blog https://thinkbeforecoding.com/post/2018/12/09/full-fsharp-blog-2 Skip all the stuff about actually generating the HTML and this sounds like your use case. quote:Azure functions is a FaaS platform, but we'll write no code for it. Using consumption plan, we'll pay only for used resource:
|
# ? Jan 7, 2019 16:43 |
|
New Yorp New Yorp posted:Correct. It's a site for my wedding. Super simple, straight HTML/CSS/JS. I'm not sure if it works with the free tier, but you can get Let's Encrypt to work with App Services and Functions, which takes care of the SSL for ya. It's kind of a pain to set up the first time, but do it once and it's super simple for every other site you want to handle.
|
# ? Jan 7, 2019 17:16 |
|
Drastic Actions posted:I'm not sure if it works with the free tier, but you can get Let's Encrypt to work with App Services and Functions, which takes care of the SSL for ya. It's kind of a pain to set up the first time, but do it once and it's super simple for every other site you want to handle. I did exactly that!
|
# ? Jan 7, 2019 17:18 |
|
NihilCredo posted:If it doesn't get many hits, you can host static sites on Azure Functions, pay literal cents, and get free custom domain support and SSL. It's the opposite for me. Setting up AWS' S3 buckets for static files is also pretty simple, and just as cheap. My question is when you need to start involving DB's and middle tier api's, prices start jumping into the $20+ range. That's when I got curious and wondered if there's any hosting out there where I could either host things for cheap, or if I could get my hands on my own box for like 5$ and set it all up myself.
|
# ? Jan 7, 2019 17:28 |
|
User0015 posted:It's the opposite for me. Setting up AWS' S3 buckets for static files is also pretty simple, and just as cheap. DigitalOcean, Linode and others have a virtual machine available for $5/month. you can put whatever you want in it. I have one in Digital Ocean with postgresql and 3 services running and some dumb website and is working just fine. Sure it cannot handle a gazillion users per day, but meh ... I'm not familiar with the AWS pricing, but surely it cannot be a lot worse for that level of a machine.
|
# ? Jan 7, 2019 17:47 |
|
Whatever you use, don't forget backups though, cheap and even expensive things sometimes go poof
|
# ? Jan 7, 2019 17:55 |
|
Volguus posted:DigitalOcean, Linode and others have a virtual machine available for $5/month. you can put whatever you want in it. I have one in Digital Ocean with postgresql and 3 services running and some dumb website and is working just fine. Sure it cannot handle a gazillion users per day, but meh ... An EBS micro + SQL DB runs every hour for the month, so the costs quickly add up. I've tried moving code over to their Lambda/Serverless Aurora setup, but that becomes a pain in the rear end to diagnose and debug issues. I'd rather just have a box. And yeah, I'm toying around with DigitalOcean right now, and trying out their dokku setup for fun.
|
# ? Jan 7, 2019 18:32 |
|
ThePeavstenator 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. Oh, the example I posted was just an analog for something further down the call stack throwing an exception. I wouldn't actually throw an exception there.
|
# ? Jan 8, 2019 17:02 |
|
If you're trying to run a database on a few dollars a month, you can almost definitely use SQLite instead of PostgreSQL or whatever. Means you don't need to look for database hosting services at all, since the "DB" is just a static resource file, and you can just run your webapp on some kind of managed service, like a FaaS where you only pay for actual use. Even if you prefer to run on a cheap minimum-tier VM and could install postgres, SQLite will eat less of the 512MB RAM or whatever you get from your provider.
|
# ? Jan 8, 2019 18:41 |
|
NihilCredo posted:If you're trying to run a database on a few dollars a month, you can almost definitely use SQLite instead of PostgreSQL or whatever. That's where aws gets you. Their ec2 instances specifically lock down sqlite, so you run into a host of permission and access issues trying to get an app to open it. Smart for them, but it's really soured me obviously.
|
# ? Jan 8, 2019 18:58 |
|
User0015 posted:That's where aws gets you. Their ec2 instances specifically lock down sqlite, so you run into a host of permission and access issues trying to get an app to open it. Smart for them, but it's really soured me obviously. huh? I just tried it on two EC2 instances in aws (one running debian and the other centos). sqlite works normally.
|
# ? Jan 8, 2019 19:08 |
|
User0015 posted:That's where aws gets you. Their ec2 instances specifically lock down sqlite, so you run into a host of permission and access issues trying to get an app to open it. Smart for them, but it's really soured me obviously. You just have the file in your app directory, I wonder how they would lock that down.
|
# ? Jan 8, 2019 22:17 |
|
User0015 posted:That's where aws gets you. Their ec2 instances specifically lock down sqlite, so you run into a host of permission and access issues trying to get an app to open it. Smart for them, but it's really soured me obviously. uh what?
|
# ? Jan 9, 2019 15:50 |
|
|
# ? Jun 8, 2024 08:58 |
|
maybe look into lightstail or whatever the amazon cheap vps thing is too, i think it's slightly better specs than a micro ec2
|
# ? Jan 9, 2019 15:51 |