Validating IOptions At Startup in C#
Read full transcript 10 segments
-
The I options of T allows you to assign options from an app settings file to a destroyed type class so you can pull that in dependency injection. But did you know you can validate those options? And not only should you validate them, but you should also validate them right the right away so your app doesn't start in invalid state. That is what we're looking at today in 10 minutes or less. Now for most of my training I work you in in-depth look at technology so you can understand when and why to use something, not just how to use it. But sometimes you just need a quick answer to the question, how do I use this? That's why I created this 10-minute training series. Okay, so we're going to jump right in with a .NET 10 minimal API. This is a file new project that's no changes made to it yet. We're going to start making changes right away. Let's start by changing Well, let's get rid of the HTTP file. We're not going to use that so let's get rid of it.
-
And then we're going to come in here and just start stripping away stuff we don't need. We're not going to use open API so let's get rid of it, which also means get ready getting rid of the mapping for it, and then let's get rid of this whole weather forecasting demo as well as the um array here, which also means we can get rid of this internal record. So if you don't know, minimal APIs are very minimal. This is it. That's all you really need. Now we don't have an endpoint yet. We're going to create one of those, but um that's it. So let's create endpoint real quick. We'll say app.mapget and we'll call this uh /demo. And um we're going to start off with nothing here. We're going to put something here in just a minute, but we're going to return uh empty string for now. So that's that would be it for an API. This API is now ready to go live and even redirect to HTTPS, but obviously we're going to do more with this than just we have here. We're going to do some validation of app settings. So, let's start with creating some app settings that we can pull in. So, go to app settings. Now, if you haven't watched my other content, just know that app settings is not the only place you can put these settings. In fact, this is usually only for in development that you put in this file.
-
>> [snorts] >> Now, there's also user secrets which you could put user secrets and it's override this app settings and so on. There's so many so much more depth to this system. But for this demo, we're just going to use app settings. So, I'm going to create a whole section. Let's put a comma here. We're going to say, let's call this um the demo section. I'm going to put curly braces inside here. I'm going to put three different uh properties and values. So, site URL and let's just say https uh devforge.com. By the way, if you want more good training clean free stuff, devforge.com is the place to go. All right. Uh admin user and we'll say T Corey. I misspelled that. Uh so, we'll come back to that in a minute. Uh user. There we go. And one last one, timeout. And we'll put that at 30 for now. Okay. So, now I've got this little section in my app settings of settings that go together.
-
I want to put this into a strongly typed object that I can then make sure is correct and make sure is fully loaded. To do that, I'm going to create uh control shift A to create this new item. I'm going to say demo options. So, I have this class here and inside here I'm going to say let's try the public const uh string we'll call it section name. And I'm going to I'm going to hard code this to demo. So, what this is is I'm going to have this be a a a variable I can use later. We'll see where to use it um that will reference what the section name is. In this case, I call it demo. If you want to call it something else, you would just change it in here. But, this is saying hey this is the section to look up. Now, I'm going to create some properties. I'll create a nullable string and we'll say site URL.
-
And I'll create another one, nullable string and it's going to be admin user. And finally, I'm going to have one that's a nullable int that is timeout. Now, I'm not going to assign values to these, but they and they are nullable. I want to say hey, you know what? Actually, there's some restrictions on these. So, let's do this. Required By the way, that's going to bring in the um the using directive system.componentmodel.dataannotations. I'm going to say required and also this is a URL. So, that's a that's two different things. I could have stacked them uh one on top of the other, but I can just put a comma and put them both in one line. And then this one is just required. And finally, the timeout, I'm going to say it's required, but also the range is going to be 1 to 90.
-
So, that says hey, you can't have a timeout of 100 or -1 or 0 or anything else. It has to be between 1 and 90. So, those are our three validation steps. So, those are the three things you want to make sure you bring in we're going to have validate. Let's come over here and on line three this empty line here, I'm going to say builder.services.addoptions. And we're going to say demo options. And that brings in our using directive for validating options, which is our our our root using directive. Okay. So, this brings in those options, but I'm not done yet. I want to bind configuration to demo options.sectionname. Remember I said that we're going to use this section name here? Well, we have to tell it where's the section that you're going to be loading in to this class. Well, the section is called demo instead of hard coding demo right here, which I could have done. I could have come in here I could have said demo, but that's going to be hard coding. I don't want to do that. I want to hard code it right where it makes sense and that is in the class.
-
I mean it stacks you can pull it in. Now, right now we're not doing any type of validation. But if I were to come down here and bring in this, I could I options of type demo options and we'll say options. And then we're going to return instead of by the way control. here to add the using directive for Microsoft.Extensions.Options. I'm going to return options. value. So, this in a perfect world that's all I need to do and I can have options. However, there's going to be a a flaw here. So, let's open this up. I'll bring us over. By the way, if you see this when you're in your API you go oh no, it's not running. It is. I just didn't map anything to the root. So, {slash} demo, we can pretty print this and make it bigger. And there we go. We can see site URL, admin user, and timeout. They're all there.
-
But, that's not we we're not living in a in a perfect world. So, let's bring this over to the side here and imagine what would happen if I didn't have all of the options. Remember, this appsettings.json uh JSON doesn't go to your server and and live there necessarily. It can, but usually you don't want to have these options pulled from appsettings.json. You usually want to have them pulled from uh Key Vault or somewhere else. And so, because of that, you might have forgotten to bring [clears throat] in some of your options. Let's say you forgot entirely the timeout. Well, if you ran that, this would still run. It would just put timeout as zero. You're not validating it. So, let's validate it. We can come down here and say {dot} validate data annotations. If I do just this, and I were to run this, it runs, not a problem. And if I were to come over here and grab this um and refresh, now we get unhandled exception. Why?
-
Because of the fact that we are missing the timeout field. It's required, we're missing it. But, that happened at runtime, which means our user sees it. Not the greatest place to happen. So, instead we want to do is add one more thing here, validate on start. And what this does is it will crash our application if it's not valid. It says, "Nope, you can't even start this because the timeout is missing. It's required." So, you go, "Oh, okay. I I made a mistake. I forgot to bring that in." You bring that in, and now it will run correctly and and say, "Yes." It it did. Um let's close this and run again. Um, now it will run correctly and validate and yes, it's running. So, that's kind of how you validate and make sure at startup that things are correct.
-
And this will even check for things like out of range. So, if you were to change this to be uh 100 and you were to run this, at startup it says, "No, no, no, you can't do that. You're outside the range." So, why would you want to crash your web application right away? And the the reason why is because why wouldn't you? You're in invalid state. So, if you have to wait for a user to hit that setting to find out that setting is missing, that's a problem. But if you validate on start, well then you're saying, "Hey, don't even launch the web application." So, we go, "Oh, whoops, we have a problem right away. We know right away." So, that's why we have validate on start. So, you need both of these, uh validate data annotations, but also validate on start to make sure that you have your setting loaded. All right? Thanks for watching. As always, I am Tim Core. >> [music]
Summary
This training demonstrates how to validate strongly typed options in a .NET 10 minimal API using data annotations and dependency injection. The tutorial covers configuring app settings, creating a demo options class with validation attributes, and ensuring the application validates these settings immediately upon startup. The key takeaway is that validating options early prevents the application from running in an invalid state, ensuring configuration errors are caught right away.